Get room list on IRC and show rooms in service discovery

This commit is contained in:
Jan Kaluza 2012-10-18 09:04:20 +02:00
parent 22679e921b
commit 3201977efb
18 changed files with 192 additions and 51 deletions

View file

@ -23,6 +23,8 @@
DEFINE_LOGGER(logger, "IRCSession");
static bool sentList;
MyIrcSession::MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix, QObject* parent) : IrcSession(parent)
{
this->np = np;
@ -40,6 +42,10 @@ void MyIrcSession::on_connected() {
m_connected = true;
if (suffix.empty()) {
np->handleConnected(user);
if (!sentList) {
sendCommand(IrcCommand::createList(""));
sentList = true;
}
}
for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) {
@ -208,6 +214,17 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) {
case 432:
np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname");
break;
case 321:
m_rooms.clear();
m_names.clear();
break;
case 322:
m_rooms.push_back(TO_UTF8(m->parameters().value(1)));
m_names.push_back(TO_UTF8(m->parameters().value(1)));
break;
case 323:
np->handleRoomList("", m_rooms, m_names);
break;
default:
break;
}

View file

@ -85,6 +85,8 @@ protected:
AutoJoinMap m_autoJoin;
std::string m_topicData;
bool m_connected;
std::list<std::string> m_rooms;
std::list<std::string> m_names;
};
//class MyIrcBuffer : public Irc::Buffer

View file

@ -28,12 +28,15 @@
namespace Transport {
class Component;
class DiscoInfoResponder;
class DiscoItemsResponder : public Swift::GetResponder<Swift::DiscoItems> {
public:
DiscoItemsResponder(Component *component);
~DiscoItemsResponder();
Swift::CapsInfo &getBuddyCapsInfo();
void addAdHocCommand(const std::string &node, const std::string &name);
// void removeAdHocCommand(const std::string &node);
@ -48,6 +51,7 @@ class DiscoItemsResponder : public Swift::GetResponder<Swift::DiscoItems> {
Component *m_component;
boost::shared_ptr<Swift::DiscoItems> m_commands;
boost::shared_ptr<Swift::DiscoItems> m_rooms;
DiscoInfoResponder *m_discoInfoResponder;
};
}

View file

@ -47,7 +47,6 @@ namespace Transport {
// } SpectrumImportantFeatures;
//
class StorageBackend;
class DiscoInfoResponder;
class Factory;
class UserRegistry;
@ -81,8 +80,6 @@ namespace Transport {
/// \return Swift::StanzaChannel associated with this Transport::Component.
Swift::StanzaChannel *getStanzaChannel();
Swift::CapsInfo &getBuddyCapsInfo();
/// Returns Swift::IQRouter associated with this Component.
/// \return Swift::IQRouter associated with this Component.
@ -104,18 +101,6 @@ namespace Transport {
void start();
void stop();
/// Sets disco#info features which are sent as answer to disco#info IQ-get.
/// This sets features of transport contact (For example "j2j.domain.tld").
/// \param features list of features as sent in disco#info response
void setTransportFeatures(std::list<std::string> &features);
/// Sets disco#info features which are sent as answer to disco#info IQ-get.
/// This sets features of legacy network buddies (For example "me\40gmail.com@j2j.domain.tld").
/// \param features list of features as sent in disco#info response
void setBuddyFeatures(std::list<std::string> &features);
/// Returns Jabber ID of this transport.
/// \return Jabber ID of this transport
@ -186,7 +171,6 @@ namespace Transport {
Transport::UserRegistry *m_userRegistry;
StorageBackend *m_storageBackend;
DiscoInfoResponder *m_discoInfoResponder;
int m_reconnectCount;
Config* m_config;
std::string m_protocol;

View file

@ -71,6 +71,8 @@ class User : public Swift::EntityCapsProvider {
Component *getComponent() { return m_component; }
UserManager *getUserManager() { return m_userManager; }
void setData(void *data) { m_data = data; }
void *getData() { return m_data; }

View file

@ -32,6 +32,7 @@ class Component;
class StorageBackend;
class StorageResponder;
class RosterResponder;
class DiscoItemsResponder;
/// Manages online XMPP Users.
@ -55,7 +56,7 @@ class UserManager : public Swift::EntityCapsProvider {
/// Creates new UserManager.
/// \param component Component which's presence will be handled
/// \param storageBackend Storage backend used to fetch UserInfos
UserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend = NULL);
UserManager(Component *component, UserRegistry *userRegistry, DiscoItemsResponder *discoItemsResponder, StorageBackend *storageBackend = NULL);
/// Destroys UserManager.
~UserManager();
@ -84,6 +85,8 @@ class UserManager : public Swift::EntityCapsProvider {
Swift::DiscoInfo::ref getCaps(const Swift::JID&) const;
DiscoItemsResponder *getDiscoResponder() { return m_discoItemsResponder; }
/// Called when new User class is created.
/// \param user newly created User class
boost::signal<void (User *user)> onUserCreated;
@ -143,6 +146,7 @@ class UserManager : public Swift::EntityCapsProvider {
Swift::Timer::ref m_removeTimer;
unsigned long m_sentToXMPP;
unsigned long m_sentToBackend;
DiscoItemsResponder *m_discoItemsResponder;
friend class RosterResponder;
};

View file

@ -384,7 +384,10 @@ int main(int argc, char **argv)
Logging::redirect_stderr();
UserManager userManager(&transport, &userRegistry, storageBackend);
DiscoItemsResponder discoItemsResponder(&transport);
discoItemsResponder.start();
UserManager userManager(&transport, &userRegistry, &discoItemsResponder, storageBackend);
userManager_ = &userManager;
UserRegistration *userRegistration = NULL;
@ -398,9 +401,6 @@ int main(int argc, char **argv)
FileTransferManager ftManager(&transport, &userManager);
DiscoItemsResponder discoItemsResponder(&transport);
discoItemsResponder.start();
NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder);
AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration);

View file

@ -13,15 +13,16 @@ admin_password=test
#cert=server.pfx #patch to PKCS#12 certificate
#cert_password=test #password to that certificate if any
users_per_backend=10
backend=../..//backends/libpurple/spectrum2_libpurple_backend
#backend=../..//backends/libpurple/spectrum2_libpurple_backend
#backend=../../backends/twitter/spectrum2_twitter_backend
#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_communi_backend
backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend
protocol=prpl-icq
#protocol=prpl-msn
#protocol=any
#protocol=prpl-icq
working_dir=./
portfile=$jid.port
irc_server=irc.freenode.org
[backend]
#default_avatar=catmelonhead.jpg

View file

@ -23,6 +23,8 @@
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/BlockPayload.h"
#include "transport/usermanager.h"
#include "transport/discoitemsresponder.h"
namespace Transport {
@ -106,7 +108,7 @@ Swift::Presence::ref Buddy::generatePresenceStanza(int features, bool only_new)
if (presence->getType() != Swift::Presence::Unavailable) {
// caps
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::CapsInfo(m_rosterManager->getUser()->getComponent()->getBuddyCapsInfo())));
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::CapsInfo(m_rosterManager->getUser()->getUserManager()->getDiscoResponder()->getBuddyCapsInfo())));
// if (features & 0/*TRANSPORT_FEATURE_AVATARS*/) {
presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::VCardUpdate (getIconHash())));

View file

@ -97,6 +97,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description
("service.more_resources", value<bool>()->default_value(false), "Allow more resources to be connected in server mode at the same time.")
("service.enable_privacy_lists", value<bool>()->default_value(true), "")
("service.enable_xhtml", value<bool>()->default_value(true), "")
("service.max_room_list_size", value<int>()->default_value(100), "")
("vhosts.vhost", value<std::vector<std::string> >()->multitoken(), "")
("identity.name", value<std::string>()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.")
("identity.category", value<std::string>()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.")

View file

@ -22,15 +22,19 @@
#include <iostream>
#include <boost/bind.hpp>
#include <boost/algorithm/string.hpp>
#include "Swiften/Disco/DiscoInfoResponder.h"
#include "Swiften/Queries/IQRouter.h"
#include "Swiften/Elements/DiscoInfo.h"
#include "Swiften/Swiften.h"
#include "transport/config.h"
#include "transport/logging.h"
using namespace Swift;
using namespace boost;
DEFINE_LOGGER(logger, "DiscoInfoResponder");
namespace Transport {
DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) : Swift::GetResponder<DiscoInfo>(router) {
@ -80,19 +84,37 @@ void DiscoInfoResponder::setBuddyFeatures(std::list<std::string> &f) {
onBuddyCapsInfoChanged(m_capsInfo);
}
void DiscoInfoResponder::addRoom(const std::string &jid, const std::string &name) {
std::string j = jid;
boost::algorithm::to_lower(j);
m_rooms[j] = name;
}
void DiscoInfoResponder::clearRooms() {
m_rooms.clear();
}
bool DiscoInfoResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::DiscoInfo> info) {
if (!info->getNode().empty()) {
sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel);
return true;
}
// presence for transport
// disco#info for transport
if (to.getNode().empty()) {
boost::shared_ptr<DiscoInfo> res(new DiscoInfo(m_transportInfo));
res->setNode(info->getNode());
sendResponse(from, id, res);
}
// presence for buddy
// disco#info for room
else if (m_rooms.find(to.toBare().toString()) != m_rooms.end()) {
boost::shared_ptr<DiscoInfo> res(new DiscoInfo());
res->addIdentity(DiscoInfo::Identity(m_rooms[to.toBare().toString()], "conference", "text"));
res->setNode(info->getNode());
sendResponse(from, to, id, res);
}
// disco#info for buddy
else {
boost::shared_ptr<DiscoInfo> res(new DiscoInfo(m_buddyInfo));
res->setNode(info->getNode());

View file

@ -38,6 +38,9 @@ class DiscoInfoResponder : public Swift::GetResponder<Swift::DiscoInfo> {
void setTransportFeatures(std::list<std::string> &features);
void setBuddyFeatures(std::list<std::string> &features);
void addRoom(const std::string &jid, const std::string &name);
void clearRooms();
boost::signal<void (const Swift::CapsInfo &capsInfo)> onBuddyCapsInfoChanged;
Swift::CapsInfo &getBuddyCapsInfo() {
@ -51,6 +54,7 @@ class DiscoInfoResponder : public Swift::GetResponder<Swift::DiscoInfo> {
Swift::DiscoInfo m_buddyInfo;
Config *m_config;
Swift::CapsInfo m_capsInfo;
std::map<std::string, std::string> m_rooms;
};
}

View file

@ -26,6 +26,7 @@
#include "Swiften/Swiften.h"
#include "transport/transport.h"
#include "transport/logging.h"
#include "discoinforesponder.h"
using namespace Swift;
using namespace boost;
@ -40,10 +41,12 @@ DiscoItemsResponder::DiscoItemsResponder(Component *component) : Swift::GetRespo
m_commands->setNode("http://jabber.org/protocol/commands");
m_rooms = boost::shared_ptr<DiscoItems>(new DiscoItems());
m_discoInfoResponder = new DiscoInfoResponder(component->getIQRouter(), component->getConfig());
m_discoInfoResponder->start();
}
DiscoItemsResponder::~DiscoItemsResponder() {
delete m_discoInfoResponder;
}
void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::string &name) {
@ -51,11 +54,20 @@ void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::st
}
void DiscoItemsResponder::addRoom(const std::string &node, const std::string &name) {
m_rooms->addItem(DiscoItems::Item(name, m_component->getJID(), node));
if (m_rooms->getItems().size() > CONFIG_INT(m_component->getConfig(), "service.max_room_list_size")) {
return;
}
m_rooms->addItem(DiscoItems::Item(name, node));
m_discoInfoResponder->addRoom(node, name);
}
void DiscoItemsResponder::clearRooms() {
m_rooms = boost::shared_ptr<DiscoItems>(new DiscoItems());
m_discoInfoResponder->clearRooms();
}
Swift::CapsInfo &DiscoItemsResponder::getBuddyCapsInfo() {
return m_discoInfoResponder->getBuddyCapsInfo();
}

View file

@ -861,7 +861,7 @@ void NetworkPluginServer::handleRoomListPayload(const std::string &data) {
m_discoItemsResponder->clearRooms();
for (int i = 0; i < payload.room_size() && i < payload.name_size(); i++) {
m_discoItemsResponder->addRoom(payload.room(i), payload.name(i));
m_discoItemsResponder->addRoom(Swift::JID::getEscapedNode(payload.room(i)) + "@" + m_component->getJID().toString(), payload.name(i));
}
}

View file

@ -57,14 +57,14 @@ void BasicTest::setMeUp (void) {
component = new Component(loop, factories, cfg, factory, userRegistry);
component->start();
userManager = new UserManager(component, userRegistry, storage);
itemsResponder = new DiscoItemsResponder(component);
itemsResponder->start();
userManager = new UserManager(component, userRegistry, itemsResponder, storage);
userRegistration = new UserRegistration(component, userManager, storage);
userRegistration->start();
itemsResponder = new DiscoItemsResponder(component);
itemsResponder->start();
payloadSerializers = new Swift::FullPayloadSerializerCollection();
payloadParserFactories = new Swift::FullPayloadParserFactoryCollection();

View file

@ -0,0 +1,100 @@
#include "transport/userregistry.h"
#include "transport/userregistration.h"
#include "transport/config.h"
#include "transport/storagebackend.h"
#include "transport/user.h"
#include "transport/transport.h"
#include "transport/conversation.h"
#include "transport/usermanager.h"
#include "transport/localbuddy.h"
#include "transport/settingsadhoccommand.h"
#include "transport/adhocmanager.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <Swiften/Swiften.h>
#include <Swiften/EventLoop/DummyEventLoop.h>
#include <Swiften/Server/Server.h>
#include <Swiften/Network/DummyNetworkFactories.h>
#include <Swiften/Network/DummyConnectionServer.h>
#include "Swiften/Server/ServerStanzaChannel.h"
#include "Swiften/Server/ServerFromClientSession.h"
#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"
#include "basictest.h"
using namespace Transport;
class DiscoItemsResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTest {
CPPUNIT_TEST_SUITE(DiscoItemsResponderTest);
CPPUNIT_TEST(roomList);
CPPUNIT_TEST(roomInfo);
CPPUNIT_TEST(clearRooms);
CPPUNIT_TEST_SUITE_END();
public:
void setUp (void) {
setMeUp();
}
void tearDown (void) {
received.clear();
tearMeDown();
}
void roomList() {
itemsResponder->addRoom("#room@localhost", "#room");
boost::shared_ptr<Swift::DiscoItems> payload(new Swift::DiscoItems());
boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
iq->setFrom("user@localhost");
injectIQ(iq);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>());
CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost"), getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems()[0].getJID().toString());
CPPUNIT_ASSERT_EQUAL(std::string("#room"), getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems()[0].getName());
}
void roomInfo() {
itemsResponder->addRoom("#room@localhost", "#room");
boost::shared_ptr<Swift::DiscoInfo> payload(new Swift::DiscoInfo());
boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
iq->setFrom("user@localhost");
iq->setTo("#room@localhost");
injectIQ(iq);
loop->processEvents();
dumpReceived();
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoInfo>());
CPPUNIT_ASSERT_EQUAL(std::string("#room"), getStanza(received[0])->getPayload<Swift::DiscoInfo>()->getIdentities()[0].getName());
CPPUNIT_ASSERT_EQUAL(std::string("conference"), getStanza(received[0])->getPayload<Swift::DiscoInfo>()->getIdentities()[0].getCategory());
CPPUNIT_ASSERT_EQUAL(std::string("text"), getStanza(received[0])->getPayload<Swift::DiscoInfo>()->getIdentities()[0].getType());
}
void clearRooms() {
itemsResponder->addRoom("#room@localhost", "#room");
itemsResponder->clearRooms();
boost::shared_ptr<Swift::DiscoItems> payload(new Swift::DiscoItems());
boost::shared_ptr<Swift::IQ> iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload);
iq->setFrom("user@localhost");
injectIQ(iq);
loop->processEvents();
CPPUNIT_ASSERT_EQUAL(1, (int) received.size());
CPPUNIT_ASSERT(dynamic_cast<Swift::IQ *>(getStanza(received[0])));
CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast<Swift::IQ *>(getStanza(received[0]))->getType());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>());
CPPUNIT_ASSERT(getStanza(received[0])->getPayload<Swift::DiscoItems>()->getItems().empty());
}
};
CPPUNIT_TEST_SUITE_REGISTRATION (DiscoItemsResponderTest);

View file

@ -26,7 +26,6 @@
#include "transport/factory.h"
#include "transport/userregistry.h"
#include "transport/logging.h"
#include "discoinforesponder.h"
#include "storageparser.h"
#ifdef _WIN32
#include <Swiften/TLS/CAPICertificate.h>
@ -158,8 +157,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
m_presenceOracle = new Transport::PresenceOracle(m_stanzaChannel);
m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1));
m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter, m_config);
m_discoInfoResponder->start();
//
// m_registerHandler = new SpectrumRegisterHandler(m_component);
@ -171,7 +169,6 @@ Component::~Component() {
delete m_entityCapsManager;
delete m_capsManager;
delete m_capsMemoryStorage;
delete m_discoInfoResponder;
if (m_component)
delete m_component;
if (m_server) {
@ -188,19 +185,6 @@ Transport::PresenceOracle *Component::getPresenceOracle() {
return m_presenceOracle;
}
void Component::setTransportFeatures(std::list<std::string> &features) {
m_discoInfoResponder->setTransportFeatures(features);
}
Swift::CapsInfo &Component::getBuddyCapsInfo() {
return m_discoInfoResponder->getBuddyCapsInfo();
}
void Component::setBuddyFeatures(std::list<std::string> &features) {
// TODO: handle caps change
m_discoInfoResponder->setBuddyFeatures(features);
}
void Component::start() {
if (m_component && !m_component->isAvailable()) {
LOG4CXX_INFO(logger, "Connecting XMPP server " << CONFIG_STRING(m_config, "service.server") << " port " << CONFIG_INT(m_config, "service.port"));

View file

@ -26,6 +26,7 @@
#include "transport/rostermanager.h"
#include "transport/userregistry.h"
#include "transport/logging.h"
#include "transport/discoitemsresponder.h"
#include "storageresponder.h"
#include "Swiften/Swiften.h"
@ -40,7 +41,7 @@ namespace Transport {
DEFINE_LOGGER(logger, "UserManager");
UserManager::UserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) {
UserManager::UserManager(Component *component, UserRegistry *userRegistry, DiscoItemsResponder *discoItemsResponder, StorageBackend *storageBackend) {
m_cachedUser = NULL;
m_onlineBuddies = 0;
m_sentToXMPP = 0;
@ -49,6 +50,7 @@ UserManager::UserManager(Component *component, UserRegistry *userRegistry, Stora
m_storageBackend = storageBackend;
m_storageResponder = NULL;
m_userRegistry = userRegistry;
m_discoItemsResponder = discoItemsResponder;
if (m_storageBackend) {
m_storageResponder = new StorageResponder(component->getIQRouter(), m_storageBackend, this);