From a7fb55381ab4a5c470bf891b31ac6e201611a2c1 Mon Sep 17 00:00:00 2001
From: Richard Maudsley <richard.maudsley@isode.com>
Date: Wed, 9 Apr 2014 08:53:12 +0100
Subject: Fix crash in QtUserSearchWindow.

Avoid storing pointers to items in vectors. Using shared_ptr for Contact items.

Change-Id: I3baa05fc058011b2beca14dc620ab794988a2b37

diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 919a3d6..654f735 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -929,11 +929,11 @@ std::vector<ChatListWindow::Chat> ChatsManager::getRecentChats() const {
 	return std::vector<ChatListWindow::Chat>(recentChats_.begin(), recentChats_.end());
 }
 
-std::vector<Contact> Swift::ChatsManager::getContacts() {
-	std::vector<Contact> result;
+std::vector<Contact::ref> Swift::ChatsManager::getContacts() {
+	std::vector<Contact::ref> result;
 	foreach (ChatListWindow::Chat chat, recentChats_) {
 		if (!chat.isMUC) {
-			result.push_back(Contact(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath));
+			result.push_back(boost::make_shared<Contact>(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath));
 		}
 	}
 	return result;
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 979d52a..88a0986 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
  * Licensed under the GNU General Public License v3.
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
@@ -73,7 +73,7 @@ namespace Swift {
 			void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info);
 			void handleIncomingMessage(boost::shared_ptr<Message> message);
 			std::vector<ChatListWindow::Chat> getRecentChats() const;
-			virtual std::vector<Contact> getContacts();
+			virtual std::vector<Contact::ref> getContacts();
 
 			boost::signal<void (bool supportsImpromptu)> onImpromptuMUCServiceDiscovered;
 
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp
index 7844c1b..8503609 100644
--- a/Swift/Controllers/Chat/UserSearchController.cpp
+++ b/Swift/Controllers/Chat/UserSearchController.cpp
@@ -215,7 +215,7 @@ void UserSearchController::handlePresenceChanged(Presence::ref presence) {
 
 void UserSearchController::handleJIDUpdateRequested(const std::vector<JID>& jids) {
 	if (window_) {
-		std::vector<Contact> updates;
+		std::vector<Contact::ref> updates;
 		foreach(const JID& jid, jids) {
 			updates.push_back(convertJIDtoContact(jid));
 		}
@@ -224,40 +224,40 @@ void UserSearchController::handleJIDUpdateRequested(const std::vector<JID>& jids
 }
 
 void UserSearchController::handleJIDAddRequested(const std::vector<JID>& jids) {
-	std::vector<Contact> contacts;
+	std::vector<Contact::ref> contacts;
 	foreach(const JID& jid, jids) {
 		contacts.push_back(convertJIDtoContact(jid));
 	}
 	window_->addContacts(contacts);
 }
 
-Contact UserSearchController::convertJIDtoContact(const JID& jid) {
-	Contact contact;
-	contact.jid = jid;
+Contact::ref UserSearchController::convertJIDtoContact(const JID& jid) {
+	Contact::ref contact = boost::make_shared<Contact>();
+	contact->jid = jid;
 
 	// name lookup
 	boost::optional<XMPPRosterItem> rosterItem = rosterController_->getItem(jid);
 	if (rosterItem && !rosterItem->getName().empty()) {
-		contact.name = rosterItem->getName();
+		contact->name = rosterItem->getName();
 	} else {
 		VCard::ref vcard = vcardManager_->getVCard(jid);
 		if (vcard && !vcard->getFullName().empty()) {
-			contact.name = vcard->getFullName();
+			contact->name = vcard->getFullName();
 		} else {
-			contact.name = jid.toString();
+			contact->name = jid.toString();
 		}
 	}
 
 	// presence lookup
 	Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid);
 	if (presence) {
-		contact.statusType = presence->getShow();
+		contact->statusType = presence->getShow();
 	} else {
-		contact.statusType = StatusShow::None;
+		contact->statusType = StatusShow::None;
 	}
 
 	// avatar lookup
-	contact.avatarPath = avatarManager_->getAvatarPath(jid);
+	contact->avatarPath = avatarManager_->getAvatarPath(jid);
 	return contact;
 }
 
diff --git a/Swift/Controllers/Chat/UserSearchController.h b/Swift/Controllers/Chat/UserSearchController.h
index fc4c8e9..d630580 100644
--- a/Swift/Controllers/Chat/UserSearchController.h
+++ b/Swift/Controllers/Chat/UserSearchController.h
@@ -7,18 +7,20 @@
 #pragma once
 
 #include <boost/shared_ptr.hpp>
+
 #include <map>
 #include <vector>
-#include <Swiften/Base/boost_bsignals.h>
-
-#include <Swiften/Elements/SearchPayload.h>
 #include <string>
-#include <Swiften/JID/JID.h>
+
+#include <Swift/Controllers/Contact.h>
+#include <Swiften/Base/boost_bsignals.h>
 #include <Swiften/Elements/DiscoInfo.h>
 #include <Swiften/Elements/DiscoItems.h>
 #include <Swiften/Elements/ErrorPayload.h>
-#include <Swiften/Elements/VCard.h>
 #include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/SearchPayload.h>
+#include <Swiften/Elements/VCard.h>
+#include <Swiften/JID/JID.h>
 
 namespace Swift {
 	class UIEventStream;
@@ -32,7 +34,6 @@ namespace Swift {
 	class ContactSuggester;
 	class AvatarManager;
 	class PresenceOracle;
-	class Contact;
 
 	class UserSearchResult {
 		public:
@@ -68,7 +69,7 @@ namespace Swift {
 			void handlePresenceChanged(Presence::ref presence);
 			void handleJIDUpdateRequested(const std::vector<JID>& jids);
 			void handleJIDAddRequested(const std::vector<JID>& jids);
-			Contact convertJIDtoContact(const JID& jid);
+			Contact::ref convertJIDtoContact(const JID& jid);
 			void endDiscoWalker();
 			void initializeUserWindow();
 
diff --git a/Swift/Controllers/Contact.h b/Swift/Controllers/Contact.h
index 039cd23..ceba152 100644
--- a/Swift/Controllers/Contact.h
+++ b/Swift/Controllers/Contact.h
@@ -4,8 +4,15 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #pragma once
 
+#include <boost/enable_shared_from_this.hpp>
 #include <boost/filesystem/path.hpp>
 
 #include <Swiften/Elements/StatusShow.h>
@@ -13,8 +20,10 @@
 
 namespace Swift {
 
-class Contact {
+class Contact : public boost::enable_shared_from_this<Contact> {
 	public:
+		typedef boost::shared_ptr<Contact> ref;
+
 		Contact();
 		Contact(const std::string& name, const JID& jid, StatusShow::Type statusType, const boost::filesystem::path& path);
 
diff --git a/Swift/Controllers/ContactProvider.h b/Swift/Controllers/ContactProvider.h
index 9ce371f..0e56de5 100644
--- a/Swift/Controllers/ContactProvider.h
+++ b/Swift/Controllers/ContactProvider.h
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #pragma once
 
 #include <vector>
@@ -15,7 +21,7 @@ namespace Swift {
 class ContactProvider {
 	public:
 		virtual ~ContactProvider();
-		virtual std::vector<Contact> getContacts() = 0;
+		virtual std::vector<Contact::ref> getContacts() = 0;
 };
 
 }
diff --git a/Swift/Controllers/ContactSuggester.cpp b/Swift/Controllers/ContactSuggester.cpp
index f1104b0..41e0261 100644
--- a/Swift/Controllers/ContactSuggester.cpp
+++ b/Swift/Controllers/ContactSuggester.cpp
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #include <Swift/Controllers/ContactSuggester.h>
 
 #include <boost/algorithm/string/find.hpp>
@@ -34,25 +40,22 @@ void ContactSuggester::addContactProvider(ContactProvider* provider) {
 	contactProviders_.push_back(provider);
 }
 
-bool ContactSuggester::matchContact(const std::string& search, const Contact& c) {
-	return fuzzyMatch(c.name, search) || fuzzyMatch(c.jid.toString(), search);
+bool ContactSuggester::matchContact(const std::string& search, const Contact::ref& c) {
+	return fuzzyMatch(c->name, search) || fuzzyMatch(c->jid.toString(), search);
 }
 
-std::vector<Contact> ContactSuggester::getSuggestions(const std::string& search) const {
-	std::vector<Contact> results;
+std::vector<Contact::ref> ContactSuggester::getSuggestions(const std::string& search) const {
+	std::vector<Contact::ref> results;
 
 	foreach(ContactProvider* provider, contactProviders_) {
 		append(results, provider->getContacts());
 	}
 
-	std::sort(results.begin(), results.end(),
-		lambda::bind(&Contact::jid, lambda::_1) < lambda::bind(&Contact::jid, lambda::_2));
-	results.erase(std::unique(results.begin(), results.end(),
-		lambda::bind(&Contact::jid, lambda::_1) == lambda::bind(&Contact::jid, lambda::_2)),
-		results.end());
+	std::sort(results.begin(), results.end(), ContactSuggester::contactLexicographicalSortPredicate);
+	results.erase(std::unique(results.begin(), results.end(), ContactSuggester::contactEqualityPredicate), results.end());
 	results.erase(std::remove_if(results.begin(), results.end(), !lambda::bind(&ContactSuggester::matchContact, search, lambda::_1)),
 		results.end());
-	std::sort(results.begin(), results.end(), ContactSuggester::chatSortPredicate);
+	std::sort(results.begin(), results.end(), ContactSuggester::contactSmartSortPredicate);
 
 	return results;
 }
@@ -69,11 +72,19 @@ bool ContactSuggester::fuzzyMatch(std::string text, std::string match) {
 	return true;
 }
 
-bool ContactSuggester::chatSortPredicate(const Contact& a, const Contact& b) {
-	if (a.statusType == b.statusType) {
-		return a.name.compare(b.name) < 0;
+bool ContactSuggester::contactLexicographicalSortPredicate(const Contact::ref& a, const Contact::ref& b) {
+	return a->jid < b->jid;
+}
+
+bool ContactSuggester::contactEqualityPredicate(const Contact::ref& a, const Contact::ref& b) {
+	return a->jid == b->jid;
+}
+
+bool ContactSuggester::contactSmartSortPredicate(const Contact::ref& a, const Contact::ref& b) {
+	if (a->statusType == b->statusType) {
+		return a->name.compare(b->name) < 0;
 	} else {
-		return a.statusType < b.statusType;
+		return a->statusType < b->statusType;
 	}
 }
 
diff --git a/Swift/Controllers/ContactSuggester.h b/Swift/Controllers/ContactSuggester.h
index 137e5d3..67b912c 100644
--- a/Swift/Controllers/ContactSuggester.h
+++ b/Swift/Controllers/ContactSuggester.h
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #pragma once
 
 #include <string>
@@ -21,14 +27,16 @@ namespace Swift {
 
 		void addContactProvider(ContactProvider* provider);
 
-		std::vector<Contact> getSuggestions(const std::string& search) const;
+		std::vector<Contact::ref> getSuggestions(const std::string& search) const;
 	private:
-		static bool matchContact(const std::string& search, const Contact& c);
+		static bool matchContact(const std::string& search, const Contact::ref& c);
 		/**
 		 * Performs fuzzy matching on the string text. Matches when each character of match string is present in sequence in text string.
 		 */
 		static bool fuzzyMatch(std::string text, std::string match);
-		static bool chatSortPredicate(const Contact& a, const Contact& b);
+		static bool contactLexicographicalSortPredicate(const Contact::ref& a, const Contact::ref& b);
+		static bool contactEqualityPredicate(const Contact::ref& a, const Contact::ref& b);
+		static bool contactSmartSortPredicate(const Contact::ref& a, const Contact::ref& b);
 
 	private:
 		std::vector<ContactProvider*> contactProviders_;
diff --git a/Swift/Controllers/ContactsFromXMPPRoster.cpp b/Swift/Controllers/ContactsFromXMPPRoster.cpp
index 15a7767..7559962 100644
--- a/Swift/Controllers/ContactsFromXMPPRoster.cpp
+++ b/Swift/Controllers/ContactsFromXMPPRoster.cpp
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #include <Swift/Controllers/ContactsFromXMPPRoster.h>
 
 #include <Swiften/Base/foreach.h>
@@ -21,13 +27,13 @@ ContactsFromXMPPRoster::ContactsFromXMPPRoster(XMPPRoster* roster, AvatarManager
 ContactsFromXMPPRoster::~ContactsFromXMPPRoster() {
 }
 
-std::vector<Contact> ContactsFromXMPPRoster::getContacts() {
-	std::vector<Contact> results;
+std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts() {
+	std::vector<Contact::ref> results;
 	std::vector<XMPPRosterItem> rosterItems = roster_->getItems();
 	foreach(const XMPPRosterItem& rosterItem, rosterItems) {
-		Contact contact(rosterItem.getName().empty() ? rosterItem.getJID().toString() : rosterItem.getName(), rosterItem.getJID(), StatusShow::None,"");
-		contact.statusType = presenceOracle_->getHighestPriorityPresence(contact.jid) ? presenceOracle_->getHighestPriorityPresence(contact.jid)->getShow() : StatusShow::None;
-		contact.avatarPath = avatarManager_->getAvatarPath(contact.jid);
+		Contact::ref contact = boost::make_shared<Contact>(rosterItem.getName().empty() ? rosterItem.getJID().toString() : rosterItem.getName(), rosterItem.getJID(), StatusShow::None,"");
+		contact->statusType = presenceOracle_->getHighestPriorityPresence(contact->jid) ? presenceOracle_->getHighestPriorityPresence(contact->jid)->getShow() : StatusShow::None;
+		contact->avatarPath = avatarManager_->getAvatarPath(contact->jid);
 		results.push_back(contact);
 	}
 	return results;
diff --git a/Swift/Controllers/ContactsFromXMPPRoster.h b/Swift/Controllers/ContactsFromXMPPRoster.h
index 3815a99..4adc606 100644
--- a/Swift/Controllers/ContactsFromXMPPRoster.h
+++ b/Swift/Controllers/ContactsFromXMPPRoster.h
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #pragma once
 
 #include <Swift/Controllers/ContactProvider.h>
@@ -19,7 +25,7 @@ class ContactsFromXMPPRoster : public ContactProvider {
 		ContactsFromXMPPRoster(XMPPRoster* roster, AvatarManager* avatarManager, PresenceOracle* presenceOracle);
 		virtual ~ContactsFromXMPPRoster();
 
-		virtual std::vector<Contact> getContacts();
+		virtual std::vector<Contact::ref> getContacts();
 	private:
 		XMPPRoster* roster_;
 		AvatarManager* avatarManager_;
diff --git a/Swift/Controllers/UIInterfaces/UserSearchWindow.h b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
index 0245f34..56992cc 100644
--- a/Swift/Controllers/UIInterfaces/UserSearchWindow.h
+++ b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
@@ -32,14 +32,14 @@ namespace Swift {
 			virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields) = 0;
 			virtual void setNameSuggestions(const std::vector<std::string>& suggestions) = 0;
 			virtual void prepopulateJIDAndName(const JID& jid, const std::string& name) = 0;
-			virtual void setContactSuggestions(const std::vector<Contact>& suggestions) = 0;
+			virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions) = 0;
 			virtual void setJIDs(const std::vector<JID>&) = 0;
 			virtual void setRoomJID(const JID& roomJID) = 0;
 			virtual std::string getReason() const = 0;
 			virtual std::vector<JID> getJIDs() const = 0;
 			virtual void setCanStartImpromptuChats(bool supportsImpromptu) = 0;
-			virtual void updateContacts(const std::vector<Contact>& contacts) = 0;
-			virtual void addContacts(const std::vector<Contact>& contacts) = 0;
+			virtual void updateContacts(const std::vector<Contact::ref>& contacts) = 0;
+			virtual void addContacts(const std::vector<Contact::ref>& contacts) = 0;
 
 			virtual void show() = 0;
 
diff --git a/Swift/QtUI/UserSearch/ContactListDelegate.cpp b/Swift/QtUI/UserSearch/ContactListDelegate.cpp
index 29cab83..56c479b 100644
--- a/Swift/QtUI/UserSearch/ContactListDelegate.cpp
+++ b/Swift/QtUI/UserSearch/ContactListDelegate.cpp
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #include <Swift/QtUI/UserSearch/ContactListDelegate.h>
 #include <Swift/QtUI/UserSearch/ContactListModel.h>
 #include <Swift/Controllers/Contact.h>
@@ -21,7 +27,7 @@ void ContactListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& o
 	if (!index.isValid()) {
 		return;
 	}
-	const Contact* contact = static_cast<Contact*>(index.internalPointer());
+	const Contact::ref contact = static_cast<Contact*>(index.internalPointer())->shared_from_this();
 	QColor nameColor = index.data(Qt::TextColorRole).value<QColor>();
 	QString avatarPath = index.data(ContactListModel::AvatarRole).value<QString>();
 	QIcon presenceIcon =index.data(ChatListRecentItem::PresenceIconRole).isValid() && !index.data(ChatListRecentItem::PresenceIconRole).value<QIcon>().isNull()
diff --git a/Swift/QtUI/UserSearch/ContactListModel.cpp b/Swift/QtUI/UserSearch/ContactListModel.cpp
index 907142f..ef6383c 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.cpp
+++ b/Swift/QtUI/UserSearch/ContactListModel.cpp
@@ -52,16 +52,20 @@ QDataStream& operator >>(QDataStream& in, StatusShow::Type& e){
 ContactListModel::ContactListModel(bool editable) : QAbstractItemModel(), editable_(editable) {
 }
 
-void ContactListModel::setList(const std::vector<Contact>& list) {
+void ContactListModel::setList(const std::vector<Contact::ref>& list) {
 	emit layoutAboutToBeChanged();
 	contacts_ = list;
 	emit layoutChanged();
 }
 
-const std::vector<Contact>& ContactListModel::getList() const {
+const std::vector<Contact::ref>& ContactListModel::getList() const {
 	return contacts_;
 }
 
+Contact::ref ContactListModel::getContact(const size_t i) const {
+	return contacts_[i];
+}
+
 Qt::ItemFlags ContactListModel::flags(const QModelIndex& index) const {
 	Qt::ItemFlags flags = QAbstractItemModel::flags(index);
 	if (index.isValid()) {
@@ -78,9 +82,9 @@ int ContactListModel::columnCount(const QModelIndex&) const {
 
 QVariant ContactListModel::data(const QModelIndex& index, int role) const {
 	if (boost::numeric_cast<size_t>(index.row()) < contacts_.size()) {
-		const Contact& contact = contacts_[index.row()];
+		const Contact::ref& contact = contacts_[index.row()];
 		if (role == Qt::EditRole) {
-			return P2QSTRING(contact.jid.toString());
+			return P2QSTRING(contact->jid.toString());
 		}
 		return dataForContact(contact, role);
 	} else {
@@ -93,7 +97,7 @@ QModelIndex ContactListModel::index(int row, int column, const QModelIndex& pare
 		return QModelIndex();
 	}
 
-	return boost::numeric_cast<size_t>(row) < contacts_.size() ? createIndex(row, column, (void*)&(contacts_[row])) : QModelIndex();
+	return boost::numeric_cast<size_t>(row) < contacts_.size() ? createIndex(row, column, contacts_[row].get()) : QModelIndex();
 }
 
 QModelIndex ContactListModel::parent(const QModelIndex& index) const {
@@ -118,18 +122,18 @@ bool ContactListModel::removeRows(int row, int /*count*/, const QModelIndex& /*p
 	return false;
 }
 
-QVariant ContactListModel::dataForContact(const Contact& contact, int role) const {
+QVariant ContactListModel::dataForContact(const Contact::ref& contact, int role) const {
 	switch (role) {
-		case Qt::DisplayRole: return P2QSTRING(contact.name);
-		case DetailTextRole: return P2QSTRING(contact.jid.toString());
-		case AvatarRole: return QVariant(P2QSTRING(pathToString(contact.avatarPath)));
+		case Qt::DisplayRole: return P2QSTRING(contact->name);
+		case DetailTextRole: return P2QSTRING(contact->jid.toString());
+		case AvatarRole: return QVariant(P2QSTRING(pathToString(contact->avatarPath)));
 		case PresenceIconRole: return getPresenceIconForContact(contact);
 		default: return QVariant();
 	}
 }
 
-QIcon ContactListModel::getPresenceIconForContact(const Contact& contact) const {
-	return QIcon(statusShowTypeToIconPath(contact.statusType));
+QIcon ContactListModel::getPresenceIconForContact(const Contact::ref& contact) const {
+	return QIcon(statusShowTypeToIconPath(contact->statusType));
 }
 
 }
diff --git a/Swift/QtUI/UserSearch/ContactListModel.h b/Swift/QtUI/UserSearch/ContactListModel.h
index 6ca505e..e582ac4 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.h
+++ b/Swift/QtUI/UserSearch/ContactListModel.h
@@ -36,8 +36,9 @@ namespace Swift {
 		public:
 			ContactListModel(bool editable);
 
-			void setList(const std::vector<Contact>& list);
-			const std::vector<Contact>& getList() const;
+			void setList(const std::vector<Contact::ref>& list);
+			const std::vector<Contact::ref>& getList() const;
+			Contact::ref getContact(const size_t i) const;
 
 			Qt::ItemFlags flags(const QModelIndex& index) const;
 			int columnCount(const QModelIndex& parent = QModelIndex()) const;
@@ -48,16 +49,16 @@ namespace Swift {
 			bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
 
 		private:
-			QVariant dataForContact(const Contact& contact, int role) const;
-			QIcon getPresenceIconForContact(const Contact& contact) const;
+			QVariant dataForContact(const Contact::ref& contact, int role) const;
+			QIcon getPresenceIconForContact(const Contact::ref& contact) const;
 
 		signals:
-			void onListChanged(std::vector<Contact> list);
+			void onListChanged(std::vector<Contact::ref> list);
 			void onJIDsDropped(const std::vector<JID>& contact);
 
 		private:
 			bool editable_;
-			std::vector<Contact> contacts_;
+			std::vector<Contact::ref> contacts_;
 	};
 
 }
diff --git a/Swift/QtUI/UserSearch/QtContactListWidget.cpp b/Swift/QtUI/UserSearch/QtContactListWidget.cpp
index 6ad1169..4adc929 100644
--- a/Swift/QtUI/UserSearch/QtContactListWidget.cpp
+++ b/Swift/QtUI/UserSearch/QtContactListWidget.cpp
@@ -26,7 +26,7 @@ QtContactListWidget::QtContactListWidget(QWidget* parent, SettingsProvider* sett
 	contactListModel_ = new ContactListModel(true);
 	setModel(contactListModel_);
 
-	connect(contactListModel_, SIGNAL(onListChanged(std::vector<Contact>)), this, SIGNAL(onListChanged(std::vector<Contact>)));
+	connect(contactListModel_, SIGNAL(onListChanged(std::vector<Contact::ref>)), this, SIGNAL(onListChanged(std::vector<Contact::ref>)));
 	connect(contactListModel_, SIGNAL(onJIDsDropped(std::vector<JID>)), this, SIGNAL(onJIDsAdded(std::vector<JID>)));
 
 	setSelectionMode(QAbstractItemView::SingleSelection);
@@ -61,23 +61,27 @@ QtContactListWidget::~QtContactListWidget() {
 	delete removableItemDelegate_;
 }
 
-void QtContactListWidget::setList(const std::vector<Contact>& list) {
+void QtContactListWidget::setList(const std::vector<Contact::ref>& list) {
 	contactListModel_->setList(list);
 }
 
-std::vector<Contact> QtContactListWidget::getList() const {
+std::vector<Contact::ref> QtContactListWidget::getList() const {
 	return contactListModel_->getList();
 }
 
+Contact::ref QtContactListWidget::getContact(const size_t i) {
+	return contactListModel_->getContact(i);
+}
+
 void QtContactListWidget::setMaximumNoOfContactsToOne(bool limited) {
 	limited_ = limited;
 }
 
-void QtContactListWidget::updateContacts(const std::vector<Contact>& contactUpdates) {
-	std::vector<Contact> contacts = contactListModel_->getList();
-	foreach(const Contact& contactUpdate, contactUpdates) {
+void QtContactListWidget::updateContacts(const std::vector<Contact::ref>& contactUpdates) {
+	std::vector<Contact::ref> contacts = contactListModel_->getList();
+	foreach(const Contact::ref& contactUpdate, contactUpdates) {
 		for(size_t n = 0; n < contacts.size(); n++) {
-			if (contactUpdate.jid == contacts[n].jid) {
+			if (contactUpdate->jid == contacts[n]->jid) {
 				contacts[n] = contactUpdate;
 				break;
 			}
diff --git a/Swift/QtUI/UserSearch/QtContactListWidget.h b/Swift/QtUI/UserSearch/QtContactListWidget.h
index a83b47a..601d320 100644
--- a/Swift/QtUI/UserSearch/QtContactListWidget.h
+++ b/Swift/QtUI/UserSearch/QtContactListWidget.h
@@ -36,15 +36,16 @@ public:
 	QtContactListWidget(QWidget* parent, SettingsProvider* settings);
 	virtual ~QtContactListWidget();
 
-	void setList(const std::vector<Contact>& list);
-	std::vector<Contact> getList() const;
+	void setList(const std::vector<Contact::ref>& list);
+	std::vector<Contact::ref> getList() const;
+	Contact::ref getContact(const size_t i);
 	void setMaximumNoOfContactsToOne(bool limited);
 
 public slots:
-	void updateContacts(const std::vector<Contact>& contactUpdates);
+	void updateContacts(const std::vector<Contact::ref>& contactUpdates);
 
 signals:
-	void onListChanged(std::vector<Contact> list);
+	void onListChanged(std::vector<Contact::ref> list);
 	void onJIDsAdded(const std::vector<JID>& jids);
 
 private:
diff --git a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
index de935d9..a4a4610 100644
--- a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
+++ b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #include <Swift/QtUI/UserSearch/QtSuggestingJIDInput.h>
 #include <Swift/QtUI/UserSearch/ContactListDelegate.h>
 #include <Swift/Controllers/Settings/SettingsProvider.h>
@@ -23,7 +29,7 @@
 
 namespace Swift {
 
-QtSuggestingJIDInput::QtSuggestingJIDInput(QWidget* parent, SettingsProvider* settings) : QLineEdit(parent), settings_(settings), currentContact_(NULL) {
+QtSuggestingJIDInput::QtSuggestingJIDInput(QWidget* parent, SettingsProvider* settings) : QLineEdit(parent), settings_(settings) {
 	treeViewPopup_ = new QTreeView();
 	treeViewPopup_->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
 	//treeViewPopup_->setAttribute(Qt::WA_ShowWithoutActivating);
@@ -57,30 +63,31 @@ QtSuggestingJIDInput::~QtSuggestingJIDInput() {
 	delete treeViewPopup_;
 }
 
-const Contact* QtSuggestingJIDInput::getContact() {
-	if (currentContact_ != NULL) {
+Contact::ref QtSuggestingJIDInput::getContact() {
+	if (!!currentContact_) {
 		return currentContact_;
-	} else {
-		if (!text().isEmpty()) {
-			JID jid(Q2PSTRING(text()));
-			if (jid.isValid()) {
-				manualContact_.name = jid.toString();
-				manualContact_.jid = jid;
-				return &manualContact_;
-			}
+	}
+
+	if (!text().isEmpty()) {
+		JID jid(Q2PSTRING(text()));
+		if (jid.isValid()) {
+			Contact::ref manualContact = boost::make_shared<Contact>();
+			manualContact->name = jid.toString();
+			manualContact->jid = jid;
+			return manualContact;
 		}
-		return NULL;
 	}
+	return boost::shared_ptr<Contact>();
 }
 
-void QtSuggestingJIDInput::setSuggestions(const std::vector<Contact>& suggestions) {
+void QtSuggestingJIDInput::setSuggestions(const std::vector<Contact::ref>& suggestions) {
 	contactListModel_->setList(suggestions);
 	positionPopup();
 	if (!suggestions.empty()) {
 		treeViewPopup_->setCurrentIndex(contactListModel_->index(0, 0));
 		showPopup();
 	} else {
-		currentContact_ = NULL;
+		currentContact_.reset();
 	}
 }
 
@@ -100,12 +107,12 @@ void QtSuggestingJIDInput::keyPressEvent(QKeyEvent* event) {
 	} else if (event->key() == Qt::Key_Return && treeViewPopup_->isVisible()) {
 		QModelIndex index = treeViewPopup_->currentIndex();
 		if (!contactListModel_->getList().empty() && index.isValid()) {
-			currentContact_ = &contactListModel_->getList()[index.row()];
+			currentContact_ = contactListModel_->getContact(index.row());
 			setText(P2QSTRING(currentContact_->jid.toString()));
 			hidePopup();
 			clearFocus();
 		} else {
-			currentContact_ = NULL;
+			currentContact_.reset();
 		}
 		editingDone();
 	} else {
@@ -130,7 +137,7 @@ void QtSuggestingJIDInput::handleSettingsChanged(const std::string& setting) {
 
 void QtSuggestingJIDInput::handleClicked(const QModelIndex& index) {
 	if (index.isValid()) {
-		currentContact_ = &contactListModel_->getList()[index.row()];
+		currentContact_ = contactListModel_->getContact(index.row());
 		setText("");
 		onUserSelected(currentContact_->jid);
 		hidePopup();
diff --git a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
index 9ec0512..25e7d42 100644
--- a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
+++ b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
@@ -4,6 +4,12 @@
  * See Documentation/Licenses/BSD-simplified.txt for more information.
  */
 
+/*
+ * Copyright (c) 2014 Kevin Smith and Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
 #pragma once
 
 #include <QLineEdit>
@@ -23,9 +29,9 @@ class QtSuggestingJIDInput : public QLineEdit {
 		QtSuggestingJIDInput(QWidget* parent, SettingsProvider* settings);
 		virtual ~QtSuggestingJIDInput();
 
-		const Contact* getContact();
+		Contact::ref getContact();
 
-		void setSuggestions(const std::vector<Contact>& suggestions);
+		void setSuggestions(const std::vector<Contact::ref>& suggestions);
 
 		boost::signal<void (const JID&)> onUserSelected;
 
@@ -52,8 +58,7 @@ class QtSuggestingJIDInput : public QLineEdit {
 		ContactListModel* contactListModel_;
 		QTreeView* treeViewPopup_;
 		ContactListDelegate* contactListDelegate_;
-		Contact manualContact_;
-		const Contact* currentContact_;
+		Contact::ref currentContact_;
 };
 
 }
diff --git a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
index 47d62d9..597c88b 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
@@ -47,7 +47,7 @@ QtUserSearchFirstMultiJIDPage::QtUserSearchFirstMultiJIDPage(UserSearchWindow::T
 	jid_ = new QtSuggestingJIDInput(this, settings);
 	horizontalLayout_6->insertWidget(0, jid_);
 
-	connect(contactList_, SIGNAL(onListChanged(std::vector<Contact>)), this, SLOT(emitCompletenessCheck()));
+	connect(contactList_, SIGNAL(onListChanged(std::vector<Contact::ref>)), this, SLOT(emitCompletenessCheck()));
 	connect(jid_, SIGNAL(editingDone()), this, SLOT(handleEditingDone()));
 
 	setAcceptDrops(true);
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
index ed0fae2..c154c8f 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
@@ -130,20 +130,20 @@ void QtUserSearchWindow::handleAccepted() {
 			break;
 		case ChatToContact:
 			if (contactVector_.size() == 1) {
-				boost::shared_ptr<UIEvent> event(new RequestChatUIEvent(contactVector_[0].jid));
+				boost::shared_ptr<UIEvent> event(new RequestChatUIEvent(contactVector_[0]->jid));
 				eventStream_->send(event);
 				break;
 			}
 
-			foreach(const Contact& contact, contactVector_) {
-				jids.push_back(contact.jid);
+			foreach(Contact::ref contact, contactVector_) {
+				jids.push_back(contact->jid);
 			}
 
 			eventStream_->send(boost::make_shared<CreateImpromptuMUCUIEvent>(jids, JID(), Q2PSTRING(firstMultiJIDPage_->reason_->text())));
 			break;
 		case InviteToChat:
-			foreach(const Contact& contact, contactVector_) {
-				jids.push_back(contact.jid);
+			foreach(Contact::ref contact, contactVector_) {
+				jids.push_back(contact->jid);
 			}
 			eventStream_->send(boost::make_shared<InviteToMUCUIEvent>(roomJID_, jids, Q2PSTRING(firstMultiJIDPage_->reason_->text())));
 			break;
@@ -156,9 +156,8 @@ void QtUserSearchWindow::handleContactSuggestionRequested(const QString& text) {
 }
 
 void QtUserSearchWindow::addContact() {
-	if (firstMultiJIDPage_->jid_->getContact() != 0) {
-		Contact contact = *(firstMultiJIDPage_->jid_->getContact());
-		contactVector_.push_back(contact);
+	if (!!firstMultiJIDPage_->jid_->getContact()) {
+		contactVector_.push_back(firstMultiJIDPage_->jid_->getContact());
 	}
 	firstMultiJIDPage_->contactList_->setList(contactVector_);
 	firstMultiJIDPage_->emitCompletenessCheck();
@@ -271,7 +270,7 @@ JID QtUserSearchWindow::getContactJID() const {
 }
 
 void QtUserSearchWindow::addSearchedJIDToList(const JID& jid) {
-	Contact contact(jid, jid.toString(), StatusShow::None, "");
+	Contact::ref contact = boost::make_shared<Contact>(jid, jid.toString(), StatusShow::None, "");
 	contactVector_.push_back(contact);
 	firstMultiJIDPage_->contactList_->setList(contactVector_);
 	firstMultiJIDPage_->emitCompletenessCheck();
@@ -336,7 +335,7 @@ void QtUserSearchWindow::prepopulateJIDAndName(const JID& jid, const std::string
 	detailsPage_->setName(name);
 }
 
-void QtUserSearchWindow::setContactSuggestions(const std::vector<Contact>& suggestions) {
+void QtUserSearchWindow::setContactSuggestions(const std::vector<Contact::ref>& suggestions) {
 	if (type_ == AddContact) {
 		firstPage_->jid_->setSuggestions(suggestions);
 	} else {
@@ -361,8 +360,8 @@ std::string QtUserSearchWindow::getReason() const {
 
 std::vector<JID> QtUserSearchWindow::getJIDs() const {
 	std::vector<JID> jids;
-	foreach (const Contact& contact, contactVector_) {
-		jids.push_back(contact.jid);
+	foreach (Contact::ref contact, contactVector_) {
+		jids.push_back(contact->jid);
 	}
 	return jids;
 }
@@ -374,19 +373,19 @@ void QtUserSearchWindow::setCanStartImpromptuChats(bool supportsImpromptu) {
 	}
 }
 
-void QtUserSearchWindow::updateContacts(const std::vector<Contact>& contacts) {
+void QtUserSearchWindow::updateContacts(const std::vector<Contact::ref>& contacts) {
 	if (type_ != AddContact) {
 		firstMultiJIDPage_->contactList_->updateContacts(contacts);
 	}
 }
 
-void QtUserSearchWindow::addContacts(const std::vector<Contact>& contacts) {
+void QtUserSearchWindow::addContacts(const std::vector<Contact::ref>& contacts) {
 	if (type_ != AddContact) {
 		/* prevent duplicate JIDs from appearing in the contact list */
-		foreach (const Contact& newContact, contacts) {
+		foreach (Contact::ref newContact, contacts) {
 			bool found = false;
-			foreach (const Contact& oldContact, contactVector_) {
-				if (newContact.jid == oldContact.jid) {
+			foreach (Contact::ref oldContact, contactVector_) {
+				if (newContact->jid == oldContact->jid) {
 					found = true;
 					break;
 				}
@@ -405,7 +404,7 @@ void QtUserSearchWindow::handleAddViaSearch() {
 	next();
 }
 
-void QtUserSearchWindow::handleListChanged(std::vector<Contact> list) {
+void QtUserSearchWindow::handleListChanged(std::vector<Contact::ref> list) {
 	contactVector_ = list;
 	if (type_ == ChatToContact) {
 		firstMultiJIDPage_->groupBox->setEnabled(supportsImpromptu_ ? 1 : (contactVector_.size() < 1));
@@ -470,7 +469,7 @@ void QtUserSearchWindow::setFirstPage(QString title) {
 		connect(firstMultiJIDPage_->jid_, SIGNAL(textEdited(QString)), this, SLOT(handleContactSuggestionRequested(QString)));
 		firstMultiJIDPage_->jid_->onUserSelected.connect(boost::bind(&QtUserSearchWindow::addSearchedJIDToList, this, _1));
 		connect(firstMultiJIDPage_->addViaSearchButton_, SIGNAL(clicked()), this, SLOT(handleAddViaSearch()));
-		connect(firstMultiJIDPage_->contactList_, SIGNAL(onListChanged(std::vector<Contact>)), this, SLOT(handleListChanged(std::vector<Contact>)));
+		connect(firstMultiJIDPage_->contactList_, SIGNAL(onListChanged(std::vector<Contact::ref>)), this, SLOT(handleListChanged(std::vector<Contact::ref>)));
 		connect(firstMultiJIDPage_->contactList_, SIGNAL(onJIDsAdded(std::vector<JID>)), this, SLOT(handleJIDsAdded(std::vector<JID>)));
 		connect(firstMultiJIDPage_, SIGNAL(onJIDsDropped(std::vector<JID>)), this, SLOT(handleJIDsAdded(std::vector<JID>)));
 		setPage(1, firstMultiJIDPage_);
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
index 941e455..bb89e51 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
@@ -43,14 +43,14 @@ namespace Swift {
 			virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields);
 			virtual void setNameSuggestions(const std::vector<std::string>& suggestions);
 			virtual void prepopulateJIDAndName(const JID& jid, const std::string& name);
-			virtual void setContactSuggestions(const std::vector<Contact>& suggestions);
+			virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions);
 			virtual void setJIDs(const std::vector<JID> &jids);
 			virtual void setRoomJID(const JID &roomJID);
 			virtual std::string getReason() const;
 			virtual std::vector<JID> getJIDs() const;
 			virtual void setCanStartImpromptuChats(bool supportsImpromptu);
-			virtual void updateContacts(const std::vector<Contact> &contacts);
-			virtual void addContacts(const std::vector<Contact>& contacts);
+			virtual void updateContacts(const std::vector<Contact::ref> &contacts);
+			virtual void addContacts(const std::vector<Contact::ref>& contacts);
 
 		protected:
 			virtual int nextId() const;
@@ -62,7 +62,7 @@ namespace Swift {
 			void handleContactSuggestionRequested(const QString& text);
 			void addContact();
 			void handleAddViaSearch();
-			void handleListChanged(std::vector<Contact> list);
+			void handleListChanged(std::vector<Contact::ref> list);
 			void handleJIDsAdded(std::vector<JID> jids);
 
 		private:
@@ -91,7 +91,7 @@ namespace Swift {
 			JID myServer_;
 			JID roomJID_;
 			int lastPage_;
-			std::vector<Contact> contactVector_;
+			std::vector<Contact::ref> contactVector_;
 			SettingsProvider* settings_;
 			bool searchNext_;
 			bool supportsImpromptu_;
-- 
cgit v0.10.2-6-g49f6