/* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swiften/MUC/MUC.h" #include #include #include #include "Swiften/Presence/PresenceSender.h" #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Elements/IQ.h" #include "Swiften/Elements/MUCUserPayload.h" #include "Swiften/Elements/MUCPayload.h" namespace Swift { typedef std::pair StringMUCOccupantPair; MUC::MUC(StanzaChannel* stanzaChannel, PresenceSender* presenceSender, const JID &muc) : ownMUCJID(muc), stanzaChannel(stanzaChannel), presenceSender(presenceSender) { scopedConnection_ = stanzaChannel->onPresenceReceived.connect(boost::bind(&MUC::handleIncomingPresence, this, _1)); } //FIXME: discover reserved nickname void MUC::joinAs(const String &nick) { //TODO: password //TODO: history request joinComplete_ = false; ownMUCJID = JID(ownMUCJID.getNode(), ownMUCJID.getDomain(), nick); boost::shared_ptr joinPresence(new Presence()); joinPresence->setTo(ownMUCJID); joinPresence->addPayload(boost::shared_ptr(new MUCPayload())); presenceSender->sendPresence(joinPresence); } void MUC::part() { presenceSender->removeDirectedPresenceReceiver(ownMUCJID); } void MUC::handleIncomingPresence(boost::shared_ptr presence) { if (!isFromMUC(presence->getFrom())) { return; } boost::shared_ptr mucPayload; foreach (boost::shared_ptr payload, presence->getPayloads()) { if (payload->getItems().size() > 0 || payload->getStatusCodes().size() > 0) { mucPayload = payload; } } if (!joinComplete_) { if (presence->getType() == Presence::Error) { String reason; onJoinFailed(presence->getPayload()); return; } } String nick = presence->getFrom().getResource(); if (nick.isEmpty()) { return; } MUCOccupant::Role role(MUCOccupant::NoRole); MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation); if (mucPayload && mucPayload->getItems().size() > 0) { role = mucPayload->getItems()[0].role; affiliation = mucPayload->getItems()[0].affiliation; } //100 is non-anonymous //TODO: 100 may also be specified in a //170 is room logging to http //TODO: Nick changes if (presence->getType() == Presence::Unavailable) { std::map::iterator i = occupants.find(nick); if (i != occupants.end()) { //TODO: part type onOccupantLeft(i->second, Part, ""); occupants.erase(i); } } else if (presence->getType() == Presence::Available) { std::map::iterator it = occupants.find(nick); if (it != occupants.end()) { MUCOccupant oldOccupant = it->second; if (oldOccupant.getRole() != role) { onOccupantRoleChanged(nick, role, oldOccupant.getRole()); } if (oldOccupant.getAffiliation() != affiliation) { onOccupantAffiliationChanged(nick, affiliation, oldOccupant.getAffiliation()); } } std::pair::iterator, bool> result = occupants.insert(std::make_pair(nick, MUCOccupant(nick, role, affiliation))); if (result.second) { onOccupantJoined(result.first->second); } onOccupantPresenceChange(presence); } if (mucPayload && !joinComplete_) { 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; ownMUCJID = presence->getFrom(); onJoinComplete(getOwnNick()); presenceSender->addDirectedPresenceReceiver(ownMUCJID); } } } } //FIXME: Recognise Topic changes //TODO: Invites(direct/mediated) //TODO: requesting membership //TODO: get member list //TODO: request voice //TODO: moderator use cases //TODO: Admin use cases //TODO: Owner use cases }