Connecting the legacy network

This commit is contained in:
HanzZ 2011-03-18 09:44:23 +01:00
parent 96e0e9f7a6
commit 5f017bd15d
8 changed files with 224 additions and 41 deletions

View file

@ -93,6 +93,8 @@ namespace Transport {
/// \return Jabber ID of this transport
Swift::JID &getJID() { return m_jid; }
Swift::BoostNetworkFactories *getFactories() { return m_factories; }
/// This signal is emitted when server disconnects the transport because of some error.
/// \param error disconnection error
boost::signal<void (const Swift::ComponentError &error)> onConnectionError;
@ -114,6 +116,8 @@ namespace Transport {
/// \param presence presence data
boost::signal<void (Swift::Presence::ref presence)> onUserPresenceReceived;
// boost::signal<void (boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid)> onDiscoInfoResponse;
private:
void handleConnected();
void handleConnectionError(const Swift::ComponentError &error);
@ -125,8 +129,8 @@ namespace Transport {
void handleDataRead(const std::string &data);
void handleDataWritten(const std::string &data);
void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
// void handleCapsChanged(const Swift::JID& jid);
// void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
void handleCapsChanged(const Swift::JID& jid);
Swift::BoostNetworkFactories *m_factories;
Swift::Component *m_component;

View file

@ -52,6 +52,9 @@ class User {
/// \return UserInfo struct
UserInfo &getUserInfo() { return m_userInfo; }
void setData(void *data) { m_data = data; }
void *getData() { return m_data; }
/// Handles presence from XMPP JID associated with this user.
/// \param presence Swift::Presence.
void handlePresence(Swift::Presence::ref presence);
@ -60,12 +63,20 @@ class User {
/// \return language
const char *getLang() { return "en"; }
boost::signal<void ()> onReadyToConnect;
private:
void onConnectingTimeout();
Swift::JID m_jid;
Component *m_component;
Swift::EntityCapsManager *m_entityCapsManager;
Swift::PresenceOracle *m_presenceOracle;
UserInfo m_userInfo;
void *m_data;
bool m_connected;
bool m_readyForConnect;
Swift::Timer::ref m_reconnectTimer;
};
}

View file

@ -68,6 +68,7 @@ class UserManager {
private:
void handlePresence(Swift::Presence::ref presence);
// void handleDiscoInfoResponse(boost::shared_ptr<Swift::DiscoInfo> info, Swift::ErrorPayload::ref error, const Swift::JID& jid);
void addUser(User *user);
long m_onlineBuddies;

View file

@ -8,9 +8,12 @@
#include "transport/logger.h"
#include "transport/sqlite3backend.h"
#include "transport/userregistration.h"
#include "transport/user.h"
#include "transport/storagebackend.h"
#include "spectrumeventloop.h"
#include "geventloop.h"
#define Log(X, STRING) std::cout << "[SPECTRUM] " << X << " " << STRING << "\n";
using namespace Transport;
@ -61,13 +64,39 @@ static PurpleCoreUiOps coreUiOps =
NULL
};
static void printDebug(PurpleDebugLevel level, const char *category, const char *arg_s) {
std::string c("[LIBPURPLE");
if (category) {
c.push_back('/');
c.append(category);
}
c.push_back(']');
std::cout << c << " " << arg_s;
}
/*
* Ops....
*/
static PurpleDebugUiOps debugUiOps =
{
printDebug,
NULL,
NULL,
NULL,
NULL,
NULL
};
static bool initPurple(Config &cfg) {
bool ret;
purple_util_set_user_dir("./");
// if (m_configuration.logAreas & LOG_AREA_PURPLE)
// purple_debug_set_ui_ops(&debugUiOps);
purple_debug_set_ui_ops(&debugUiOps);
purple_core_set_ui_ops(&coreUiOps);
purple_eventloop_set_ui_ops(getEventLoopUiOps());
@ -119,6 +148,118 @@ static bool initPurple(Config &cfg) {
return ret;
}
static void handleUserReadyToConnect(User *user) {
PurpleAccount *account = (PurpleAccount *) user->getData();
purple_account_set_enabled(account, "spectrum", TRUE);
const PurpleStatusType *status_type = purple_account_get_status_type_with_primitive(account, PURPLE_STATUS_AVAILABLE);
if (status_type != NULL) {
purple_account_set_status(account, purple_status_type_get_id(status_type), TRUE, NULL);
}
}
static void handleUserCreated(User *user, UserManager *userManager, Config *config) {
UserInfo userInfo = user->getUserInfo();
PurpleAccount *account = NULL;
const char *protocol = CONFIG_STRING(config, "service.protocol").c_str();
if (purple_accounts_find(userInfo.uin.c_str(), protocol) != NULL){
Log(userInfo.jid, "this account already exists");
account = purple_accounts_find(userInfo.uin.c_str(), protocol);
User *u = (User *) account->ui_data;
if (u && u != user) {
Log(userInfo.jid, "This account is already connected by another jid " << user->getJID());
return;
}
}
else {
Log(userInfo.jid, "creating new account");
account = purple_account_new(userInfo.uin.c_str(), protocol);
purple_accounts_add(account);
}
// Transport::instance()->collector()->stopCollecting(m_account);
// PurplePlugin *plugin = purple_find_prpl(protocol);
// PurplePluginProtocolInfo *prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(plugin);
// for (GList *l = prpl_info->protocol_options; l != NULL; l = l->next) {
// PurpleAccountOption *option = (PurpleAccountOption *) l->data;
// purple_account_remove_setting(account, purple_account_option_get_setting(option));
// }
//
// std::map <std::string, PurpleAccountSettingValue> &settings = Transport::instance()->getConfiguration().purple_account_settings;
// for (std::map <std::string, PurpleAccountSettingValue>::iterator it = settings.begin(); it != settings.end(); it++) {
// PurpleAccountSettingValue v = (*it).second;
// std::string key((*it).first);
// switch (v.type) {
// case PURPLE_PREF_BOOLEAN:
// purple_account_set_bool(m_account, key.c_str(), v.b);
// break;
//
// case PURPLE_PREF_INT:
// purple_account_set_int(m_account, key.c_str(), v.i);
// break;
//
// case PURPLE_PREF_STRING:
// if (v.str)
// purple_account_set_string(m_account, key.c_str(), v.str);
// else
// purple_account_remove_setting(m_account, key.c_str());
// break;
//
// case PURPLE_PREF_STRING_LIST:
// // TODO:
// break;
//
// default:
// continue;
// }
// }
purple_account_set_string(account, "encoding", userInfo.encoding.empty() ? CONFIG_STRING(config, "registration.encoding").c_str() : userInfo.encoding.c_str());
purple_account_set_bool(account, "use_clientlogin", false);
// purple_account_set_bool(account, "require_tls", Transport::instance()->getConfiguration().require_tls);
// purple_account_set_bool(account, "use_ssl", Transport::instance()->getConfiguration().require_tls);
purple_account_set_bool(account, "direct_connect", false);
// purple_account_set_bool(account, "check-mail", purple_value_get_boolean(getSetting("enable_notify_email")));
account->ui_data = user;
user->setData(account);
user->onReadyToConnect.connect(boost::bind(&handleUserReadyToConnect, user));
// Transport::instance()->protocol()->onPurpleAccountCreated(m_account);
// m_loadingBuddiesFromDB = true;
// loadRoster();
// m_loadingBuddiesFromDB = false;
// m_connectionStart = time(NULL);
// m_readyForConnect = false;
purple_account_set_password(account, userInfo.password.c_str());
// Log(m_jid, "UIN:" << m_username << " USER_ID:" << m_userID);
}
static void handleUserDestroyed(User *user, UserManager *userManager, Config *config) {
PurpleAccount *account = (PurpleAccount *) user->getData();
if (account) {
purple_account_set_enabled(account, "spectrum", FALSE);
// Remove conversations.
// This has to be called before m_account->ui_data = NULL;, because it uses
// ui_data to call SpectrumMessageHandler::purpleConversationDestroyed() callback.
GList *iter;
for (iter = purple_get_conversations(); iter; ) {
PurpleConversation *conv = (PurpleConversation*) iter->data;
iter = iter->next;
if (purple_conversation_get_account(conv) == account)
purple_conversation_destroy(conv);
}
account->ui_data = NULL;
// Transport::instance()->collector()->collect(m_account);
}
}
int main(int argc, char **argv) {
GError *error = NULL;
GOptionContext *context;
@ -183,7 +324,7 @@ int main(int argc, char **argv) {
#endif
Config config;
if (!config.load(argv[1])) {
std::cout << "Can't open sample.cfg configuration file.\n";
std::cout << "Can't open " << argv[1] << " configuration file.\n";
return 1;
}
@ -192,8 +333,22 @@ int main(int argc, char **argv) {
SpectrumEventLoop eventLoop;
Component transport(&eventLoop, &config);
Logger logger(&transport);
SQLite3Backend sql(&config);
logger.setStorageBackend(&sql);
if (!sql.connect()) {
std::cout << "Can't connect to database.\n";
}
UserManager userManager(&transport, &sql);
userManager.onUserCreated.connect(boost::bind(&handleUserCreated, _1, &userManager, &config));
userManager.onUserDestroyed.connect(boost::bind(&handleUserDestroyed, _1, &userManager, &config));
UserRegistration userRegistration(&transport, &userManager, &sql);
logger.setUserRegistration(&userRegistration);
logger.setUserManager(&userManager);
transport.connect();
eventLoop.run();
}

View file

@ -3,6 +3,7 @@ jid = icq.localhost
password = secret
server = 127.0.0.1
port = 8888
protocol=prpl-jabber
[database]
database = test.sql

View file

@ -52,7 +52,7 @@ Component::Component(Swift::EventLoop *loop, Config *config) {
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_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));
@ -169,11 +169,11 @@ void Component::handlePresence(Swift::Presence::ref presence) {
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();
}
// 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);
@ -223,35 +223,9 @@ void Component::handleSubscription(Swift::Presence::ref presence) {
// }
}
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();
// }
// }
// }
void Component::handleCapsChanged(const Swift::JID& jid) {
bool haveFeatures = m_entityCapsManager->getCaps(jid) != DiscoInfo::ref();
std::cout << "has capsInfo " << haveFeatures << "\n";
}
}

View file

@ -32,6 +32,11 @@ User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component) {
m_presenceOracle = component->m_presenceOracle;
m_entityCapsManager = component->m_entityCapsManager;
m_userInfo = userInfo;
m_connected = false;
m_readyForConnect = false;
m_reconnectTimer = m_component->getFactories()->getTimerFactory()->createTimer(10000);
m_reconnectTimer->onTick.connect(boost::bind(&User::onConnectingTimeout, this));
}
User::~User(){
@ -44,8 +49,31 @@ const Swift::JID &User::getJID() {
void User::handlePresence(Swift::Presence::ref presence) {
Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare());
if (!m_connected) {
// we are not connected to legacy network, so we should do it when disco#info arrive :)
if (m_readyForConnect == false) {
// Forward status message to legacy network, but only if it's sent from active resource
// if (m_activeResource == presence->getFrom().getResource().getUTF8String()) {
// forwardStatus(presenceShow, stanzaStatus);
// }
boost::shared_ptr<Swift::CapsInfo> capsInfo = presence->getPayload<Swift::CapsInfo>();
if (capsInfo && capsInfo->getHash() == "sha-1") {
if (m_entityCapsManager->getCaps(presence->getFrom()) != Swift::DiscoInfo::ref()) {
m_readyForConnect = true;
onReadyToConnect();
}
}
else {
m_reconnectTimer->start();
}
}
}
if (highest) {
highest->setTo(presence->getFrom());
highest->setTo(presence->getFrom().toBare());
highest->setFrom(m_component->getJID());
m_component->getComponent()->sendPresence(highest);
}
@ -58,4 +86,12 @@ void User::handlePresence(Swift::Presence::ref presence) {
}
}
void User::onConnectingTimeout() {
if (m_connected || m_readyForConnect)
return;
m_reconnectTimer->stop();
m_readyForConnect = true;
onReadyToConnect();
}
}

View file

@ -32,6 +32,7 @@ UserManager::UserManager(Component *component, StorageBackend *storageBackend) {
m_storageBackend = storageBackend;
component->onUserPresenceReceived.connect(bind(&UserManager::handlePresence, this, _1));
// component->onDiscoInfoResponse.connect(bind(&UserManager::handleDiscoInfoResponse, this, _1, _2, _3));
}
UserManager::~UserManager(){