From 0da93507bea788cf6bd8f327478caddf3ea679e5 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Sun, 12 Sep 2010 21:36:48 +0100
Subject: Block MUC bookmarks until the server has responded.

Else there could be bookmarks overwritten in an infeasibly unlikely race condition.

Resolves: #340

diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index acc5e1d..e1a53b4 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -39,11 +39,15 @@ ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRo
 	presenceSender_ = presenceSender;
 	uiEventStream_ = uiEventStream;
 	mucBookmarkManager_ = new MUCBookmarkManager(iqRouter);
+	mucBookmarkManager_->onBookmarksReady.connect(boost::bind(&ChatsManager::handleBookmarksReady, this));
 	mucBookmarkManager_->onBookmarkAdded.connect(boost::bind(&ChatsManager::handleMUCBookmarkAdded, this, _1));
 	mucBookmarkManager_->onBookmarkRemoved.connect(boost::bind(&ChatsManager::handleMUCBookmarkRemoved, this, _1));
 	presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1, _2));
 	uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
 	chatListWindow_ = chatListWindowFactory->createWindow(uiEventStream_);
+	if (chatListWindow_) {
+		chatListWindow_->setBookmarksEnabled(false);
+	}
 }
 
 ChatsManager::~ChatsManager() {
@@ -56,6 +60,12 @@ ChatsManager::~ChatsManager() {
 	delete mucBookmarkManager_;
 }
 
+void ChatsManager::handleBookmarksReady() {
+	if (chatListWindow_) {
+		chatListWindow_->setBookmarksEnabled(true);
+	}
+}
+
 void ChatsManager::handleMUCBookmarkAdded(const MUCBookmark& bookmark) {
 	std::map<JID, MUCController*>::iterator it = mucControllers_.find(bookmark.getRoom());
 	if (it == mucControllers_.end() && bookmark.getAutojoin()) {
diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h
index 3efd507..752acff 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -52,6 +52,7 @@ namespace Swift {
 			void handleMUCBookmarkAdded(const MUCBookmark& bookmark);
 			void handleMUCBookmarkRemoved(const MUCBookmark& bookmark);
 			void handleUserLeftMUC(MUCController* mucController);
+			void handleBookmarksReady();
 			ChatController* getChatControllerOrFindAnother(const JID &contact);
 			ChatController* createNewChatController(const JID &contact);
 			ChatController* getChatControllerOrCreate(const JID &contact);
diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h
index fd176a6..3a7c30e 100644
--- a/Swift/Controllers/UIInterfaces/ChatListWindow.h
+++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h
@@ -15,6 +15,7 @@ namespace Swift {
 		public:
 			virtual ~ChatListWindow();
 
+			virtual void setBookmarksEnabled(bool enabled) = 0;
 			virtual void addMUCBookmark(const MUCBookmark& bookmark) = 0;
 			virtual void removeMUCBookmark(const MUCBookmark& bookmark) = 0;
 	};
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index 5943078..86dfa8f 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp
@@ -21,6 +21,7 @@ namespace Swift {
 
 QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, QWidget* parent) : QTreeView(parent) {
 	eventStream_ = uiEventStream;
+	bookmarksEnabled_ = false;
 	model_ = new ChatListModel();
 	setModel(model_);
 	delegate_ = new ChatListDelegate();
@@ -45,6 +46,10 @@ QtChatListWindow::~QtChatListWindow() {
 	delete emptyMenu_;
 }
 
+void QtChatListWindow::setBookmarksEnabled(bool enabled) {
+	bookmarksEnabled_ = enabled;
+}
+
 void QtChatListWindow::handleClicked(const QModelIndex& index) {
 	ChatListGroupItem* item = dynamic_cast<ChatListGroupItem*>(static_cast<ChatListItem*>(index.internalPointer()));
 	if (item) {
@@ -99,6 +104,9 @@ void QtChatListWindow::handleEditBookmark() {
 
 
 void QtChatListWindow::contextMenuEvent(QContextMenuEvent* event) {
+	if (!bookmarksEnabled_) {
+		return;
+	}
 	QModelIndex index = indexAt(event->pos());
 	ChatListItem* baseItem = index.isValid() ? static_cast<ChatListItem*>(index.internalPointer()) : NULL;
 	contextMenuItem_ = baseItem;
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index 1215f83..2c13300 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -23,6 +23,7 @@ namespace Swift {
 			virtual ~QtChatListWindow();
 			void addMUCBookmark(const MUCBookmark& bookmark);
 			void removeMUCBookmark(const MUCBookmark& bookmark);
+			void setBookmarksEnabled(bool enabled);
 		private slots:
 			void handleItemActivated(const QModelIndex&);
 			void handleAddBookmark();
@@ -34,6 +35,7 @@ namespace Swift {
 			void contextMenuEvent(QContextMenuEvent* event);
 		private:
 			void setupContextMenus();
+			bool bookmarksEnabled_;
 			UIEventStream* eventStream_;
 			ChatListModel* model_;
 			ChatListDelegate* delegate_;
diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp
index 77921e9..64615e4 100644
--- a/Swiften/MUC/MUCBookmarkManager.cpp
+++ b/Swiften/MUC/MUCBookmarkManager.cpp
@@ -18,6 +18,7 @@ namespace Swift {
 
 MUCBookmarkManager::MUCBookmarkManager(IQRouter* iqRouter) {
 	iqRouter_ = iqRouter;
+	ready_ = false;
 	boost::shared_ptr<GetPrivateStorageRequest<Storage> > request(new GetPrivateStorageRequest<Storage>(iqRouter_));
 	request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksReceived, this, _1, _2));
 	request->send();
@@ -27,6 +28,10 @@ void MUCBookmarkManager::handleBookmarksReceived(boost::shared_ptr<Storage> payl
 	if (error) {
 		return;
 	}
+
+	ready_ = true;
+	onBookmarksReady();
+
 	storage = payload;
 
 	std::vector<MUCBookmark> receivedBookmarks;
@@ -57,6 +62,7 @@ bool MUCBookmarkManager::containsEquivalent(const std::vector<MUCBookmark>& list
 }
 
 void MUCBookmarkManager::replaceBookmark(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark) {
+	if (!ready_) return;
 	for (size_t i = 0; i < bookmarks_.size(); i++) {
 		if (bookmarks_[i] == oldBookmark) {
 			bookmarks_[i] = newBookmark;
@@ -69,6 +75,7 @@ void MUCBookmarkManager::replaceBookmark(const MUCBookmark& oldBookmark, const M
 }
 
 void MUCBookmarkManager::addBookmark(const MUCBookmark& bookmark) {
+	if (!ready_) return;
 	bookmarks_.push_back(bookmark);
 	onBookmarkAdded(bookmark);
 	flush();
@@ -76,6 +83,7 @@ void MUCBookmarkManager::addBookmark(const MUCBookmark& bookmark) {
 
 
 void MUCBookmarkManager::removeBookmark(const MUCBookmark& bookmark) {
+	if (!ready_) return;
 	std::vector<MUCBookmark>::iterator it;
 	for (it = bookmarks_.begin(); it != bookmarks_.end(); it++) {
 		if ((*it) == bookmark) {
diff --git a/Swiften/MUC/MUCBookmarkManager.h b/Swiften/MUC/MUCBookmarkManager.h
index a942595..8067b4b 100644
--- a/Swiften/MUC/MUCBookmarkManager.h
+++ b/Swiften/MUC/MUCBookmarkManager.h
@@ -32,6 +32,10 @@ namespace Swift {
 		public:
 			boost::signal<void (const MUCBookmark&)> onBookmarkAdded;
 			boost::signal<void (const MUCBookmark&)> onBookmarkRemoved;
+			/**
+			 * When server bookmarks are ready to be used (request response has been received).
+			 */
+			boost::signal<void ()> onBookmarksReady;
 
 		private:
 			bool containsEquivalent(const std::vector<MUCBookmark>& list, const MUCBookmark& bookmark);
@@ -39,6 +43,7 @@ namespace Swift {
 			void flush();
 
 		private:
+			bool ready_;
 			std::vector<MUCBookmark> bookmarks_;
 			IQRouter* iqRouter_;
 			boost::shared_ptr<Storage> storage;
-- 
cgit v0.10.2-6-g49f6