spectrum2/src/transport.cpp
2011-03-07 20:52:35 +01:00

245 lines
8.6 KiB
C++

/**
* libtransport -- C++ library for easy XMPP Transports development
*
* Copyright (C) 2011, Jan Kaluza <hanzz.k@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include "transport/transport.h"
#include <boost/bind.hpp>
#include "transport/storagebackend.h"
#include "discoinforesponder.h"
using namespace Swift;
using namespace boost;
namespace Transport {
Component::Component(Swift::EventLoop *loop, Config *config) {
m_reconnectCount = 0;
m_config = config;
m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid"));
m_factories = new BoostNetworkFactories(loop);
m_reconnectTimer = m_factories->getTimerFactory()->createTimer(1000);
m_reconnectTimer->onTick.connect(bind(&Component::connect, this));
m_component = new Swift::Component(loop, m_factories, m_jid, CONFIG_STRING(m_config, "service.password"));
m_component->setSoftwareVersion("", "");
m_component->onConnected.connect(bind(&Component::handleConnected, this));
m_component->onError.connect(bind(&Component::handleConnectionError, this, _1));
m_component->onDataRead.connect(bind(&Component::handleDataRead, this, _1));
m_component->onDataWritten.connect(bind(&Component::handleDataWritten, this, _1));
m_component->onPresenceReceived.connect(bind(&Component::handlePresenceReceived, this, _1));
// m_component->onMessageReceived.connect(bind(&Component::handleMessageReceived, this, _1));
m_capsMemoryStorage = new CapsMemoryStorage();
m_capsManager = new CapsManager(m_capsMemoryStorage, m_component->getStanzaChannel(), m_component->getIQRouter());
m_entityCapsManager = new EntityCapsManager(m_capsManager, m_component->getStanzaChannel());
// m_entityCapsManager->onCapsChanged.connect(boost::bind(&Component::handleCapsChanged, this, _1));
m_presenceOracle = new PresenceOracle(m_component->getStanzaChannel());
m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1));
m_discoInfoResponder = new DiscoInfoResponder(m_component->getIQRouter());
m_discoInfoResponder->start();
//
// m_registerHandler = new SpectrumRegisterHandler(m_component);
// m_registerHandler->start();
}
Component::~Component() {
delete m_presenceOracle;
delete m_entityCapsManager;
delete m_capsManager;
delete m_capsMemoryStorage;
// delete m_discoInfoResponder;
// delete m_registerHandler;
delete m_component;
delete m_factories;
}
void Component::setTransportFeatures(std::list<std::string> &features) {
m_discoInfoResponder->setTransportFeatures(features);
}
void Component::setBuddyFeatures(std::list<std::string> &features) {
// TODO: handle caps change
m_discoInfoResponder->setBuddyFeatures(features);
}
void Component::connect() {
m_reconnectCount++;
m_component->connect(CONFIG_STRING(m_config, "service.server"), CONFIG_INT(m_config, "service.port"));
m_reconnectTimer->stop();
}
void Component::handleConnected() {
onConnected();
m_reconnectCount = 0;
}
void Component::handleConnectionError(const ComponentError &error) {
onConnectionError(error);
// if (m_reconnectCount == 2)
// Component::instance()->userManager()->removeAllUsers();
m_reconnectTimer->start();
}
void Component::handleDataRead(const std::string &data) {
onXMLIn(data);
}
void Component::handleDataWritten(const std::string &data) {
onXMLOut(data);
}
void Component::handlePresenceReceived(Swift::Presence::ref presence) {
switch(presence->getType()) {
case Swift::Presence::Subscribe:
case Swift::Presence::Subscribed:
case Swift::Presence::Unsubscribe:
case Swift::Presence::Unsubscribed:
handleSubscription(presence);
break;
case Swift::Presence::Available:
case Swift::Presence::Unavailable:
break;
case Swift::Presence::Probe:
handleProbePresence(presence);
break;
default:
break;
};
}
void Component::handlePresence(Swift::Presence::ref presence) {
bool isMUC = presence->getPayload<MUCPayload>() != NULL;
// filter out login/logout presence spam
if (!presence->getTo().getNode().empty() && isMUC == false)
return;
// filter out bad presences
if (!presence->getFrom().isValid()) {
Swift::Presence::ref response = Swift::Presence::create();
response->setTo(presence->getFrom());
response->setFrom(presence->getTo());
response->setType(Swift::Presence::Error);
response->addPayload(boost::shared_ptr<Payload>(new ErrorPayload(ErrorPayload::JIDMalformed, ErrorPayload::Modify)));
m_component->sendPresence(response);
return;
}
// check if we have this client's capabilities and ask for them
bool haveFeatures = false;
if (presence->getType() != Swift::Presence::Unavailable) {
boost::shared_ptr<CapsInfo> capsInfo = presence->getPayload<CapsInfo>();
if (capsInfo && capsInfo->getHash() == "sha-1") {
haveFeatures = m_entityCapsManager->getCaps(presence->getFrom()) != DiscoInfo::ref();
std::cout << "has capsInfo " << haveFeatures << "\n";
}
else {
GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(presence->getFrom(), m_component->getIQRouter());
discoInfoRequest->onResponse.connect(boost::bind(&Component::handleDiscoInfoResponse, this, _1, _2, presence->getFrom()));
discoInfoRequest->send();
}
}
onUserPresenceReceived(presence);
}
void Component::handleProbePresence(Swift::Presence::ref presence) {
}
void Component::handleSubscription(Swift::Presence::ref presence) {
// answer to subscibe
if (presence->getType() == Swift::Presence::Subscribe && presence->getTo().getNode().empty()) {
// Log(presence->getFrom().toString().getUTF8String(), "Subscribe presence received => sending subscribed");
Swift::Presence::ref response = Swift::Presence::create();
response->setFrom(presence->getTo());
response->setTo(presence->getFrom());
response->setType(Swift::Presence::Subscribed);
m_component->sendPresence(response);
return;
}
if (m_protocol == "irc") {
return;
}
// User *user;
// std::string barejid = presence->getTo().toBare().toString().getUTF8String();
// std::string userkey = presence->getFrom().toBare().toString().getUTF8String();
// if (Transport::instance()->protocol()->tempAccountsAllowed()) {
// std::string server = barejid.substr(barejid.find("%") + 1, barejid.length() - barejid.find("%"));
// userkey += server;
// }
// user = (User *) Transport::instance()->userManager()->getUserByJID(userkey);
// if (user) {
// user->handleSubscription(presence);
// }
// else if (presence->getType() == Swift::Presence::Unsubscribe) {
// Swift::Presence::ref response = Swift::Presence::create();
// response->setFrom(presence->getTo());
// response->setTo(presence->getFrom());
// response->setType(Swift::Presence::Unsubscribed);
// m_component->sendPresence(response);
// }
// else {
// // Log(presence->getFrom().toString().getUTF8String(), "Subscribe presence received, but this user is not logged in");
// }
}
void Component::handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> discoInfo, Swift::ErrorPayload::ref error, const Swift::JID& jid) {
// AbstractUser *user = Transport::instance()->userManager()->getUserByJID(jid.toBare().toString().getUTF8String());
//
// std::string resource = jid.getResource().getUTF8String();
// if (user && user->hasResource(resource)) {
// if (user->getResource(resource).caps == 0) {
// int capabilities = 0;
//
// for (std::vector< String >::const_iterator it = discoInfo->getFeatures().begin(); it != discoInfo->getFeatures().end(); ++it) {
// if (*it == "http://jabber.org/protocol/rosterx") {
// capabilities |= CLIENT_FEATURE_ROSTERX;
// }
// else if (*it == "http://jabber.org/protocol/xhtml-im") {
// capabilities |= CLIENT_FEATURE_XHTML_IM;
// }
// else if (*it == "http://jabber.org/protocol/si/profile/file-transfer") {
// capabilities |= CLIENT_FEATURE_FILETRANSFER;
// }
// else if (*it == "http://jabber.org/protocol/chatstates") {
// capabilities |= CLIENT_FEATURE_CHATSTATES;
// }
// }
//
// user->setResource(resource, -256, capabilities);
// if (user->readyForConnect()) {
// user->connect();
// }
// }
// }
}
}