diff options
Diffstat (limited to 'Swiften/MUC')
-rw-r--r-- | Swiften/MUC/MUC.h | 130 | ||||
-rw-r--r-- | Swiften/MUC/MUCBookmark.h | 142 | ||||
-rw-r--r-- | Swiften/MUC/MUCBookmarkManager.cpp | 150 | ||||
-rw-r--r-- | Swiften/MUC/MUCBookmarkManager.h | 62 | ||||
-rw-r--r-- | Swiften/MUC/MUCImpl.cpp | 658 | ||||
-rw-r--r-- | Swiften/MUC/MUCImpl.h | 204 | ||||
-rw-r--r-- | Swiften/MUC/MUCManager.cpp | 2 | ||||
-rw-r--r-- | Swiften/MUC/MUCManager.h | 28 | ||||
-rw-r--r-- | Swiften/MUC/MUCRegistry.cpp | 6 | ||||
-rw-r--r-- | Swiften/MUC/MUCRegistry.h | 20 | ||||
-rw-r--r-- | Swiften/MUC/UnitTest/MUCTest.cpp | 496 | ||||
-rw-r--r-- | Swiften/MUC/UnitTest/MockMUC.cpp | 32 | ||||
-rw-r--r-- | Swiften/MUC/UnitTest/MockMUC.h | 124 |
13 files changed, 1027 insertions, 1027 deletions
diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h index fbd7be6..e8f953e 100644 --- a/Swiften/MUC/MUC.h +++ b/Swiften/MUC/MUC.h @@ -24,77 +24,77 @@ #include <Swiften/MUC/MUCRegistry.h> namespace Swift { - class StanzaChannel; - class IQRouter; - class DirectedPresenceSender; + class StanzaChannel; + class IQRouter; + class DirectedPresenceSender; - class SWIFTEN_API MUC { - public: - typedef boost::shared_ptr<MUC> ref; + class SWIFTEN_API MUC { + public: + typedef boost::shared_ptr<MUC> ref; - enum JoinResult { JoinSucceeded, JoinFailed }; - enum LeavingType { LeavePart, LeaveKick, LeaveBan, LeaveDestroy, LeaveNotMember, Disconnect }; + enum JoinResult { JoinSucceeded, JoinFailed }; + enum LeavingType { LeavePart, LeaveKick, LeaveBan, LeaveDestroy, LeaveNotMember, Disconnect }; - public: - virtual ~MUC(); + public: + virtual ~MUC(); - /** - * Returns the (bare) JID of the MUC. - */ - virtual JID getJID() const = 0; + /** + * Returns the (bare) JID of the MUC. + */ + virtual JID getJID() const = 0; - /** - * Returns if the room is unlocked and other people can join the room. - * @return True if joinable by others; false otherwise. - */ - virtual bool isUnlocked() const = 0; + /** + * Returns if the room is unlocked and other people can join the room. + * @return True if joinable by others; false otherwise. + */ + virtual bool isUnlocked() const = 0; - virtual void joinAs(const std::string &nick) = 0; - virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) = 0; - /*virtual void queryRoomInfo(); */ - /*virtual void queryRoomItems(); */ - /*virtual std::string getCurrentNick() = 0; */ - virtual std::map<std::string, MUCOccupant> getOccupants() const = 0; - virtual void changeNickname(const std::string& newNickname) = 0; - virtual void part() = 0; - /*virtual void handleIncomingMessage(Message::ref message) = 0; */ - /** Expose public so it can be called when e.g. user goes offline */ - virtual void handleUserLeft(LeavingType) = 0; - /** Get occupant information*/ - virtual const MUCOccupant& getOccupant(const std::string& nick) = 0; - virtual bool hasOccupant(const std::string& nick) = 0; - virtual void kickOccupant(const JID& jid) = 0; - virtual void changeOccupantRole(const JID& jid, MUCOccupant::Role role) = 0; - virtual void requestAffiliationList(MUCOccupant::Affiliation) = 0; - virtual void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation) = 0; - virtual void changeSubject(const std::string& subject) = 0; - virtual void requestConfigurationForm() = 0; - virtual void configureRoom(Form::ref) = 0; - virtual void cancelConfigureRoom() = 0; - virtual void destroyRoom() = 0; - /** Send an invite for the person to join the MUC */ - virtual void invitePerson(const JID& person, const std::string& reason = "", bool isImpromptu = false, bool isReuseChat = false) = 0; - virtual void setCreateAsReservedIfNew() = 0; - virtual void setPassword(const boost::optional<std::string>& password) = 0; + virtual void joinAs(const std::string &nick) = 0; + virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) = 0; + /*virtual void queryRoomInfo(); */ + /*virtual void queryRoomItems(); */ + /*virtual std::string getCurrentNick() = 0; */ + virtual std::map<std::string, MUCOccupant> getOccupants() const = 0; + virtual void changeNickname(const std::string& newNickname) = 0; + virtual void part() = 0; + /*virtual void handleIncomingMessage(Message::ref message) = 0; */ + /** Expose public so it can be called when e.g. user goes offline */ + virtual void handleUserLeft(LeavingType) = 0; + /** Get occupant information*/ + virtual const MUCOccupant& getOccupant(const std::string& nick) = 0; + virtual bool hasOccupant(const std::string& nick) = 0; + virtual void kickOccupant(const JID& jid) = 0; + virtual void changeOccupantRole(const JID& jid, MUCOccupant::Role role) = 0; + virtual void requestAffiliationList(MUCOccupant::Affiliation) = 0; + virtual void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation) = 0; + virtual void changeSubject(const std::string& subject) = 0; + virtual void requestConfigurationForm() = 0; + virtual void configureRoom(Form::ref) = 0; + virtual void cancelConfigureRoom() = 0; + virtual void destroyRoom() = 0; + /** Send an invite for the person to join the MUC */ + virtual void invitePerson(const JID& person, const std::string& reason = "", bool isImpromptu = false, bool isReuseChat = false) = 0; + virtual void setCreateAsReservedIfNew() = 0; + virtual void setPassword(const boost::optional<std::string>& password) = 0; - public: - boost::signal<void (const std::string& /*nick*/)> onJoinComplete; - boost::signal<void (ErrorPayload::ref)> onJoinFailed; - boost::signal<void (ErrorPayload::ref, const JID&, MUCOccupant::Role)> onRoleChangeFailed; - boost::signal<void (ErrorPayload::ref, const JID&, MUCOccupant::Affiliation)> onAffiliationChangeFailed; - boost::signal<void (ErrorPayload::ref)> onConfigurationFailed; - boost::signal<void (ErrorPayload::ref)> onAffiliationListFailed; - boost::signal<void (Presence::ref)> onOccupantPresenceChange; - boost::signal<void (const std::string&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged; - boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged; - boost::signal<void (const MUCOccupant&)> onOccupantJoined; - boost::signal<void (const std::string& /*oldNickname*/, const std::string& /*newNickname*/ )> onOccupantNicknameChanged; - boost::signal<void (const MUCOccupant&, LeavingType, const std::string& /*reason*/)> onOccupantLeft; - boost::signal<void (Form::ref)> onConfigurationFormReceived; - boost::signal<void (MUCOccupant::Affiliation, const std::vector<JID>&)> onAffiliationListReceived; - boost::signal<void ()> onUnlocked; - /* boost::signal<void (const MUCInfo&)> onInfoResult; */ - /* boost::signal<void (const blah&)> onItemsResult; */ + public: + boost::signal<void (const std::string& /*nick*/)> onJoinComplete; + boost::signal<void (ErrorPayload::ref)> onJoinFailed; + boost::signal<void (ErrorPayload::ref, const JID&, MUCOccupant::Role)> onRoleChangeFailed; + boost::signal<void (ErrorPayload::ref, const JID&, MUCOccupant::Affiliation)> onAffiliationChangeFailed; + boost::signal<void (ErrorPayload::ref)> onConfigurationFailed; + boost::signal<void (ErrorPayload::ref)> onAffiliationListFailed; + boost::signal<void (Presence::ref)> onOccupantPresenceChange; + boost::signal<void (const std::string&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged; + boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged; + boost::signal<void (const MUCOccupant&)> onOccupantJoined; + boost::signal<void (const std::string& /*oldNickname*/, const std::string& /*newNickname*/ )> onOccupantNicknameChanged; + boost::signal<void (const MUCOccupant&, LeavingType, const std::string& /*reason*/)> onOccupantLeft; + boost::signal<void (Form::ref)> onConfigurationFormReceived; + boost::signal<void (MUCOccupant::Affiliation, const std::vector<JID>&)> onAffiliationListReceived; + boost::signal<void ()> onUnlocked; + /* boost::signal<void (const MUCInfo&)> onInfoResult; */ + /* boost::signal<void (const blah&)> onItemsResult; */ - }; + }; } diff --git a/Swiften/MUC/MUCBookmark.h b/Swiften/MUC/MUCBookmark.h index 1f54a8f..92050f1 100644 --- a/Swiften/MUC/MUCBookmark.h +++ b/Swiften/MUC/MUCBookmark.h @@ -15,76 +15,76 @@ #include <Swiften/JID/JID.h> namespace Swift { - class SWIFTEN_API MUCBookmark { - public: - MUCBookmark(const Storage::Room& room) { - name_ = room.name; - room_ = room.jid; - nick_ = room.nick; - password_ = room.password; - autojoin_ = room.autoJoin; - } - - MUCBookmark(const JID& room, const std::string& bookmarkName) : room_(room), name_(bookmarkName), autojoin_(false) { - } - - void setAutojoin(bool enabled) { - autojoin_ = enabled; - } - - bool getAutojoin() const { - return autojoin_; - } - - void setNick(const boost::optional<std::string>& nick) { - nick_ = nick; - } - - void setPassword(const boost::optional<std::string>& password) { - password_ = password; - } - - const boost::optional<std::string>& getNick() const { - return nick_; - } - - const boost::optional<std::string>& getPassword() const { - return password_; - } - - const std::string& getName() const { - return name_; - } - - const JID& getRoom() const { - return room_; - } - - bool operator==(const MUCBookmark& rhs) const { - /* FIXME: not checking passwords for equality - which might make sense, perhaps */ - return rhs.room_ == room_ && rhs.name_ == name_ && rhs.nick_ == nick_ /*&& rhs.password_ == password_*/ && rhs.autojoin_ == autojoin_; - } - - Storage::Room toStorage() const { - Storage::Room room; - room.name = name_; - room.jid = room_; - if (nick_) { - room.nick = *nick_; - } - if (password_) { - room.password = *password_; - } - room.autoJoin = autojoin_; - return room; - } - - private: - JID room_; - std::string name_; - boost::optional<std::string> nick_; - boost::optional<std::string> password_; - bool autojoin_; - }; + class SWIFTEN_API MUCBookmark { + public: + MUCBookmark(const Storage::Room& room) { + name_ = room.name; + room_ = room.jid; + nick_ = room.nick; + password_ = room.password; + autojoin_ = room.autoJoin; + } + + MUCBookmark(const JID& room, const std::string& bookmarkName) : room_(room), name_(bookmarkName), autojoin_(false) { + } + + void setAutojoin(bool enabled) { + autojoin_ = enabled; + } + + bool getAutojoin() const { + return autojoin_; + } + + void setNick(const boost::optional<std::string>& nick) { + nick_ = nick; + } + + void setPassword(const boost::optional<std::string>& password) { + password_ = password; + } + + const boost::optional<std::string>& getNick() const { + return nick_; + } + + const boost::optional<std::string>& getPassword() const { + return password_; + } + + const std::string& getName() const { + return name_; + } + + const JID& getRoom() const { + return room_; + } + + bool operator==(const MUCBookmark& rhs) const { + /* FIXME: not checking passwords for equality - which might make sense, perhaps */ + return rhs.room_ == room_ && rhs.name_ == name_ && rhs.nick_ == nick_ /*&& rhs.password_ == password_*/ && rhs.autojoin_ == autojoin_; + } + + Storage::Room toStorage() const { + Storage::Room room; + room.name = name_; + room.jid = room_; + if (nick_) { + room.nick = *nick_; + } + if (password_) { + room.password = *password_; + } + room.autoJoin = autojoin_; + return room; + } + + private: + JID room_; + std::string name_; + boost::optional<std::string> nick_; + boost::optional<std::string> password_; + bool autojoin_; + }; } diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp index b109be2..1d8c2aa 100644 --- a/Swiften/MUC/MUCBookmarkManager.cpp +++ b/Swiften/MUC/MUCBookmarkManager.cpp @@ -19,103 +19,103 @@ namespace Swift { MUCBookmarkManager::MUCBookmarkManager(IQRouter* iqRouter) { - iqRouter_ = iqRouter; - ready_ = false; - GetPrivateStorageRequest<Storage>::ref request = GetPrivateStorageRequest<Storage>::create(iqRouter_); - request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksReceived, this, _1, _2)); - request->send(); + iqRouter_ = iqRouter; + ready_ = false; + GetPrivateStorageRequest<Storage>::ref request = GetPrivateStorageRequest<Storage>::create(iqRouter_); + request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksReceived, this, _1, _2)); + request->send(); } void MUCBookmarkManager::handleBookmarksReceived(boost::shared_ptr<Storage> payload, ErrorPayload::ref error) { - if (error) { - return; - } - - ready_ = true; - onBookmarksReady(); - - storage = payload; - - std::vector<MUCBookmark> receivedBookmarks; - foreach (Storage::Room room, payload->getRooms()) { - receivedBookmarks.push_back(MUCBookmark(room)); - } - - std::vector<MUCBookmark> newBookmarks; - foreach (const MUCBookmark& oldBookmark, bookmarks_) { - if (containsEquivalent(receivedBookmarks, oldBookmark)) { - newBookmarks.push_back(oldBookmark); - } else { - onBookmarkRemoved(oldBookmark); - } - } - - foreach (const MUCBookmark& newBookmark, receivedBookmarks) { - if (!containsEquivalent(bookmarks_, newBookmark)) { - newBookmarks.push_back(newBookmark); - onBookmarkAdded(newBookmark); - } - } - bookmarks_ = newBookmarks; + if (error) { + return; + } + + ready_ = true; + onBookmarksReady(); + + storage = payload; + + std::vector<MUCBookmark> receivedBookmarks; + foreach (Storage::Room room, payload->getRooms()) { + receivedBookmarks.push_back(MUCBookmark(room)); + } + + std::vector<MUCBookmark> newBookmarks; + foreach (const MUCBookmark& oldBookmark, bookmarks_) { + if (containsEquivalent(receivedBookmarks, oldBookmark)) { + newBookmarks.push_back(oldBookmark); + } else { + onBookmarkRemoved(oldBookmark); + } + } + + foreach (const MUCBookmark& newBookmark, receivedBookmarks) { + if (!containsEquivalent(bookmarks_, newBookmark)) { + newBookmarks.push_back(newBookmark); + onBookmarkAdded(newBookmark); + } + } + bookmarks_ = newBookmarks; } bool MUCBookmarkManager::containsEquivalent(const std::vector<MUCBookmark>& list, const MUCBookmark& bookmark) { - return std::find(list.begin(), list.end(), bookmark) != list.end(); + return std::find(list.begin(), list.end(), bookmark) != list.end(); } 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; - flush(); - onBookmarkRemoved(oldBookmark); - onBookmarkAdded(newBookmark); - return; - } - } + if (!ready_) return; + for (size_t i = 0; i < bookmarks_.size(); i++) { + if (bookmarks_[i] == oldBookmark) { + bookmarks_[i] = newBookmark; + flush(); + onBookmarkRemoved(oldBookmark); + onBookmarkAdded(newBookmark); + return; + } + } } void MUCBookmarkManager::addBookmark(const MUCBookmark& bookmark) { - if (!ready_) return; - bookmarks_.push_back(bookmark); - onBookmarkAdded(bookmark); - flush(); + if (!ready_) return; + bookmarks_.push_back(bookmark); + onBookmarkAdded(bookmark); + flush(); } 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) { - bookmarks_.erase(it); - onBookmarkRemoved(bookmark); - break; - } - } - flush(); + if (!ready_) return; + std::vector<MUCBookmark>::iterator it; + for (it = bookmarks_.begin(); it != bookmarks_.end(); ++it) { + if ((*it) == bookmark) { + bookmarks_.erase(it); + onBookmarkRemoved(bookmark); + break; + } + } + flush(); } void MUCBookmarkManager::flush() { - if (!storage) { - storage = boost::make_shared<Storage>(); - } - // Update the storage element - storage->clearRooms(); - foreach(const MUCBookmark& bookmark, bookmarks_) { - storage->addRoom(bookmark.toStorage()); - } - - // Send an iq to save the storage element - SetPrivateStorageRequest<Storage>::ref request = SetPrivateStorageRequest<Storage>::create(storage, iqRouter_); - // FIXME: We should care about the result - //request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksSet, this, _1, _2)); - request->send(); + if (!storage) { + storage = boost::make_shared<Storage>(); + } + // Update the storage element + storage->clearRooms(); + foreach(const MUCBookmark& bookmark, bookmarks_) { + storage->addRoom(bookmark.toStorage()); + } + + // Send an iq to save the storage element + SetPrivateStorageRequest<Storage>::ref request = SetPrivateStorageRequest<Storage>::create(storage, iqRouter_); + // FIXME: We should care about the result + //request->onResponse.connect(boost::bind(&MUCBookmarkManager::handleBookmarksSet, this, _1, _2)); + request->send(); } const std::vector<MUCBookmark>& MUCBookmarkManager::getBookmarks() const { - return bookmarks_; + return bookmarks_; } } diff --git a/Swiften/MUC/MUCBookmarkManager.h b/Swiften/MUC/MUCBookmarkManager.h index fb5d9f1..18dd677 100644 --- a/Swiften/MUC/MUCBookmarkManager.h +++ b/Swiften/MUC/MUCBookmarkManager.h @@ -18,35 +18,35 @@ #include <Swiften/MUC/MUCBookmark.h> namespace Swift { - class IQRouter; - - class SWIFTEN_API MUCBookmarkManager { - public: - MUCBookmarkManager(IQRouter* iqRouter); - - void addBookmark(const MUCBookmark& bookmark); - void removeBookmark(const MUCBookmark& bookmark); - void replaceBookmark(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark); - - const std::vector<MUCBookmark>& getBookmarks() const; - - 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); - void handleBookmarksReceived(boost::shared_ptr<Storage> payload, ErrorPayload::ref error); - void flush(); - - private: - bool ready_; - std::vector<MUCBookmark> bookmarks_; - IQRouter* iqRouter_; - boost::shared_ptr<Storage> storage; - }; + class IQRouter; + + class SWIFTEN_API MUCBookmarkManager { + public: + MUCBookmarkManager(IQRouter* iqRouter); + + void addBookmark(const MUCBookmark& bookmark); + void removeBookmark(const MUCBookmark& bookmark); + void replaceBookmark(const MUCBookmark& oldBookmark, const MUCBookmark& newBookmark); + + const std::vector<MUCBookmark>& getBookmarks() const; + + 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); + void handleBookmarksReceived(boost::shared_ptr<Storage> payload, ErrorPayload::ref error); + void flush(); + + private: + bool ready_; + std::vector<MUCBookmark> bookmarks_; + IQRouter* iqRouter_; + boost::shared_ptr<Storage> storage; + }; } diff --git a/Swiften/MUC/MUCImpl.cpp b/Swiften/MUC/MUCImpl.cpp index 774bf7a..8562ec8 100644 --- a/Swiften/MUC/MUCImpl.cpp +++ b/Swiften/MUC/MUCImpl.cpp @@ -31,7 +31,7 @@ namespace Swift { typedef std::pair<std::string, MUCOccupant> StringMUCOccupantPair; MUCImpl::MUCImpl(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry) : ownMUCJID(muc), stanzaChannel(stanzaChannel), iqRouter_(iqRouter), presenceSender(presenceSender), mucRegistry(mucRegistry), createAsReservedIfNew(false), unlocking(false), isUnlocked_(false) { - scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUCImpl::handleIncomingPresence, this, _1)); + scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUCImpl::handleIncomingPresence, this, _1)); } MUCImpl::~MUCImpl() @@ -44,427 +44,427 @@ MUCImpl::~MUCImpl() * Join the MUC with default context. */ void MUCImpl::joinAs(const std::string &nick) { - joinSince_ = boost::posix_time::not_a_date_time; - internalJoin(nick); + joinSince_ = boost::posix_time::not_a_date_time; + internalJoin(nick); } /** * Set the password used for entering the room. */ void MUCImpl::setPassword(const boost::optional<std::string>& newPassword) { - password = newPassword; + password = newPassword; } /** * Join the MUC with context since date. */ void MUCImpl::joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since) { - joinSince_ = since; - internalJoin(nick); + joinSince_ = since; + internalJoin(nick); } std::map<std::string, MUCOccupant> MUCImpl::getOccupants() const { - return occupants; + return occupants; } bool MUCImpl::isEqualExceptID(const Presence& lhs, const Presence& rhs) { - bool isEqual = false; - if (lhs.getFrom() == rhs.getFrom() && lhs.getTo() == rhs.getTo() && lhs.getStatus() == rhs.getStatus() && lhs.getShow() == rhs.getShow()) { - CapsInfo::ref lhsCaps = lhs.getPayload<CapsInfo>(); - CapsInfo::ref rhsCaps = rhs.getPayload<CapsInfo>(); - - if (!!lhsCaps && !!rhsCaps) { - isEqual = (*lhsCaps == *rhsCaps); - } - else { - isEqual = (!lhsCaps && !rhsCaps); - } - } - return isEqual; + bool isEqual = false; + if (lhs.getFrom() == rhs.getFrom() && lhs.getTo() == rhs.getTo() && lhs.getStatus() == rhs.getStatus() && lhs.getShow() == rhs.getShow()) { + CapsInfo::ref lhsCaps = lhs.getPayload<CapsInfo>(); + CapsInfo::ref rhsCaps = rhs.getPayload<CapsInfo>(); + + if (!!lhsCaps && !!rhsCaps) { + isEqual = (*lhsCaps == *rhsCaps); + } + else { + isEqual = (!lhsCaps && !rhsCaps); + } + } + return isEqual; } void MUCImpl::internalJoin(const std::string &nick) { - //TODO: history request - joinComplete_ = false; - joinSucceeded_ = false; - - mucRegistry->addMUC(getJID()); - - ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); - - Presence::ref joinPresence = presenceSender->getLastSentUndirectedPresence() ? (*presenceSender->getLastSentUndirectedPresence())->clone() : boost::make_shared<Presence>(); - assert(joinPresence->getType() == Presence::Available); - joinPresence->setTo(ownMUCJID); - MUCPayload::ref mucPayload = boost::make_shared<MUCPayload>(); - if (joinSince_ != boost::posix_time::not_a_date_time) { - mucPayload->setSince(joinSince_); - } - if (password) { - mucPayload->setPassword(*password); - } - joinPresence->addPayload(mucPayload); - joinRequestPresence_ = joinPresence; - presenceSender->sendPresence(joinPresence); + //TODO: history request + joinComplete_ = false; + joinSucceeded_ = false; + + mucRegistry->addMUC(getJID()); + + ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); + + Presence::ref joinPresence = presenceSender->getLastSentUndirectedPresence() ? (*presenceSender->getLastSentUndirectedPresence())->clone() : boost::make_shared<Presence>(); + assert(joinPresence->getType() == Presence::Available); + joinPresence->setTo(ownMUCJID); + MUCPayload::ref mucPayload = boost::make_shared<MUCPayload>(); + if (joinSince_ != boost::posix_time::not_a_date_time) { + mucPayload->setSince(joinSince_); + } + if (password) { + mucPayload->setPassword(*password); + } + joinPresence->addPayload(mucPayload); + joinRequestPresence_ = joinPresence; + presenceSender->sendPresence(joinPresence); } void MUCImpl::changeNickname(const std::string& newNickname) { - Presence::ref changeNicknamePresence = boost::make_shared<Presence>(); - changeNicknamePresence->setTo(ownMUCJID.toBare().toString() + std::string("/") + newNickname); - presenceSender->sendPresence(changeNicknamePresence); + Presence::ref changeNicknamePresence = boost::make_shared<Presence>(); + changeNicknamePresence->setTo(ownMUCJID.toBare().toString() + std::string("/") + newNickname); + presenceSender->sendPresence(changeNicknamePresence); } void MUCImpl::part() { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - mucRegistry->removeMUC(getJID()); + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + mucRegistry->removeMUC(getJID()); } void MUCImpl::handleUserLeft(LeavingType type) { - std::map<std::string,MUCOccupant>::iterator i = occupants.find(ownMUCJID.getResource()); - if (i != occupants.end()) { - MUCOccupant me = i->second; - occupants.erase(i); - onOccupantLeft(me, type, ""); - } - occupants.clear(); - joinComplete_ = false; - joinSucceeded_ = false; - isUnlocked_ = false; - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + std::map<std::string,MUCOccupant>::iterator i = occupants.find(ownMUCJID.getResource()); + if (i != occupants.end()) { + MUCOccupant me = i->second; + occupants.erase(i); + onOccupantLeft(me, type, ""); + } + occupants.clear(); + joinComplete_ = false; + joinSucceeded_ = false; + isUnlocked_ = false; + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); } void MUCImpl::handleIncomingPresence(Presence::ref presence) { - if (!isFromMUC(presence->getFrom())) { - return; - } - - MUCUserPayload::ref mucPayload; - foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) { - if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) { - mucPayload = payload; - } - } - - // On the first incoming presence, check if our join has succeeded - // (i.e. we start getting non-error presence from the MUC) or not - if (!joinSucceeded_) { - if (presence->getType() == Presence::Error) { - std::string reason; - onJoinFailed(presence->getPayload<ErrorPayload>()); - return; - } - else { - joinSucceeded_ = true; - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - if (presenceSender->getLastSentUndirectedPresence() && !isEqualExceptID(**(presenceSender->getLastSentUndirectedPresence()), *joinRequestPresence_)) { - // our presence changed between join request and join complete, send current presence to MUC - Presence::ref latestPresence = boost::make_shared<Presence>(**presenceSender->getLastSentUndirectedPresence()); - latestPresence->setTo(ownMUCJID); - presenceSender->sendPresence(latestPresence); - } - } - } - - std::string nick = presence->getFrom().getResource(); - if (nick.empty()) { - return; - } - MUCOccupant::Role role(MUCOccupant::NoRole); - MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation); - boost::optional<JID> realJID; - if (mucPayload && mucPayload->getItems().size() > 0) { - role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole; - affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation; - realJID = mucPayload->getItems()[0].realJID; - } - - //100 is non-anonymous - //TODO: 100 may also be specified in a <message/> - //170 is room logging to http - //TODO: Nick changes - if (presence->getType() == Presence::Unavailable) { - LeavingType type = LeavePart; - boost::optional<std::string> newNickname; - if (mucPayload) { - if (boost::dynamic_pointer_cast<MUCDestroyPayload>(mucPayload->getPayload())) { - type = LeaveDestroy; - } - else foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { - if (status.code == 307) { - type = LeaveKick; - } - else if (status.code == 301) { - type = LeaveBan; - } - else if (status.code == 321) { - type = LeaveNotMember; - } - else if (status.code == 303) { - if (mucPayload->getItems().size() == 1) { - newNickname = mucPayload->getItems()[0].nick; - } - } - } - } - if (newNickname) { - std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); - if (i != occupants.end()) { - MUCOccupant occupant = i->second; - occupants.erase(i); - occupant.setNick(newNickname.get()); - occupants.insert(std::make_pair(newNickname.get(), occupant)); - onOccupantNicknameChanged(nick, newNickname.get()); - } - } - else { - if (presence->getFrom() == ownMUCJID) { - handleUserLeft(type); - return; - } - else { - std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); - if (i != occupants.end()) { - //TODO: part type - MUCOccupant occupant = i->second; - occupants.erase(i); - onOccupantLeft(occupant, type, ""); - } - } - } - } - else if (presence->getType() == Presence::Available) { - std::map<std::string, MUCOccupant>::iterator it = occupants.find(nick); - MUCOccupant occupant(nick, role, affiliation); - bool isJoin = true; - if (realJID) { - occupant.setRealJID(realJID.get()); - } - if (it != occupants.end()) { - isJoin = false; - MUCOccupant oldOccupant = it->second; - if (oldOccupant.getRole() != role) { - onOccupantRoleChanged(nick, occupant, oldOccupant.getRole()); - } - if (oldOccupant.getAffiliation() != affiliation) { - onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation()); - } - occupants.erase(it); - } - std::pair<std::map<std::string, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, occupant)); - if (isJoin) { - onOccupantJoined(result.first->second); - } - onOccupantPresenceChange(presence); - } - if (mucPayload && !joinComplete_) { - bool isLocked = false; - foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { - if (status.code == 110) { - /* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */ - joinComplete_ = true; - if (ownMUCJID != presence->getFrom()) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - ownMUCJID = presence->getFrom(); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - } - // MUC status 201: a new room has been created - if (status.code == 201) { - isLocked = true; - /* Room is created and locked */ - /* Currently deal with this by making an instant room */ - if (ownMUCJID != presence->getFrom()) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - ownMUCJID = presence->getFrom(); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - } - if (createAsReservedIfNew) { - unlocking = true; - requestConfigurationForm(); - } - else { - // Accept default room configuration and create an instant room http://xmpp.org/extensions/xep-0045.html#createroom-instant - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); - mucPayload->setPayload(boost::make_shared<Form>(Form::SubmitType)); - boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared< GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); - request->send(); - } - } - } - if (joinComplete_ && !isLocked) { - onJoinComplete(getOwnNick()); - } - if (!isLocked && !isUnlocked_ && (presence->getFrom() == ownMUCJID)) { - isUnlocked_ = true; - onUnlocked(); - } - } + if (!isFromMUC(presence->getFrom())) { + return; + } + + MUCUserPayload::ref mucPayload; + foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) { + if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) { + mucPayload = payload; + } + } + + // On the first incoming presence, check if our join has succeeded + // (i.e. we start getting non-error presence from the MUC) or not + if (!joinSucceeded_) { + if (presence->getType() == Presence::Error) { + std::string reason; + onJoinFailed(presence->getPayload<ErrorPayload>()); + return; + } + else { + joinSucceeded_ = true; + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + if (presenceSender->getLastSentUndirectedPresence() && !isEqualExceptID(**(presenceSender->getLastSentUndirectedPresence()), *joinRequestPresence_)) { + // our presence changed between join request and join complete, send current presence to MUC + Presence::ref latestPresence = boost::make_shared<Presence>(**presenceSender->getLastSentUndirectedPresence()); + latestPresence->setTo(ownMUCJID); + presenceSender->sendPresence(latestPresence); + } + } + } + + std::string nick = presence->getFrom().getResource(); + if (nick.empty()) { + return; + } + MUCOccupant::Role role(MUCOccupant::NoRole); + MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation); + boost::optional<JID> realJID; + if (mucPayload && mucPayload->getItems().size() > 0) { + role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole; + affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation; + realJID = mucPayload->getItems()[0].realJID; + } + + //100 is non-anonymous + //TODO: 100 may also be specified in a <message/> + //170 is room logging to http + //TODO: Nick changes + if (presence->getType() == Presence::Unavailable) { + LeavingType type = LeavePart; + boost::optional<std::string> newNickname; + if (mucPayload) { + if (boost::dynamic_pointer_cast<MUCDestroyPayload>(mucPayload->getPayload())) { + type = LeaveDestroy; + } + else foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { + if (status.code == 307) { + type = LeaveKick; + } + else if (status.code == 301) { + type = LeaveBan; + } + else if (status.code == 321) { + type = LeaveNotMember; + } + else if (status.code == 303) { + if (mucPayload->getItems().size() == 1) { + newNickname = mucPayload->getItems()[0].nick; + } + } + } + } + if (newNickname) { + std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); + if (i != occupants.end()) { + MUCOccupant occupant = i->second; + occupants.erase(i); + occupant.setNick(newNickname.get()); + occupants.insert(std::make_pair(newNickname.get(), occupant)); + onOccupantNicknameChanged(nick, newNickname.get()); + } + } + else { + if (presence->getFrom() == ownMUCJID) { + handleUserLeft(type); + return; + } + else { + std::map<std::string,MUCOccupant>::iterator i = occupants.find(nick); + if (i != occupants.end()) { + //TODO: part type + MUCOccupant occupant = i->second; + occupants.erase(i); + onOccupantLeft(occupant, type, ""); + } + } + } + } + else if (presence->getType() == Presence::Available) { + std::map<std::string, MUCOccupant>::iterator it = occupants.find(nick); + MUCOccupant occupant(nick, role, affiliation); + bool isJoin = true; + if (realJID) { + occupant.setRealJID(realJID.get()); + } + if (it != occupants.end()) { + isJoin = false; + MUCOccupant oldOccupant = it->second; + if (oldOccupant.getRole() != role) { + onOccupantRoleChanged(nick, occupant, oldOccupant.getRole()); + } + if (oldOccupant.getAffiliation() != affiliation) { + onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation()); + } + occupants.erase(it); + } + std::pair<std::map<std::string, MUCOccupant>::iterator, bool> result = occupants.insert(std::make_pair(nick, occupant)); + if (isJoin) { + onOccupantJoined(result.first->second); + } + onOccupantPresenceChange(presence); + } + if (mucPayload && !joinComplete_) { + bool isLocked = false; + foreach (MUCUserPayload::StatusCode status, mucPayload->getStatusCodes()) { + if (status.code == 110) { + /* Simply knowing this is your presence is enough, 210 doesn't seem to be necessary. */ + joinComplete_ = true; + if (ownMUCJID != presence->getFrom()) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + ownMUCJID = presence->getFrom(); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } + } + // MUC status 201: a new room has been created + if (status.code == 201) { + isLocked = true; + /* Room is created and locked */ + /* Currently deal with this by making an instant room */ + if (ownMUCJID != presence->getFrom()) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + ownMUCJID = presence->getFrom(); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + } + if (createAsReservedIfNew) { + unlocking = true; + requestConfigurationForm(); + } + else { + // Accept default room configuration and create an instant room http://xmpp.org/extensions/xep-0045.html#createroom-instant + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + presenceSender->addDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::DontSendPresence); + mucPayload->setPayload(boost::make_shared<Form>(Form::SubmitType)); + boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared< GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); + request->send(); + } + } + } + if (joinComplete_ && !isLocked) { + onJoinComplete(getOwnNick()); + } + if (!isLocked && !isUnlocked_ && (presence->getFrom() == ownMUCJID)) { + isUnlocked_ = true; + onUnlocked(); + } + } } void MUCImpl::handleCreationConfigResponse(MUCOwnerPayload::ref /*unused*/, ErrorPayload::ref error) { - unlocking = false; - if (error) { - presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); - onJoinFailed(error); - } else { - onJoinComplete(getOwnNick()); /* Previously, this wasn't needed here, as the presence duplication bug caused an emit elsewhere. */ - isUnlocked_ = true; - onUnlocked(); - } + unlocking = false; + if (error) { + presenceSender->removeDirectedPresenceReceiver(ownMUCJID, DirectedPresenceSender::AndSendPresence); + onJoinFailed(error); + } else { + onJoinComplete(getOwnNick()); /* Previously, this wasn't needed here, as the presence duplication bug caused an emit elsewhere. */ + isUnlocked_ = true; + onUnlocked(); + } } bool MUCImpl::hasOccupant(const std::string& nick) { - return occupants.find(nick) != occupants.end(); + return occupants.find(nick) != occupants.end(); } const MUCOccupant& MUCImpl::getOccupant(const std::string& nick) { - return occupants.find(nick)->second; + return occupants.find(nick)->second; } void MUCImpl::kickOccupant(const JID& jid) { - changeOccupantRole(jid, MUCOccupant::NoRole); + changeOccupantRole(jid, MUCOccupant::NoRole); } /** * Call with the room JID, not the real JID. */ void MUCImpl::changeOccupantRole(const JID& jid, MUCOccupant::Role role) { - MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); - MUCItem item; - item.role = role; - item.nick = jid.getResource(); - mucPayload->addItem(item); - boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleOccupantRoleChangeResponse, this, _1, _2, jid, role)); - request->send(); - + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.role = role; + item.nick = jid.getResource(); + mucPayload->addItem(item); + boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleOccupantRoleChangeResponse, this, _1, _2, jid, role)); + request->send(); + } void MUCImpl::handleOccupantRoleChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Role role) { - if (error) { - onRoleChangeFailed(error, jid, role); - } + if (error) { + onRoleChangeFailed(error, jid, role); + } } void MUCImpl::requestAffiliationList(MUCOccupant::Affiliation affiliation) { - MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); - MUCItem item; - item.affiliation = affiliation; - mucPayload->addItem(item); - boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared< GenericRequest<MUCAdminPayload> >(IQ::Get, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationListResponse, this, _1, _2, affiliation)); - request->send(); + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.affiliation = affiliation; + mucPayload->addItem(item); + boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared< GenericRequest<MUCAdminPayload> >(IQ::Get, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationListResponse, this, _1, _2, affiliation)); + request->send(); } /** * Must be called with the real JID, not the room JID. */ void MUCImpl::changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation) { - MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); - MUCItem item; - item.affiliation = affiliation; - item.realJID = jid.toBare(); - mucPayload->addItem(item); - boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationChangeResponse, this, _1, _2, jid, affiliation)); - request->send(); + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.affiliation = affiliation; + item.realJID = jid.toBare(); + mucPayload->addItem(item); + boost::shared_ptr<GenericRequest<MUCAdminPayload> > request = boost::make_shared<GenericRequest<MUCAdminPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleAffiliationChangeResponse, this, _1, _2, jid, affiliation)); + request->send(); } void MUCImpl::handleAffiliationListResponse(MUCAdminPayload::ref payload, ErrorPayload::ref error, MUCOccupant::Affiliation affiliation) { - if (error) { - onAffiliationListFailed(error); - } - else { - std::vector<JID> jids; - foreach (MUCItem item, payload->getItems()) { - if (item.realJID) { - jids.push_back(*item.realJID); - } - } - onAffiliationListReceived(affiliation, jids); - } + if (error) { + onAffiliationListFailed(error); + } + else { + std::vector<JID> jids; + foreach (MUCItem item, payload->getItems()) { + if (item.realJID) { + jids.push_back(*item.realJID); + } + } + onAffiliationListReceived(affiliation, jids); + } } void MUCImpl::handleAffiliationChangeResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid, MUCOccupant::Affiliation affiliation) { - if (error) { - onAffiliationChangeFailed(error, jid, affiliation); - } + if (error) { + onAffiliationChangeFailed(error, jid, affiliation); + } } void MUCImpl::changeSubject(const std::string& subject) { - Message::ref message = boost::make_shared<Message>(); - message->setSubject(subject); - message->setType(Message::Groupchat); - message->setTo(ownMUCJID.toBare()); - stanzaChannel->sendMessage(message); + Message::ref message = boost::make_shared<Message>(); + message->setSubject(subject); + message->setType(Message::Groupchat); + message->setTo(ownMUCJID.toBare()); + stanzaChannel->sendMessage(message); } void MUCImpl::requestConfigurationForm() { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Get, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationFormReceived, this, _1, _2)); - request->send(); + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Get, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationFormReceived, this, _1, _2)); + request->send(); } void MUCImpl::cancelConfigureRoom() { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - mucPayload->setPayload(boost::make_shared<Form>(Form::CancelType)); - boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - request->send(); + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + mucPayload->setPayload(boost::make_shared<Form>(Form::CancelType)); + boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->send(); } void MUCImpl::handleConfigurationFormReceived(MUCOwnerPayload::ref payload, ErrorPayload::ref error) { - Form::ref form; - if (payload) { - form = payload->getForm(); - } - if (error || !form) { - onConfigurationFailed(error); - } else { - onConfigurationFormReceived(form); - } + Form::ref form; + if (payload) { + form = payload->getForm(); + } + if (error || !form) { + onConfigurationFailed(error); + } else { + onConfigurationFormReceived(form); + } } void MUCImpl::handleConfigurationResultReceived(MUCOwnerPayload::ref /*payload*/, ErrorPayload::ref error) { - if (error) { - onConfigurationFailed(error); - } + if (error) { + onConfigurationFailed(error); + } } void MUCImpl::configureRoom(Form::ref form) { - MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); - mucPayload->setPayload(form); - boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - if (unlocking) { - request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); - } - else { - request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationResultReceived, this, _1, _2)); - } - request->send(); + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + mucPayload->setPayload(form); + boost::shared_ptr<GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + if (unlocking) { + request->onResponse.connect(boost::bind(&MUCImpl::handleCreationConfigResponse, this, _1, _2)); + } + else { + request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationResultReceived, this, _1, _2)); + } + request->send(); } void MUCImpl::destroyRoom() { - MUCOwnerPayload::ref mucPayload = boost::make_shared<MUCOwnerPayload>(); - MUCDestroyPayload::ref mucDestroyPayload = boost::make_shared<MUCDestroyPayload>(); - mucPayload->setPayload(mucDestroyPayload); - boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); - request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationResultReceived, this, _1, _2)); - request->send(); + MUCOwnerPayload::ref mucPayload = boost::make_shared<MUCOwnerPayload>(); + MUCDestroyPayload::ref mucDestroyPayload = boost::make_shared<MUCDestroyPayload>(); + mucPayload->setPayload(mucDestroyPayload); + boost::shared_ptr< GenericRequest<MUCOwnerPayload> > request = boost::make_shared<GenericRequest<MUCOwnerPayload> >(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUCImpl::handleConfigurationResultReceived, this, _1, _2)); + request->send(); } void MUCImpl::invitePerson(const JID& person, const std::string& reason, bool isImpromptu, bool isReuseChat) { - Message::ref message = boost::make_shared<Message>(); - message->setTo(person); - message->setType(Message::Normal); - MUCInvitationPayload::ref invite = boost::make_shared<MUCInvitationPayload>(); - invite->setReason(reason); - invite->setJID(ownMUCJID.toBare()); - invite->setIsImpromptu(isImpromptu); - invite->setIsContinuation(isReuseChat); - message->addPayload(invite); - stanzaChannel->sendMessage(message); + Message::ref message = boost::make_shared<Message>(); + message->setTo(person); + message->setType(Message::Normal); + MUCInvitationPayload::ref invite = boost::make_shared<MUCInvitationPayload>(); + invite->setReason(reason); + invite->setJID(ownMUCJID.toBare()); + invite->setIsImpromptu(isImpromptu); + invite->setIsContinuation(isReuseChat); + message->addPayload(invite); + stanzaChannel->sendMessage(message); } //TODO: Invites(direct/mediated) diff --git a/Swiften/MUC/MUCImpl.h b/Swiften/MUC/MUCImpl.h index 8103e69..9b4377a 100644 --- a/Swiften/MUC/MUCImpl.h +++ b/Swiften/MUC/MUCImpl.h @@ -25,106 +25,106 @@ #include <Swiften/MUC/MUCRegistry.h> namespace Swift { - class StanzaChannel; - class IQRouter; - class DirectedPresenceSender; - - class SWIFTEN_API MUCImpl : public MUC { - public: - typedef boost::shared_ptr<MUCImpl> ref; - - public: - MUCImpl(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry); - virtual ~MUCImpl(); - - /** - * Returns the (bare) JID of the MUC. - */ - virtual JID getJID() const { - return ownMUCJID.toBare(); - } - - /** - * Returns if the room is unlocked and other people can join the room. - * @return True if joinable by others; false otherwise. - */ - virtual bool isUnlocked() const { - return isUnlocked_; - } - - virtual void joinAs(const std::string &nick); - virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since); - /*virtual void queryRoomInfo(); */ - /*virtual void queryRoomItems(); */ - /*virtual std::string getCurrentNick(); */ - virtual std::map<std::string, MUCOccupant> getOccupants() const; - - /** - * Send a new presence to the MUC indicating a nickname change. Any custom status the user had in the is cleared. - * @param newNickname The nickname to change to. - */ - virtual void changeNickname(const std::string& newNickname); - virtual void part(); - /*virtual void handleIncomingMessage(Message::ref message); */ - /** Expose public so it can be called when e.g. user goes offline */ - virtual void handleUserLeft(LeavingType); - /** Get occupant information*/ - virtual const MUCOccupant& getOccupant(const std::string& nick); - virtual bool hasOccupant(const std::string& nick); - virtual void kickOccupant(const JID& jid); - virtual void changeOccupantRole(const JID& jid, MUCOccupant::Role role); - virtual void requestAffiliationList(MUCOccupant::Affiliation); - virtual void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation); - virtual void changeSubject(const std::string& subject); - virtual void requestConfigurationForm(); - virtual void configureRoom(Form::ref); - virtual void cancelConfigureRoom(); - virtual void destroyRoom(); - /** Send an invite for the person to join the MUC */ - virtual void invitePerson(const JID& person, const std::string& reason = "", bool isImpromptu = false, bool isReuseChat = false); - virtual void setCreateAsReservedIfNew() {createAsReservedIfNew = true;} - virtual void setPassword(const boost::optional<std::string>& password); - - private: - bool isFromMUC(const JID& j) const { - return ownMUCJID.equals(j, JID::WithoutResource); - } - - const std::string& getOwnNick() const { - return ownMUCJID.getResource(); - } - - /** - * This function compares two Presence elements for equality based on to, from, status, show and entity capability information. - * @return True if equal; else otherwise. - */ - static bool isEqualExceptID(const Presence& lhs, const Presence& rhs); - - private: - void handleIncomingPresence(Presence::ref presence); - void internalJoin(const std::string& nick); - void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref); - void handleOccupantRoleChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Role); - void handleAffiliationChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Affiliation); - void handleAffiliationListResponse(MUCAdminPayload::ref, ErrorPayload::ref, MUCOccupant::Affiliation); - void handleConfigurationFormReceived(MUCOwnerPayload::ref, ErrorPayload::ref); - void handleConfigurationResultReceived(MUCOwnerPayload::ref, ErrorPayload::ref); - - private: - JID ownMUCJID; - StanzaChannel* stanzaChannel; - IQRouter* iqRouter_; - DirectedPresenceSender* presenceSender; - MUCRegistry* mucRegistry; - std::map<std::string, MUCOccupant> occupants; - bool joinSucceeded_; - bool joinComplete_; - boost::bsignals::scoped_connection scopedConnection_; - boost::posix_time::ptime joinSince_; - bool createAsReservedIfNew; - bool unlocking; - bool isUnlocked_; - boost::optional<std::string> password; - Presence::ref joinRequestPresence_; - }; + class StanzaChannel; + class IQRouter; + class DirectedPresenceSender; + + class SWIFTEN_API MUCImpl : public MUC { + public: + typedef boost::shared_ptr<MUCImpl> ref; + + public: + MUCImpl(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, const JID &muc, MUCRegistry* mucRegistry); + virtual ~MUCImpl(); + + /** + * Returns the (bare) JID of the MUC. + */ + virtual JID getJID() const { + return ownMUCJID.toBare(); + } + + /** + * Returns if the room is unlocked and other people can join the room. + * @return True if joinable by others; false otherwise. + */ + virtual bool isUnlocked() const { + return isUnlocked_; + } + + virtual void joinAs(const std::string &nick); + virtual void joinWithContextSince(const std::string &nick, const boost::posix_time::ptime& since); + /*virtual void queryRoomInfo(); */ + /*virtual void queryRoomItems(); */ + /*virtual std::string getCurrentNick(); */ + virtual std::map<std::string, MUCOccupant> getOccupants() const; + + /** + * Send a new presence to the MUC indicating a nickname change. Any custom status the user had in the is cleared. + * @param newNickname The nickname to change to. + */ + virtual void changeNickname(const std::string& newNickname); + virtual void part(); + /*virtual void handleIncomingMessage(Message::ref message); */ + /** Expose public so it can be called when e.g. user goes offline */ + virtual void handleUserLeft(LeavingType); + /** Get occupant information*/ + virtual const MUCOccupant& getOccupant(const std::string& nick); + virtual bool hasOccupant(const std::string& nick); + virtual void kickOccupant(const JID& jid); + virtual void changeOccupantRole(const JID& jid, MUCOccupant::Role role); + virtual void requestAffiliationList(MUCOccupant::Affiliation); + virtual void changeAffiliation(const JID& jid, MUCOccupant::Affiliation affiliation); + virtual void changeSubject(const std::string& subject); + virtual void requestConfigurationForm(); + virtual void configureRoom(Form::ref); + virtual void cancelConfigureRoom(); + virtual void destroyRoom(); + /** Send an invite for the person to join the MUC */ + virtual void invitePerson(const JID& person, const std::string& reason = "", bool isImpromptu = false, bool isReuseChat = false); + virtual void setCreateAsReservedIfNew() {createAsReservedIfNew = true;} + virtual void setPassword(const boost::optional<std::string>& password); + + private: + bool isFromMUC(const JID& j) const { + return ownMUCJID.equals(j, JID::WithoutResource); + } + + const std::string& getOwnNick() const { + return ownMUCJID.getResource(); + } + + /** + * This function compares two Presence elements for equality based on to, from, status, show and entity capability information. + * @return True if equal; else otherwise. + */ + static bool isEqualExceptID(const Presence& lhs, const Presence& rhs); + + private: + void handleIncomingPresence(Presence::ref presence); + void internalJoin(const std::string& nick); + void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref); + void handleOccupantRoleChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Role); + void handleAffiliationChangeResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&, MUCOccupant::Affiliation); + void handleAffiliationListResponse(MUCAdminPayload::ref, ErrorPayload::ref, MUCOccupant::Affiliation); + void handleConfigurationFormReceived(MUCOwnerPayload::ref, ErrorPayload::ref); + void handleConfigurationResultReceived(MUCOwnerPayload::ref, ErrorPayload::ref); + + private: + JID ownMUCJID; + StanzaChannel* stanzaChannel; + IQRouter* iqRouter_; + DirectedPresenceSender* presenceSender; + MUCRegistry* mucRegistry; + std::map<std::string, MUCOccupant> occupants; + bool joinSucceeded_; + bool joinComplete_; + boost::bsignals::scoped_connection scopedConnection_; + boost::posix_time::ptime joinSince_; + bool createAsReservedIfNew; + bool unlocking; + bool isUnlocked_; + boost::optional<std::string> password; + Presence::ref joinRequestPresence_; + }; } diff --git a/Swiften/MUC/MUCManager.cpp b/Swiften/MUC/MUCManager.cpp index 58a9a15..b4e3b00 100644 --- a/Swiften/MUC/MUCManager.cpp +++ b/Swiften/MUC/MUCManager.cpp @@ -14,7 +14,7 @@ MUCManager::MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, Directe } MUC::ref MUCManager::createMUC(const JID& jid) { - return boost::make_shared<MUCImpl>(stanzaChannel, iqRouter, presenceSender, jid, mucRegistry); + return boost::make_shared<MUCImpl>(stanzaChannel, iqRouter, presenceSender, jid, mucRegistry); } } diff --git a/Swiften/MUC/MUCManager.h b/Swiften/MUC/MUCManager.h index 5e237f5..c1f0f61 100644 --- a/Swiften/MUC/MUCManager.h +++ b/Swiften/MUC/MUCManager.h @@ -10,21 +10,21 @@ #include <Swiften/MUC/MUC.h> namespace Swift { - class IQRouter; - class StanzaChannel; - class DirectedPresenceSender; - class MUCRegistry; + class IQRouter; + class StanzaChannel; + class DirectedPresenceSender; + class MUCRegistry; - class SWIFTEN_API MUCManager { - public: - MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, MUCRegistry* mucRegistry); + class SWIFTEN_API MUCManager { + public: + MUCManager(StanzaChannel* stanzaChannel, IQRouter* iqRouter, DirectedPresenceSender* presenceSender, MUCRegistry* mucRegistry); - MUC::ref createMUC(const JID&); + MUC::ref createMUC(const JID&); - private: - StanzaChannel* stanzaChannel; - IQRouter* iqRouter; - DirectedPresenceSender* presenceSender; - MUCRegistry* mucRegistry; - }; + private: + StanzaChannel* stanzaChannel; + IQRouter* iqRouter; + DirectedPresenceSender* presenceSender; + MUCRegistry* mucRegistry; + }; } diff --git a/Swiften/MUC/MUCRegistry.cpp b/Swiften/MUC/MUCRegistry.cpp index 38433a7..9315173 100644 --- a/Swiften/MUC/MUCRegistry.cpp +++ b/Swiften/MUC/MUCRegistry.cpp @@ -14,15 +14,15 @@ MUCRegistry::~MUCRegistry() { } bool MUCRegistry::isMUC(const JID& j) const { - return std::find(mucs.begin(), mucs.end(), j) != mucs.end(); + return std::find(mucs.begin(), mucs.end(), j) != mucs.end(); } void MUCRegistry::addMUC(const JID& j) { - mucs.push_back(j); + mucs.push_back(j); } void MUCRegistry::removeMUC(const JID& j) { - erase(mucs, j); + erase(mucs, j); } diff --git a/Swiften/MUC/MUCRegistry.h b/Swiften/MUC/MUCRegistry.h index e69cdb5..3f61c71 100644 --- a/Swiften/MUC/MUCRegistry.h +++ b/Swiften/MUC/MUCRegistry.h @@ -12,17 +12,17 @@ #include <Swiften/JID/JID.h> namespace Swift { - class JID; + class JID; - class SWIFTEN_API MUCRegistry { - public: - ~MUCRegistry(); + class SWIFTEN_API MUCRegistry { + public: + ~MUCRegistry(); - bool isMUC(const JID& j) const; - void addMUC(const JID& j); - void removeMUC(const JID& j); + bool isMUC(const JID& j) const; + void addMUC(const JID& j); + void removeMUC(const JID& j); - private: - std::vector<JID> mucs; - }; + private: + std::vector<JID> mucs; + }; } diff --git a/Swiften/MUC/UnitTest/MUCTest.cpp b/Swiften/MUC/UnitTest/MUCTest.cpp index a422c12..548617c 100644 --- a/Swiften/MUC/UnitTest/MUCTest.cpp +++ b/Swiften/MUC/UnitTest/MUCTest.cpp @@ -24,254 +24,254 @@ using namespace Swift; class MUCTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(MUCTest); - CPPUNIT_TEST(testJoin); - CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess); - CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess); - CPPUNIT_TEST(testJoin_NoPresenceChangeDuringJoinDoesNotResendAfterJoinSuccess); - CPPUNIT_TEST(testCreateInstant); - CPPUNIT_TEST(testReplicateBug); - CPPUNIT_TEST(testNicknameChange); - /*CPPUNIT_TEST(testJoin_Success); - CPPUNIT_TEST(testJoin_Fail);*/ - CPPUNIT_TEST_SUITE_END(); - - public: - void setUp() { - channel = new DummyStanzaChannel(); - router = new IQRouter(channel); - mucRegistry = new MUCRegistry(); - stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel); - presenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); - nickChanges = 0; - } - - void tearDown() { - delete presenceSender; - delete stanzaChannelPresenceSender; - delete mucRegistry; - delete router; - delete channel; - } - - void testJoin() { - MUC::ref testling = createMUC(JID("foo@bar.com")); - testling->joinAs("Alice"); - - CPPUNIT_ASSERT(mucRegistry->isMUC(JID("foo@bar.com"))); - Presence::ref p = channel->getStanzaAtIndex<Presence>(0); - CPPUNIT_ASSERT(p); - CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); - } - - void testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess() { - MUC::ref testling = createMUC(JID("foo@bar.com")); - testling->joinAs("Alice"); - - presenceSender->sendPresence(Presence::create("Test")); - CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); - } - - void testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess() { - MUC::ref testling = createMUC(JID("foo@bar.com")); - testling->joinAs("Alice"); - - presenceSender->sendPresence(Presence::create("Test")); - receivePresence(JID("foo@bar.com/Rabbit"), "Here"); - - CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(channel->sentStanzas.size())); - Presence::ref p = channel->getStanzaAtIndex<Presence>(2); - CPPUNIT_ASSERT(p); - CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); - CPPUNIT_ASSERT_EQUAL(std::string("Test"), p->getStatus()); - } - - void testJoin_NoPresenceChangeDuringJoinDoesNotResendAfterJoinSuccess() { - MUC::ref testling = createMUC(JID("foo@bar.com")); - testling->joinAs("Alice"); - - receivePresence(JID("foo@bar.com/Rabbit"), "Here"); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); - Presence::ref p = channel->getStanzaAtIndex<Presence>(0); - CPPUNIT_ASSERT(p); - CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); - CPPUNIT_ASSERT_EQUAL(std::string(""), p->getStatus()); - } - - void testCreateInstant() { - MUC::ref testling = createMUC(JID("rabbithole@wonderland.lit")); - testling->joinAs("Alice"); - Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); - serverRespondsLocked->setFrom(JID("rabbithole@wonderland.lit/Alice")); - MUCUserPayload::ref mucPayload(new MUCUserPayload()); - MUCItem myItem; - myItem.affiliation = MUCOccupant::Owner; - myItem.role = MUCOccupant::Moderator; - mucPayload->addItem(myItem); - mucPayload->addStatusCode(MUCUserPayload::StatusCode(110)); - mucPayload->addStatusCode(MUCUserPayload::StatusCode(201)); - serverRespondsLocked->addPayload(mucPayload); - channel->onPresenceReceived(serverRespondsLocked); - CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); - IQ::ref iq = channel->getStanzaAtIndex<IQ>(1); - CPPUNIT_ASSERT(iq); - CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()); - CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm()); - CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); - } - - void testReplicateBug() { - Presence::ref initialPresence = boost::make_shared<Presence>(); - initialPresence->setStatus(""); - VCard::ref vcard = boost::make_shared<VCard>(); - vcard->setPhoto(createByteArray("15c30080ae98ec48be94bf0e191d43edd06e500a")); - initialPresence->addPayload(vcard); - CapsInfo::ref caps = boost::make_shared<CapsInfo>(); - caps->setNode("http://swift.im"); - caps->setVersion("p2UP0DrcVgKM6jJqYN/B92DKK0o="); - initialPresence->addPayload(caps); - channel->sendPresence(initialPresence); - - MUC::ref testling = createMUC(JID("test@rooms.swift.im")); - testling->joinAs("Test"); - Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); - serverRespondsLocked->setFrom(JID("test@rooms.swift.im/Test")); - serverRespondsLocked->setTo(JID("test@swift.im/6913d576d55f0b67")); - serverRespondsLocked->addPayload(vcard); - serverRespondsLocked->addPayload(caps); - serverRespondsLocked->setStatus(""); - MUCUserPayload::ref mucPayload(new MUCUserPayload()); - MUCItem myItem; - myItem.affiliation = MUCOccupant::Owner; - myItem.role = MUCOccupant::Moderator; - mucPayload->addItem(myItem); - mucPayload->addStatusCode(MUCUserPayload::StatusCode(201)); - serverRespondsLocked->addPayload(mucPayload); - channel->onPresenceReceived(serverRespondsLocked); - CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(channel->sentStanzas.size())); - IQ::ref iq = channel->getStanzaAtIndex<IQ>(2); - CPPUNIT_ASSERT(iq); - CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()); - CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm()); - CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); - } - - void testNicknameChange() { - MUC::ref testling = createMUC(JID("foo@bar.com")); - // Join as Rabbit - testling->joinAs("Rabbit"); - - // Rabbit joins - Presence::ref rabbitJoins = boost::make_shared<Presence>(); - rabbitJoins->setTo("test@swift.im/6913d576d55f0b67"); - rabbitJoins->setFrom(testling->getJID().toString() + "/Rabbit"); - channel->onPresenceReceived(rabbitJoins); - CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Rabbit")); - - // Alice joins - Presence::ref aliceJoins = boost::make_shared<Presence>(); - aliceJoins->setTo("test@swift.im/6913d576d55f0b67"); - aliceJoins->setFrom(testling->getJID().toString() + "/Alice"); - channel->onPresenceReceived(aliceJoins); - CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice")); - - // Change nick to Dodo - testling->changeNickname("Dodo"); - Presence::ref stanza = channel->getStanzaAtIndex<Presence>(1); - CPPUNIT_ASSERT(stanza); - CPPUNIT_ASSERT_EQUAL(std::string("Dodo"), stanza->getTo().getResource()); - - // Alice changes nick to Alice2 - stanza = boost::make_shared<Presence>(); - stanza->setFrom(JID("foo@bar.com/Alice")); - stanza->setTo(JID(router->getJID())); - stanza->setType(Presence::Unavailable); - MUCUserPayload::ref mucPayload(new MUCUserPayload()); - MUCItem myItem; - myItem.affiliation = MUCOccupant::Member; - myItem.nick = "Alice2"; - myItem.role = MUCOccupant::Participant; - mucPayload->addItem(myItem); - mucPayload->addStatusCode(303); - stanza->addPayload(mucPayload); - channel->onPresenceReceived(stanza); - CPPUNIT_ASSERT_EQUAL(1, nickChanges); - CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Alice")); - CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice2")); - - // We (Rabbit) change nick to Robot - stanza = boost::make_shared<Presence>(); - stanza->setFrom(JID("foo@bar.com/Rabbit")); - stanza->setTo(JID(router->getJID())); - stanza->setType(Presence::Unavailable); - mucPayload = MUCUserPayload::ref(new MUCUserPayload()); - myItem.affiliation = MUCOccupant::Member; - myItem.nick = "Robot"; - myItem.role = MUCOccupant::Participant; - mucPayload->addItem(myItem); - mucPayload->addStatusCode(303); - stanza->addPayload(mucPayload); - channel->onPresenceReceived(stanza); - CPPUNIT_ASSERT_EQUAL(2, nickChanges); - CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Rabbit")); - CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Robot")); - } - - /*void testJoin_Success() { - MUC::ref testling = createMUC(JID("foo@bar.com")); - testling->onJoinFinished.connect(boost::bind(&MUCTest::handleJoinFinished, this, _1, _2)); - testling->joinAs("Alice"); - receivePresence(JID("foo@bar.com/Rabbit"), "Here"); - - CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(joinResults.size())); - CPPUNIT_ASSERT_EQUAL(std::string("Alice"), joinResults[0].nick); - CPPUNIT_ASSERT(joinResults[0].error); - } - - void testJoin_Fail() { - //CPPUNIT_ASSERT(!mucRegistry->isMUC(JID("foo@bar.com"))); - }*/ - - private: - MUC::ref createMUC(const JID& jid) { - MUC::ref muc = boost::make_shared<MUCImpl>(channel, router, presenceSender, jid, mucRegistry); - muc->onOccupantNicknameChanged.connect(boost::bind(&MUCTest::handleOccupantNicknameChanged, this, _1, _2)); - return muc; - } - - void handleJoinFinished(const std::string& nick, ErrorPayload::ref error) { - JoinResult r; - r.nick = nick; - r.error = error; - joinResults.push_back(r); - } - - void receivePresence(const JID& jid, const std::string& status) { - Presence::ref p = Presence::create(status); - p->setFrom(jid); - //MUCUserPayload::ref mucUserPayload = boost::make_shared<MUCUserPayload>(); - //mucUserPayload->addItem(item); - //p->addPayload(mucUserPayload); - channel->onPresenceReceived(p); - } - - void handleOccupantNicknameChanged(const std::string&, const std::string&) { - nickChanges++; - } - - private: - DummyStanzaChannel* channel; - IQRouter* router; - MUCRegistry* mucRegistry; - StanzaChannelPresenceSender* stanzaChannelPresenceSender; - DirectedPresenceSender* presenceSender; - struct JoinResult { - std::string nick; - ErrorPayload::ref error; - }; - std::vector<JoinResult> joinResults; - int nickChanges; + CPPUNIT_TEST_SUITE(MUCTest); + CPPUNIT_TEST(testJoin); + CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess); + CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess); + CPPUNIT_TEST(testJoin_NoPresenceChangeDuringJoinDoesNotResendAfterJoinSuccess); + CPPUNIT_TEST(testCreateInstant); + CPPUNIT_TEST(testReplicateBug); + CPPUNIT_TEST(testNicknameChange); + /*CPPUNIT_TEST(testJoin_Success); + CPPUNIT_TEST(testJoin_Fail);*/ + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + channel = new DummyStanzaChannel(); + router = new IQRouter(channel); + mucRegistry = new MUCRegistry(); + stanzaChannelPresenceSender = new StanzaChannelPresenceSender(channel); + presenceSender = new DirectedPresenceSender(stanzaChannelPresenceSender); + nickChanges = 0; + } + + void tearDown() { + delete presenceSender; + delete stanzaChannelPresenceSender; + delete mucRegistry; + delete router; + delete channel; + } + + void testJoin() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + testling->joinAs("Alice"); + + CPPUNIT_ASSERT(mucRegistry->isMUC(JID("foo@bar.com"))); + Presence::ref p = channel->getStanzaAtIndex<Presence>(0); + CPPUNIT_ASSERT(p); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); + } + + void testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + testling->joinAs("Alice"); + + presenceSender->sendPresence(Presence::create("Test")); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); + } + + void testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + testling->joinAs("Alice"); + + presenceSender->sendPresence(Presence::create("Test")); + receivePresence(JID("foo@bar.com/Rabbit"), "Here"); + + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(channel->sentStanzas.size())); + Presence::ref p = channel->getStanzaAtIndex<Presence>(2); + CPPUNIT_ASSERT(p); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); + CPPUNIT_ASSERT_EQUAL(std::string("Test"), p->getStatus()); + } + + void testJoin_NoPresenceChangeDuringJoinDoesNotResendAfterJoinSuccess() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + testling->joinAs("Alice"); + + receivePresence(JID("foo@bar.com/Rabbit"), "Here"); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); + Presence::ref p = channel->getStanzaAtIndex<Presence>(0); + CPPUNIT_ASSERT(p); + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com/Alice"), p->getTo()); + CPPUNIT_ASSERT_EQUAL(std::string(""), p->getStatus()); + } + + void testCreateInstant() { + MUC::ref testling = createMUC(JID("rabbithole@wonderland.lit")); + testling->joinAs("Alice"); + Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); + serverRespondsLocked->setFrom(JID("rabbithole@wonderland.lit/Alice")); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Owner; + myItem.role = MUCOccupant::Moderator; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(MUCUserPayload::StatusCode(110)); + mucPayload->addStatusCode(MUCUserPayload::StatusCode(201)); + serverRespondsLocked->addPayload(mucPayload); + channel->onPresenceReceived(serverRespondsLocked); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); + IQ::ref iq = channel->getStanzaAtIndex<IQ>(1); + CPPUNIT_ASSERT(iq); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm()); + CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); + } + + void testReplicateBug() { + Presence::ref initialPresence = boost::make_shared<Presence>(); + initialPresence->setStatus(""); + VCard::ref vcard = boost::make_shared<VCard>(); + vcard->setPhoto(createByteArray("15c30080ae98ec48be94bf0e191d43edd06e500a")); + initialPresence->addPayload(vcard); + CapsInfo::ref caps = boost::make_shared<CapsInfo>(); + caps->setNode("http://swift.im"); + caps->setVersion("p2UP0DrcVgKM6jJqYN/B92DKK0o="); + initialPresence->addPayload(caps); + channel->sendPresence(initialPresence); + + MUC::ref testling = createMUC(JID("test@rooms.swift.im")); + testling->joinAs("Test"); + Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); + serverRespondsLocked->setFrom(JID("test@rooms.swift.im/Test")); + serverRespondsLocked->setTo(JID("test@swift.im/6913d576d55f0b67")); + serverRespondsLocked->addPayload(vcard); + serverRespondsLocked->addPayload(caps); + serverRespondsLocked->setStatus(""); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Owner; + myItem.role = MUCOccupant::Moderator; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(MUCUserPayload::StatusCode(201)); + serverRespondsLocked->addPayload(mucPayload); + channel->onPresenceReceived(serverRespondsLocked); + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(channel->sentStanzas.size())); + IQ::ref iq = channel->getStanzaAtIndex<IQ>(2); + CPPUNIT_ASSERT(iq); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm()); + CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); + } + + void testNicknameChange() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + // Join as Rabbit + testling->joinAs("Rabbit"); + + // Rabbit joins + Presence::ref rabbitJoins = boost::make_shared<Presence>(); + rabbitJoins->setTo("test@swift.im/6913d576d55f0b67"); + rabbitJoins->setFrom(testling->getJID().toString() + "/Rabbit"); + channel->onPresenceReceived(rabbitJoins); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Rabbit")); + + // Alice joins + Presence::ref aliceJoins = boost::make_shared<Presence>(); + aliceJoins->setTo("test@swift.im/6913d576d55f0b67"); + aliceJoins->setFrom(testling->getJID().toString() + "/Alice"); + channel->onPresenceReceived(aliceJoins); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice")); + + // Change nick to Dodo + testling->changeNickname("Dodo"); + Presence::ref stanza = channel->getStanzaAtIndex<Presence>(1); + CPPUNIT_ASSERT(stanza); + CPPUNIT_ASSERT_EQUAL(std::string("Dodo"), stanza->getTo().getResource()); + + // Alice changes nick to Alice2 + stanza = boost::make_shared<Presence>(); + stanza->setFrom(JID("foo@bar.com/Alice")); + stanza->setTo(JID(router->getJID())); + stanza->setType(Presence::Unavailable); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Member; + myItem.nick = "Alice2"; + myItem.role = MUCOccupant::Participant; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(303); + stanza->addPayload(mucPayload); + channel->onPresenceReceived(stanza); + CPPUNIT_ASSERT_EQUAL(1, nickChanges); + CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Alice")); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Alice2")); + + // We (Rabbit) change nick to Robot + stanza = boost::make_shared<Presence>(); + stanza->setFrom(JID("foo@bar.com/Rabbit")); + stanza->setTo(JID(router->getJID())); + stanza->setType(Presence::Unavailable); + mucPayload = MUCUserPayload::ref(new MUCUserPayload()); + myItem.affiliation = MUCOccupant::Member; + myItem.nick = "Robot"; + myItem.role = MUCOccupant::Participant; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(303); + stanza->addPayload(mucPayload); + channel->onPresenceReceived(stanza); + CPPUNIT_ASSERT_EQUAL(2, nickChanges); + CPPUNIT_ASSERT_EQUAL(false, testling->hasOccupant("Rabbit")); + CPPUNIT_ASSERT_EQUAL(true, testling->hasOccupant("Robot")); + } + + /*void testJoin_Success() { + MUC::ref testling = createMUC(JID("foo@bar.com")); + testling->onJoinFinished.connect(boost::bind(&MUCTest::handleJoinFinished, this, _1, _2)); + testling->joinAs("Alice"); + receivePresence(JID("foo@bar.com/Rabbit"), "Here"); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(joinResults.size())); + CPPUNIT_ASSERT_EQUAL(std::string("Alice"), joinResults[0].nick); + CPPUNIT_ASSERT(joinResults[0].error); + } + + void testJoin_Fail() { + //CPPUNIT_ASSERT(!mucRegistry->isMUC(JID("foo@bar.com"))); + }*/ + + private: + MUC::ref createMUC(const JID& jid) { + MUC::ref muc = boost::make_shared<MUCImpl>(channel, router, presenceSender, jid, mucRegistry); + muc->onOccupantNicknameChanged.connect(boost::bind(&MUCTest::handleOccupantNicknameChanged, this, _1, _2)); + return muc; + } + + void handleJoinFinished(const std::string& nick, ErrorPayload::ref error) { + JoinResult r; + r.nick = nick; + r.error = error; + joinResults.push_back(r); + } + + void receivePresence(const JID& jid, const std::string& status) { + Presence::ref p = Presence::create(status); + p->setFrom(jid); + //MUCUserPayload::ref mucUserPayload = boost::make_shared<MUCUserPayload>(); + //mucUserPayload->addItem(item); + //p->addPayload(mucUserPayload); + channel->onPresenceReceived(p); + } + + void handleOccupantNicknameChanged(const std::string&, const std::string&) { + nickChanges++; + } + + private: + DummyStanzaChannel* channel; + IQRouter* router; + MUCRegistry* mucRegistry; + StanzaChannelPresenceSender* stanzaChannelPresenceSender; + DirectedPresenceSender* presenceSender; + struct JoinResult { + std::string nick; + ErrorPayload::ref error; + }; + std::vector<JoinResult> joinResults; + int nickChanges; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCTest); diff --git a/Swiften/MUC/UnitTest/MockMUC.cpp b/Swiften/MUC/UnitTest/MockMUC.cpp index 6131183..93e7d0b 100644 --- a/Swiften/MUC/UnitTest/MockMUC.cpp +++ b/Swiften/MUC/UnitTest/MockMUC.cpp @@ -18,34 +18,34 @@ MockMUC::~MockMUC() { void MockMUC::insertOccupant(const MUCOccupant& occupant) { - occupants_.insert(std::make_pair(occupant.getNick(), occupant)); - onOccupantJoined(occupant); + occupants_.insert(std::make_pair(occupant.getNick(), occupant)); + onOccupantJoined(occupant); } const MUCOccupant& MockMUC::getOccupant(const std::string& nick) { - return occupants_.find(nick)->second; + return occupants_.find(nick)->second; } bool MockMUC::hasOccupant(const std::string& nick) { - return occupants_.find(nick) != occupants_.end(); + return occupants_.find(nick) != occupants_.end(); } void MockMUC::changeAffiliation(const JID &jid, MUCOccupant::Affiliation newAffilation) { - std::map<std::string, MUCOccupant>::iterator i = occupants_.find(jid.getResource()); - if (i != occupants_.end()) { - const MUCOccupant old = i->second; - i->second = MUCOccupant(old.getNick(), old.getRole(), newAffilation); - onOccupantAffiliationChanged(i->first, newAffilation, old.getAffiliation()); - } + std::map<std::string, MUCOccupant>::iterator i = occupants_.find(jid.getResource()); + if (i != occupants_.end()) { + const MUCOccupant old = i->second; + i->second = MUCOccupant(old.getNick(), old.getRole(), newAffilation); + onOccupantAffiliationChanged(i->first, newAffilation, old.getAffiliation()); + } } void MockMUC::changeOccupantRole(const JID &jid, MUCOccupant::Role newRole) { - std::map<std::string, MUCOccupant>::iterator i = occupants_.find(jid.getResource()); - if (i != occupants_.end()) { - const MUCOccupant old = i->second; - i->second = MUCOccupant(old.getNick(), newRole, old.getAffiliation()); - onOccupantRoleChanged(i->first, i->second, old.getRole()); - } + std::map<std::string, MUCOccupant>::iterator i = occupants_.find(jid.getResource()); + if (i != occupants_.end()) { + const MUCOccupant old = i->second; + i->second = MUCOccupant(old.getNick(), newRole, old.getAffiliation()); + onOccupantRoleChanged(i->first, i->second, old.getRole()); + } } } diff --git a/Swiften/MUC/UnitTest/MockMUC.h b/Swiften/MUC/UnitTest/MockMUC.h index c54e738..c61f8a9 100644 --- a/Swiften/MUC/UnitTest/MockMUC.h +++ b/Swiften/MUC/UnitTest/MockMUC.h @@ -25,74 +25,74 @@ #include <Swiften/MUC/MUCRegistry.h> namespace Swift { - class StanzaChannel; - class IQRouter; - class DirectedPresenceSender; + class StanzaChannel; + class IQRouter; + class DirectedPresenceSender; - class SWIFTEN_API MockMUC : public MUC{ - public: - typedef boost::shared_ptr<MockMUC> ref; + class SWIFTEN_API MockMUC : public MUC{ + public: + typedef boost::shared_ptr<MockMUC> ref; - public: - MockMUC(const JID &muc); - virtual ~MockMUC(); + public: + MockMUC(const JID &muc); + virtual ~MockMUC(); - /** - * Cause a user to appear to have entered the room. For testing only. - */ - void insertOccupant(const MUCOccupant& occupant); + /** + * Cause a user to appear to have entered the room. For testing only. + */ + void insertOccupant(const MUCOccupant& occupant); - /** - * Returns the (bare) JID of the MUC. - */ - virtual JID getJID() const { - return ownMUCJID.toBare(); - } - /** - * Returns if the room is unlocked and other people can join the room. - * @return True if joinable by others; false otherwise. - */ - virtual bool isUnlocked() const { return true; } + /** + * Returns the (bare) JID of the MUC. + */ + virtual JID getJID() const { + return ownMUCJID.toBare(); + } + /** + * Returns if the room is unlocked and other people can join the room. + * @return True if joinable by others; false otherwise. + */ + virtual bool isUnlocked() const { return true; } - virtual void joinAs(const std::string&) {} - virtual void joinWithContextSince(const std::string&, const boost::posix_time::ptime&) {} - /*virtual void queryRoomInfo(); */ - /*virtual void queryRoomItems(); */ - /*virtual std::string getCurrentNick() = 0; */ - virtual std::map<std::string, MUCOccupant> getOccupants() const { return occupants_; } - virtual void changeNickname(const std::string&) { } - virtual void part() {} - /*virtual void handleIncomingMessage(Message::ref message) = 0; */ - /** Expose public so it can be called when e.g. user goes offline */ - virtual void handleUserLeft(LeavingType) {} - /** Get occupant information*/ - virtual const MUCOccupant& getOccupant(const std::string&); - virtual bool hasOccupant(const std::string&); - virtual void kickOccupant(const JID&) {} - virtual void changeOccupantRole(const JID&, MUCOccupant::Role); - virtual void requestAffiliationList(MUCOccupant::Affiliation) {} - virtual void changeAffiliation(const JID&, MUCOccupant::Affiliation); - virtual void changeSubject(const std::string&) {} - virtual void requestConfigurationForm() {} - virtual void configureRoom(Form::ref) {} - virtual void cancelConfigureRoom() {} - virtual void destroyRoom() {} - /** Send an invite for the person to join the MUC */ - virtual void invitePerson(const JID&, const std::string&, bool, bool) {} - virtual void setCreateAsReservedIfNew() {} - virtual void setPassword(const boost::optional<std::string>&) {} + virtual void joinAs(const std::string&) {} + virtual void joinWithContextSince(const std::string&, const boost::posix_time::ptime&) {} + /*virtual void queryRoomInfo(); */ + /*virtual void queryRoomItems(); */ + /*virtual std::string getCurrentNick() = 0; */ + virtual std::map<std::string, MUCOccupant> getOccupants() const { return occupants_; } + virtual void changeNickname(const std::string&) { } + virtual void part() {} + /*virtual void handleIncomingMessage(Message::ref message) = 0; */ + /** Expose public so it can be called when e.g. user goes offline */ + virtual void handleUserLeft(LeavingType) {} + /** Get occupant information*/ + virtual const MUCOccupant& getOccupant(const std::string&); + virtual bool hasOccupant(const std::string&); + virtual void kickOccupant(const JID&) {} + virtual void changeOccupantRole(const JID&, MUCOccupant::Role); + virtual void requestAffiliationList(MUCOccupant::Affiliation) {} + virtual void changeAffiliation(const JID&, MUCOccupant::Affiliation); + virtual void changeSubject(const std::string&) {} + virtual void requestConfigurationForm() {} + virtual void configureRoom(Form::ref) {} + virtual void cancelConfigureRoom() {} + virtual void destroyRoom() {} + /** Send an invite for the person to join the MUC */ + virtual void invitePerson(const JID&, const std::string&, bool, bool) {} + virtual void setCreateAsReservedIfNew() {} + virtual void setPassword(const boost::optional<std::string>&) {} - protected: - virtual bool isFromMUC(const JID& j) const { - return ownMUCJID.equals(j, JID::WithoutResource); - } + protected: + virtual bool isFromMUC(const JID& j) const { + return ownMUCJID.equals(j, JID::WithoutResource); + } - virtual const std::string& getOwnNick() const { - return ownMUCJID.getResource(); - } + virtual const std::string& getOwnNick() const { + return ownMUCJID.getResource(); + } - private: - JID ownMUCJID; - std::map<std::string, MUCOccupant> occupants_; - }; + private: + JID ownMUCJID; + std::map<std::string, MUCOccupant> occupants_; + }; } |