diff --git a/include/Swiften/Server/ServerStanzaChannel.cpp b/include/Swiften/Server/ServerStanzaChannel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..690cc515b1ff624606f2b2eed98a059dbd7008a9 --- /dev/null +++ b/include/Swiften/Server/ServerStanzaChannel.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Base/Error.h" + +#include + +namespace Swift { + +namespace { +// struct PriorityLessThan { +// bool operator()(const ServerSession* s1, const ServerSession* s2) const { +// return s1->getPriority() < s2->getPriority(); +// } +// }; + + struct HasJID { + HasJID(const JID& jid) : jid(jid) {} + bool operator()(const boost::shared_ptr session) const { + return session->getRemoteJID().equals(jid, JID::WithResource); + } + JID jid; + }; +} + +void ServerStanzaChannel::addSession(boost::shared_ptr session) { + sessions.push_back(session); + session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); + session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); +} + +void ServerStanzaChannel::removeSession(boost::shared_ptr session) { + session->onSessionFinished.disconnect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); + session->onElementReceived.disconnect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); + sessions.erase(std::remove(sessions.begin(), sessions.end(), session), sessions.end()); +} + +void ServerStanzaChannel::sendIQ(boost::shared_ptr iq) { + send(iq); +} + +void ServerStanzaChannel::sendMessage(boost::shared_ptr message) { + send(message); +} + +void ServerStanzaChannel::sendPresence(boost::shared_ptr presence) { + send(presence); +} + +void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element) { + std::vector > candidateSessions; + for (std::list >::const_iterator i = sessions.begin(); i != sessions.end(); ++i) { + if ((*i)->getRemoteJID().equals(to, JID::WithoutResource)) { + (*i)->sendElement(element); + candidateSessions.push_back(*i); + } + } + + for (std::vector >::const_iterator i = candidateSessions.begin(); i != candidateSessions.end(); ++i) { + (*i)->finishSession(); + } +} + +std::string ServerStanzaChannel::getNewIQID() { + return idGenerator.generateID(); +} + +void ServerStanzaChannel::send(boost::shared_ptr stanza) { + JID to = stanza->getTo(); + assert(to.isValid()); + + // For a full JID, first try to route to a session with the full JID + if (!to.isBare()) { + std::list >::const_iterator i = std::find_if(sessions.begin(), sessions.end(), HasJID(to)); + if (i != sessions.end()) { + (*i)->sendElement(stanza); + return; + } + } + + // Look for candidate sessions + to = to.toBare(); + std::vector > candidateSessions; + for (std::list >::const_iterator i = sessions.begin(); i != sessions.end(); ++i) { + if ((*i)->getRemoteJID().equals(to, JID::WithoutResource)) { + candidateSessions.push_back(*i); + (*i)->sendElement(stanza); + } + } + if (candidateSessions.empty()) { + return; + } + + // Find the session with the highest priority +// std::vector::const_iterator i = std::max_element(sessions.begin(), sessions.end(), PriorityLessThan()); +// (*i)->sendStanza(stanza); + return; +} + +void ServerStanzaChannel::handleSessionFinished(const boost::optional&, const boost::shared_ptr& session) { + removeSession(session); + + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(JID(session->getUser(), session->getLocalJID().getDomain()).toString()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); +} + +void ServerStanzaChannel::handleElement(boost::shared_ptr element, const boost::shared_ptr& session) { + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + if (stanza->getFrom().toString().empty()) { + stanza->setFrom(session->getRemoteJID()); + } + + if (!stanza->getFrom().isValid()) + return; + + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + onMessageReceived(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + onPresenceReceived(presence); + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + onIQReceived(iq); + return; + } +} + +void ServerStanzaChannel::handleSessionInitialized() { + onAvailableChanged(true); +} + +}