Merge branch 'master' of https://github.com/hanzz/libtransport
This commit is contained in:
commit
b653edf477
31 changed files with 574 additions and 57 deletions
4
ChangeLog
Normal file
4
ChangeLog
Normal file
|
@ -0,0 +1,4 @@
|
|||
version 2.0.0 alpha (2011-12-06):
|
||||
General:
|
||||
* First Spectrum 2.0.0 alpha release, check more on
|
||||
http://spectrum.im/projects/spectrum/wiki/Spectrum_200_alpha
|
|
@ -171,7 +171,9 @@ class FrotzNetworkPlugin : public NetworkPlugin {
|
|||
|
||||
void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) {
|
||||
np->handleConnected(user);
|
||||
np->handleBuddyChanged(user, "zcode", "ZCode", "ZCode", pbnetwork::STATUS_ONLINE);
|
||||
std::vector<std::string> groups;
|
||||
groups.push_back("ZCode");
|
||||
np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE);
|
||||
// sleep(1);
|
||||
// np->handleMessage(np->m_user, "zork", first_msg);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class SpectrumNetworkPlugin;
|
|||
GKeyFile *keyfile;
|
||||
SpectrumNetworkPlugin *np;
|
||||
|
||||
std::string replaceAll(
|
||||
static std::string replaceAll(
|
||||
std::string result,
|
||||
const std::string& replaceWhat,
|
||||
const std::string& replaceWithWhat)
|
||||
|
@ -808,7 +808,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::string &groups) {
|
||||
void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector<std::string> &groups) {
|
||||
PurpleAccount *account = m_sessions[user];
|
||||
if (account) {
|
||||
if (m_authRequests.find(user + buddyName) != m_authRequests.end()) {
|
||||
|
@ -823,9 +823,10 @@ class SpectrumNetworkPlugin : public NetworkPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::string &groups) {
|
||||
void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector<std::string> &groups_) {
|
||||
PurpleAccount *account = m_sessions[user];
|
||||
if (account) {
|
||||
std::string groups = groups_.empty() ? "" : groups_[0];
|
||||
|
||||
if (m_authRequests.find(user + buddyName) != m_authRequests.end()) {
|
||||
m_authRequests[user + buddyName]->authorize_cb(m_authRequests[user + buddyName]->user_data);
|
||||
|
@ -1052,7 +1053,22 @@ static std::string getIconHash(PurpleBuddy *m_buddy) {
|
|||
|
||||
static std::vector<std::string> getGroups(PurpleBuddy *m_buddy) {
|
||||
std::vector<std::string> groups;
|
||||
groups.push_back((purple_buddy_get_group(m_buddy) && purple_group_get_name(purple_buddy_get_group(m_buddy))) ? std::string(purple_group_get_name(purple_buddy_get_group(m_buddy))) : std::string("Buddies"));
|
||||
if (purple_buddy_get_name(m_buddy)) {
|
||||
GSList *buddies = purple_find_buddies(purple_buddy_get_account(m_buddy), purple_buddy_get_name(m_buddy));
|
||||
while(buddies) {
|
||||
PurpleGroup *g = purple_buddy_get_group((PurpleBuddy *) buddies->data);
|
||||
buddies = g_slist_delete_link(buddies, buddies);
|
||||
|
||||
if(g && purple_group_get_name(g)) {
|
||||
groups.push_back(purple_group_get_name(g));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (groups.empty()) {
|
||||
groups.push_back("Buddies");
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
|
@ -1105,7 +1121,7 @@ static void buddyListNewNode(PurpleBlistNode *node) {
|
|||
}
|
||||
}
|
||||
|
||||
np->handleBuddyChanged(np->m_accounts[account], purple_buddy_get_name(buddy), getAlias(buddy), getGroups(buddy)[0], status, message, getIconHash(buddy),
|
||||
np->handleBuddyChanged(np->m_accounts[account], purple_buddy_get_name(buddy), getAlias(buddy), getGroups(buddy), status, message, getIconHash(buddy),
|
||||
blocked
|
||||
);
|
||||
}
|
||||
|
|
13
include/Swiften/Elements/SpectrumErrorPayload.cpp
Normal file
13
include/Swiften/Elements/SpectrumErrorPayload.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Jan Kaluza
|
||||
* Licensed under the Simplified BSD license.
|
||||
* See Documentation/Licenses/BSD-simplified.txt for more information.
|
||||
*/
|
||||
|
||||
#include <Swiften/Elements/SpectrumErrorPayload.h>
|
||||
|
||||
namespace Swift {
|
||||
|
||||
SpectrumErrorPayload::SpectrumErrorPayload(Error error) : error_(error) { }
|
||||
|
||||
}
|
50
include/Swiften/Elements/SpectrumErrorPayload.h
Normal file
50
include/Swiften/Elements/SpectrumErrorPayload.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Jan Kaluza
|
||||
* Licensed under the Simplified BSD license.
|
||||
* See Documentation/Licenses/BSD-simplified.txt for more information.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <string>
|
||||
#include <Swiften/Elements/Payload.h>
|
||||
|
||||
namespace Swift {
|
||||
class SpectrumErrorPayload : public Payload {
|
||||
public:
|
||||
enum Error {
|
||||
CONNECTION_ERROR_NETWORK_ERROR = 0,
|
||||
CONNECTION_ERROR_INVALID_USERNAME = 1,
|
||||
CONNECTION_ERROR_AUTHENTICATION_FAILED = 2,
|
||||
CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE = 3,
|
||||
CONNECTION_ERROR_NO_SSL_SUPPORT = 4,
|
||||
CONNECTION_ERROR_ENCRYPTION_ERROR = 5,
|
||||
CONNECTION_ERROR_NAME_IN_USE = 6,
|
||||
CONNECTION_ERROR_INVALID_SETTINGS = 7,
|
||||
CONNECTION_ERROR_CERT_NOT_PROVIDED = 8,
|
||||
CONNECTION_ERROR_CERT_UNTRUSTED = 9,
|
||||
CONNECTION_ERROR_CERT_EXPIRED = 10,
|
||||
CONNECTION_ERROR_CERT_NOT_ACTIVATED = 11,
|
||||
CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH = 12,
|
||||
CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH = 13,
|
||||
CONNECTION_ERROR_CERT_SELF_SIGNED = 14,
|
||||
CONNECTION_ERROR_CERT_OTHER_ERROR = 15,
|
||||
CONNECTION_ERROR_OTHER_ERROR = 16
|
||||
};
|
||||
|
||||
SpectrumErrorPayload(Error error = CONNECTION_ERROR_OTHER_ERROR);
|
||||
|
||||
Error getError() const {
|
||||
return error_;
|
||||
}
|
||||
|
||||
void setError(Error error) {
|
||||
error_ = error;
|
||||
}
|
||||
|
||||
private:
|
||||
Error error_;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Jan Kaluza
|
||||
* Licensed under the Simplified BSD license.
|
||||
* See Documentation/Licenses/BSD-simplified.txt for more information.
|
||||
*/
|
||||
|
||||
#include <Swiften/Serializer/PayloadSerializers/SpectrumErrorSerializer.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <Swiften/Base/foreach.h>
|
||||
#include <Swiften/Serializer/XML/XMLTextNode.h>
|
||||
#include <Swiften/Serializer/XML/XMLRawTextNode.h>
|
||||
#include <Swiften/Serializer/XML/XMLElement.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
namespace Swift {
|
||||
|
||||
SpectrumErrorSerializer::SpectrumErrorSerializer() : GenericPayloadSerializer<SpectrumErrorPayload>() {
|
||||
}
|
||||
|
||||
std::string SpectrumErrorSerializer::serializePayload(boost::shared_ptr<SpectrumErrorPayload> error) const {
|
||||
std::string data;
|
||||
switch (error->getError()) {
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_NETWORK_ERROR: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_INVALID_USERNAME: data = "CONNECTION_ERROR_INVALID_USERNAME"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_AUTHENTICATION_FAILED: data = "CONNECTION_ERROR_AUTHENTICATION_FAILED"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE: data = "CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_NO_SSL_SUPPORT: data = "CONNECTION_ERROR_NO_SSL_SUPPORT"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_ENCRYPTION_ERROR: data = "CONNECTION_ERROR_ENCRYPTION_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_NAME_IN_USE: data = "CONNECTION_ERROR_NAME_IN_USE"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_INVALID_SETTINGS: data = "CONNECTION_ERROR_INVALID_SETTINGS"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_NOT_PROVIDED: data = "CONNECTION_ERROR_CERT_NOT_PROVIDED"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_UNTRUSTED: data = "CONNECTION_ERROR_CERT_UNTRUSTED"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_EXPIRED: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_NOT_ACTIVATED: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_HOSTNAME_MISMATCH: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_FINGERPRINT_MISMATCH: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_SELF_SIGNED: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_CERT_OTHER_ERROR: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
case SpectrumErrorPayload::CONNECTION_ERROR_OTHER_ERROR: data = "CONNECTION_ERROR_NETWORK_ERROR"; break;
|
||||
}
|
||||
|
||||
XMLElement el("spectrumerror", "http://spectrum.im/error", data);
|
||||
|
||||
el.setAttribute("error", boost::lexical_cast<std::string>(error->getError()));
|
||||
|
||||
return el.serialize();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2011 Jan Kaluza
|
||||
* Licensed under the Simplified BSD license.
|
||||
* See Documentation/Licenses/BSD-simplified.txt for more information.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Swiften/Serializer/GenericPayloadSerializer.h>
|
||||
#include <Swiften/Elements/SpectrumErrorPayload.h>
|
||||
|
||||
namespace Swift {
|
||||
class SpectrumErrorSerializer : public GenericPayloadSerializer<SpectrumErrorPayload> {
|
||||
public:
|
||||
SpectrumErrorSerializer();
|
||||
|
||||
virtual std::string serializePayload(boost::shared_ptr<SpectrumErrorPayload>) const;
|
||||
};
|
||||
}
|
|
@ -82,6 +82,8 @@ class MySQLBackend : public StorageBackend
|
|||
/// \return true if user has been found in database and roster has been fetched
|
||||
bool getBuddies(long id, std::list<BuddyInfo> &roster);
|
||||
|
||||
bool getOnlineUsers(std::vector<std::string> &users);
|
||||
|
||||
long addBuddy(long userId, const BuddyInfo &buddyInfo);
|
||||
|
||||
void updateBuddy(long userId, const BuddyInfo &buddyInfo);
|
||||
|
@ -148,6 +150,7 @@ class MySQLBackend : public StorageBackend
|
|||
Statement *m_getBuddies;
|
||||
Statement *m_getBuddiesSettings;
|
||||
Statement *m_setUserOnline;
|
||||
Statement *m_getOnlineUsers;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ class NetworkPlugin {
|
|||
/// \param iconHash MD5 hash of buddy icon. Empty if none buddy icon.
|
||||
/// \param blocked True if this buddy is blocked in privacy lists in legacy network.
|
||||
void handleBuddyChanged(const std::string &user, const std::string &buddyName, const std::string &alias,
|
||||
const std::string &groups, pbnetwork::StatusType status, const std::string &statusMessage = "", const std::string &iconHash = "",
|
||||
const std::vector<std::string> &groups, pbnetwork::StatusType status, const std::string &statusMessage = "", const std::string &iconHash = "",
|
||||
bool blocked = false
|
||||
);
|
||||
|
||||
|
@ -197,8 +197,8 @@ class NetworkPlugin {
|
|||
virtual void handleJoinRoomRequest(const std::string &/*user*/, const std::string &/*room*/, const std::string &/*nickname*/, const std::string &/*pasword*/) {}
|
||||
virtual void handleLeaveRoomRequest(const std::string &/*user*/, const std::string &/*room*/) {}
|
||||
virtual void handleStatusChangeRequest(const std::string &/*user*/, int status, const std::string &statusMessage) {}
|
||||
virtual void handleBuddyUpdatedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*alias*/, const std::string &/*groups*/) {}
|
||||
virtual void handleBuddyRemovedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*groups*/) {}
|
||||
virtual void handleBuddyUpdatedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*alias*/, const std::vector<std::string> &/*groups*/) {}
|
||||
virtual void handleBuddyRemovedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::vector<std::string> &/*groups*/) {}
|
||||
virtual void handleBuddyBlockToggled(const std::string &/*user*/, const std::string &/*buddyName*/, bool /*blocked*/) {}
|
||||
|
||||
virtual void handleTypingRequest(const std::string &/*user*/, const std::string &/*buddyName*/) {}
|
||||
|
|
|
@ -55,6 +55,7 @@ class NetworkPluginServer {
|
|||
unsigned long shared;
|
||||
bool acceptUsers;
|
||||
bool longRun;
|
||||
bool willDie;
|
||||
};
|
||||
|
||||
NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager);
|
||||
|
|
|
@ -55,7 +55,7 @@ message Buddy {
|
|||
required string userName = 1;
|
||||
required string buddyName = 2;
|
||||
optional string alias = 3;
|
||||
optional string groups = 4;
|
||||
repeated string group = 4;
|
||||
optional StatusType status = 5;
|
||||
optional string statusMessage = 6;
|
||||
optional string iconHash = 7;
|
||||
|
|
|
@ -70,6 +70,8 @@ class SQLite3Backend : public StorageBackend
|
|||
/// \param online online state
|
||||
void setUserOnline(long id, bool online);
|
||||
|
||||
bool getOnlineUsers(std::vector<std::string> &users);
|
||||
|
||||
/// Removes user and all connected data from database.
|
||||
/// \param id id of user - UserInfo.id
|
||||
/// \return true if user has been found in database and removed
|
||||
|
@ -115,6 +117,7 @@ class SQLite3Backend : public StorageBackend
|
|||
sqlite3_stmt *m_getBuddies;
|
||||
sqlite3_stmt *m_getBuddiesSettings;
|
||||
sqlite3_stmt *m_setUserOnline;
|
||||
sqlite3_stmt *m_getOnlineUsers;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -108,6 +108,9 @@ class StorageBackend
|
|||
/// getBuddies
|
||||
virtual bool getBuddies(long id, std::list<BuddyInfo> &roster) = 0;
|
||||
|
||||
/// getOnlineUsers
|
||||
virtual bool getOnlineUsers(std::vector<std::string> &users) = 0;
|
||||
|
||||
virtual long addBuddy(long userId, const BuddyInfo &buddyInfo) = 0;
|
||||
virtual void updateBuddy(long userId, const BuddyInfo &buddyInfo) = 0;
|
||||
virtual void removeBuddy(long id) = 0;
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "Swiften/Disco/EntityCapsProvider.h"
|
||||
#include "storagebackend.h"
|
||||
#include <Swiften/FileTransfer/OutgoingFileTransfer.h>
|
||||
#include "Swiften/Elements/SpectrumErrorPayload.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
|
@ -93,7 +94,7 @@ class User : public Swift::EntityCapsProvider {
|
|||
/// \return language
|
||||
const char *getLang() { return "en"; }
|
||||
|
||||
void handleDisconnected(const std::string &error);
|
||||
void handleDisconnected(const std::string &error, Swift::SpectrumErrorPayload::Error e = Swift::SpectrumErrorPayload::CONNECTION_ERROR_OTHER_ERROR);
|
||||
|
||||
bool isReadyToConnect() {
|
||||
return m_readyForConnect;
|
||||
|
@ -136,6 +137,7 @@ class User : public Swift::EntityCapsProvider {
|
|||
std::map<Swift::JID, Swift::DiscoInfo::ref> m_legacyCaps;
|
||||
std::vector<boost::shared_ptr<Swift::OutgoingFileTransfer> > m_filetransfers;
|
||||
int m_resources;
|
||||
int m_reconnectCounter;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -78,9 +78,9 @@ class UserManager : public Swift::EntityCapsProvider {
|
|||
/// Removes user. This function disconnects user and safely removes
|
||||
/// User class. This does *not* remove user from StorageBackend.
|
||||
/// \param user User class to remove
|
||||
void removeUser(User *user);
|
||||
void removeUser(User *user, bool onUserBehalf = true);
|
||||
|
||||
void removeAllUsers();
|
||||
void removeAllUsers(bool onUserBehalf = true);
|
||||
|
||||
Swift::DiscoInfo::ref getCaps(const Swift::JID&) const;
|
||||
|
||||
|
|
56
include/transport/usersreconnecter.h
Normal file
56
include/transport/usersreconnecter.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "Swiften/Swiften.h"
|
||||
|
||||
namespace Transport {
|
||||
|
||||
class StorageBackend;
|
||||
class Component;
|
||||
|
||||
/// Tries to reconnect users who have been online before crash/restart.
|
||||
class UsersReconnecter {
|
||||
public:
|
||||
/// Creates new UsersReconnecter.
|
||||
/// \param component Transport instance associated with this roster.
|
||||
/// \param storageBackend StorageBackend from which the users will be fetched.
|
||||
UsersReconnecter(Component *component, StorageBackend *storageBackend);
|
||||
|
||||
/// Destructor.
|
||||
virtual ~UsersReconnecter();
|
||||
|
||||
void reconnectNextUser();
|
||||
|
||||
private:
|
||||
void handleConnected();
|
||||
|
||||
Component *m_component;
|
||||
StorageBackend *m_storageBackend;
|
||||
bool m_started;
|
||||
std::vector<std::string> m_users;
|
||||
Swift::Timer::ref m_nextUserTimer;
|
||||
};
|
||||
|
||||
}
|
|
@ -36,6 +36,10 @@ std::string encryptPassword(const std::string &password, const std::string &key)
|
|||
|
||||
std::string decryptPassword(std::string &encrypted, const std::string &key);
|
||||
|
||||
std::string serializeGroups(const std::vector<std::string> &groups);
|
||||
|
||||
std::vector<std::string> deserializeGroups(std::string &groups);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -115,12 +115,14 @@ void NetworkPlugin::handleSubject(const std::string &user, const std::string &le
|
|||
}
|
||||
|
||||
void NetworkPlugin::handleBuddyChanged(const std::string &user, const std::string &buddyName, const std::string &alias,
|
||||
const std::string &groups, pbnetwork::StatusType status, const std::string &statusMessage, const std::string &iconHash, bool blocked) {
|
||||
const std::vector<std::string> &groups, pbnetwork::StatusType status, const std::string &statusMessage, const std::string &iconHash, bool blocked) {
|
||||
pbnetwork::Buddy buddy;
|
||||
buddy.set_username(user);
|
||||
buddy.set_buddyname(buddyName);
|
||||
buddy.set_alias(alias);
|
||||
buddy.set_groups(groups);
|
||||
for (std::vector<std::string>::const_iterator it = groups.begin(); it != groups.end(); it++) {
|
||||
buddy.add_group(*it);
|
||||
}
|
||||
buddy.set_status((pbnetwork::StatusType) status);
|
||||
buddy.set_statusmessage(statusMessage);
|
||||
buddy.set_iconhash(iconHash);
|
||||
|
@ -424,7 +426,11 @@ void NetworkPlugin::handleBuddyChangedPayload(const std::string &data) {
|
|||
handleBuddyBlockToggled(payload.username(), payload.buddyname(), payload.blocked());
|
||||
}
|
||||
else {
|
||||
handleBuddyUpdatedRequest(payload.username(), payload.buddyname(), payload.alias(), payload.groups());
|
||||
std::vector<std::string> groups;
|
||||
for (int i = 0; i < payload.group_size(); i++) {
|
||||
groups.push_back(payload.group(i));
|
||||
}
|
||||
handleBuddyUpdatedRequest(payload.username(), payload.buddyname(), payload.alias(), groups);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -435,7 +441,12 @@ void NetworkPlugin::handleBuddyRemovedPayload(const std::string &data) {
|
|||
return;
|
||||
}
|
||||
|
||||
handleBuddyRemovedRequest(payload.username(), payload.buddyname(), payload.groups());
|
||||
std::vector<std::string> groups;
|
||||
for (int i = 0; i < payload.group_size(); i++) {
|
||||
groups.push_back(payload.group(i));
|
||||
}
|
||||
|
||||
handleBuddyRemovedRequest(payload.username(), payload.buddyname(), groups);
|
||||
}
|
||||
|
||||
void NetworkPlugin::handleChatStatePayload(const std::string &data, int type) {
|
||||
|
|
|
@ -6,7 +6,7 @@ ADD_EXECUTABLE(spectrum2 ${SRC})
|
|||
ADD_DEPENDENCIES(spectrum2 spectrum2_libpurple_backend)
|
||||
ADD_DEPENDENCIES(spectrum2 spectrum2_libircclient-qt_backend)
|
||||
|
||||
target_link_libraries(spectrum2 transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
|
||||
target_link_libraries(spectrum2 transport ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES})
|
||||
|
||||
INSTALL(TARGETS spectrum2 RUNTIME DESTINATION bin)
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "transport/networkpluginserver.h"
|
||||
#include "transport/admininterface.h"
|
||||
#include "transport/statsresponder.h"
|
||||
#include "transport/usersreconnecter.h"
|
||||
#include "transport/util.h"
|
||||
#include "Swiften/EventLoop/SimpleEventLoop.h"
|
||||
#include <boost/filesystem.hpp>
|
||||
|
@ -42,7 +43,7 @@ Component *component_ = NULL;
|
|||
UserManager *userManager_ = NULL;
|
||||
|
||||
static void stop_spectrum() {
|
||||
userManager_->removeAllUsers();
|
||||
userManager_->removeAllUsers(false);
|
||||
component_->stop();
|
||||
eventLoop_->stop();
|
||||
}
|
||||
|
@ -352,30 +353,48 @@ int main(int argc, char **argv)
|
|||
if (CONFIG_STRING(&config, "database.type") == "sqlite3") {
|
||||
storageBackend = new SQLite3Backend(&config);
|
||||
if (!storageBackend->connect()) {
|
||||
std::cerr << "Can't connect to database.\n";
|
||||
std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (CONFIG_STRING(&config, "database.type") == "sqlite3") {
|
||||
std::cerr << "Spectrum2 is not compiled with mysql backend.\n";
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_MYSQL
|
||||
if (CONFIG_STRING(&config, "database.type") == "mysql") {
|
||||
storageBackend = new MySQLBackend(&config);
|
||||
if (!storageBackend->connect()) {
|
||||
std::cerr << "Can't connect to database.\n";
|
||||
std::cerr << "Can't connect to database. Check the log to find out the reason.\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (CONFIG_STRING(&config, "database.type") == "mysql") {
|
||||
std::cerr << "Spectrum2 is not compiled with mysql backend.\n";
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3") {
|
||||
std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n";
|
||||
return -2;
|
||||
}
|
||||
|
||||
UserManager userManager(&transport, &userRegistry, storageBackend);
|
||||
userManager_ = &userManager;
|
||||
|
||||
UserRegistration *userRegistration = NULL;
|
||||
UsersReconnecter *usersReconnecter = NULL;
|
||||
if (storageBackend) {
|
||||
userRegistration = new UserRegistration(&transport, &userManager, storageBackend);
|
||||
userRegistration->start();
|
||||
// logger.setUserRegistration(&userRegistration);
|
||||
|
||||
usersReconnecter = new UsersReconnecter(&transport, storageBackend);
|
||||
}
|
||||
// logger.setUserManager(&userManager);
|
||||
|
||||
FileTransferManager ftManager(&transport, &userManager);
|
||||
|
||||
|
@ -393,6 +412,11 @@ int main(int argc, char **argv)
|
|||
userRegistration->stop();
|
||||
delete userRegistration;
|
||||
}
|
||||
|
||||
if (usersReconnecter) {
|
||||
delete usersReconnecter;
|
||||
}
|
||||
|
||||
delete storageBackend;
|
||||
delete factories;
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ 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=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend
|
||||
backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend
|
||||
#backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe
|
||||
#backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend
|
||||
backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend
|
||||
#backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend
|
||||
#protocol=prpl-msn
|
||||
protocol=any
|
||||
#protocol=prpl-icq
|
||||
|
|
|
@ -74,20 +74,20 @@ type = none
|
|||
|
||||
# For SQLite3: Full path to database
|
||||
# For MySQL: name of database
|
||||
# database = /var/lib/spectrum2/$jid/database.sql
|
||||
database = jabber_transport
|
||||
# default database = /var/lib/spectrum2/$jid/database.sql
|
||||
#database = jabber_transport
|
||||
|
||||
# Server.
|
||||
server = localhost
|
||||
#server = localhost
|
||||
|
||||
# Port.
|
||||
port = 0
|
||||
#port = 0
|
||||
|
||||
# User.
|
||||
user = spectrum
|
||||
#user = spectrum
|
||||
|
||||
# Paasword.
|
||||
password = secret
|
||||
#password = secret
|
||||
|
||||
# Prefix used for tables
|
||||
prefix = jabber_
|
||||
#prefix = jabber_
|
||||
|
|
|
@ -234,7 +234,8 @@ static void stop_all_instances(ManagerConfig *config) {
|
|||
}
|
||||
}
|
||||
|
||||
void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) {
|
||||
static int show_status(ManagerConfig *config) {
|
||||
int ret = 0;
|
||||
path p(CONFIG_STRING(config, "service.config_directory"));
|
||||
|
||||
try {
|
||||
|
@ -256,8 +257,65 @@ void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &netw
|
|||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
}
|
||||
|
||||
std::vector<std::string> vhosts;
|
||||
if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost"))
|
||||
vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost");
|
||||
vhosts.push_back(CONFIG_STRING(&cfg, "service.jid"));
|
||||
|
||||
BOOST_FOREACH(std::string &vhost, vhosts) {
|
||||
Config vhostCfg;
|
||||
if (vhostCfg.load(itr->path().string(), vhost) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile"));
|
||||
if (pid) {
|
||||
std::cout << itr->path() << ": " << vhost << " Running\n";
|
||||
}
|
||||
else {
|
||||
ret = 3;
|
||||
std::cout << itr->path() << ": " << vhost << " Stopped\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const filesystem_error& ex) {
|
||||
std::cerr << "boost filesystem error\n";
|
||||
exit(5);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ask_local_servers(ManagerConfig *config, Swift::BoostNetworkFactories &networkFactories, const std::string &message) {
|
||||
path p(CONFIG_STRING(config, "service.config_directory"));
|
||||
|
||||
try {
|
||||
if (!exists(p)) {
|
||||
std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n";
|
||||
exit(6);
|
||||
}
|
||||
|
||||
if (!is_directory(p)) {
|
||||
std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n";
|
||||
exit(7);
|
||||
}
|
||||
|
||||
directory_iterator end_itr;
|
||||
for (directory_iterator itr(p); itr != end_itr; ++itr) {
|
||||
if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") {
|
||||
Config cfg;
|
||||
if (cfg.load(itr->path().string()) == false) {
|
||||
std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n";
|
||||
}
|
||||
|
||||
if (CONFIG_STRING(&cfg, "service.admin_jid").empty() || CONFIG_STRING(&cfg, "service.admin_password").empty()) {
|
||||
std::cerr << itr->path().string() << ": service.admin_jid or service.admin_password empty. This server can't be queried over XMPP.\n";
|
||||
}
|
||||
|
||||
finished++;
|
||||
Swift::Client *client = new Swift::Client(CONFIG_STRING(&cfg, "service.admin_username"), CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories);
|
||||
Swift::Client *client = new Swift::Client(CONFIG_STRING(&cfg, "service.admin_jid"), CONFIG_STRING(&cfg, "service.admin_password"), &networkFactories);
|
||||
client->setAlwaysTrustCertificates();
|
||||
client->onConnected.connect(boost::bind(&handleConnected, client, CONFIG_STRING(&cfg, "service.jid")));
|
||||
client->onDisconnected.connect(bind(&handleDisconnected, client, _1, CONFIG_STRING(&cfg, "service.jid")));
|
||||
|
@ -285,6 +343,7 @@ int main(int argc, char **argv)
|
|||
boost::program_options::options_description desc("Usage: spectrum [OPTIONS] <COMMAND>\nCommands:\n"
|
||||
" start - start all local Spectrum2 instances\n"
|
||||
" stop - stop all local Spectrum2 instances\n"
|
||||
" status - status of local Spectrum2 instances\n"
|
||||
" <other> - send command to all local + remote Spectrum2 instances and print output\n"
|
||||
"Allowed options");
|
||||
desc.add_options()
|
||||
|
@ -333,6 +392,9 @@ int main(int argc, char **argv)
|
|||
else if (command == "stop") {
|
||||
stop_all_instances(&config);
|
||||
}
|
||||
else if (command == "status") {
|
||||
return show_status(&config);
|
||||
}
|
||||
else {
|
||||
Swift::SimpleEventLoop eventLoop;
|
||||
Swift::BoostNetworkFactories networkFactories(&eventLoop);
|
||||
|
|
|
@ -300,6 +300,7 @@ void MySQLBackend::disconnect() {
|
|||
delete m_updateUserSetting;
|
||||
delete m_updateBuddySetting;
|
||||
delete m_setUserOnline;
|
||||
delete m_getOnlineUsers;
|
||||
mysql_close(&m_conn);
|
||||
}
|
||||
|
||||
|
@ -320,7 +321,7 @@ bool MySQLBackend::connect() {
|
|||
|
||||
createDatabase();
|
||||
|
||||
m_setUser = new Statement(&m_conn, "sssssbs", "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, NOW(), ?) ON DUPLICATE KEY UPDATE password=?");
|
||||
m_setUser = new Statement(&m_conn, "sssssbss", "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, NOW(), ?) ON DUPLICATE KEY UPDATE uin=?, password=?");
|
||||
m_getUser = new Statement(&m_conn, "s|isssssb", "SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=?");
|
||||
|
||||
m_removeUser = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "users WHERE id=?");
|
||||
|
@ -339,6 +340,7 @@ bool MySQLBackend::connect() {
|
|||
m_updateUserSetting = new Statement(&m_conn, "sis", "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?");
|
||||
|
||||
m_setUserOnline = new Statement(&m_conn, "bi", "UPDATE " + m_prefix + "users SET online=?, last_login=NOW() WHERE id=?");
|
||||
m_getOnlineUsers = new Statement(&m_conn, "|s", "SELECT jid FROM " + m_prefix + "users WHERE online=1");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -414,7 +416,7 @@ void MySQLBackend::setUser(const UserInfo &user) {
|
|||
if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) {
|
||||
encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key"));
|
||||
}
|
||||
*m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.password;
|
||||
*m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted;
|
||||
EXEC(m_setUser, setUser(user));
|
||||
}
|
||||
|
||||
|
@ -442,10 +444,25 @@ void MySQLBackend::setUserOnline(long id, bool online) {
|
|||
EXEC(m_setUserOnline, setUserOnline(id, online));
|
||||
}
|
||||
|
||||
bool MySQLBackend::getOnlineUsers(std::vector<std::string> &users) {
|
||||
EXEC(m_getOnlineUsers, getOnlineUsers(users));
|
||||
if (!exec_ok)
|
||||
return false;
|
||||
|
||||
std::string jid;
|
||||
while (m_getOnlineUsers->fetch() == 0) {
|
||||
*m_getOnlineUsers >> jid;
|
||||
users.push_back(jid);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
|
||||
std::string groups = Util::serializeGroups(buddyInfo.groups);
|
||||
*m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription;
|
||||
*m_addBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]);
|
||||
*m_addBuddy << groups;
|
||||
*m_addBuddy << buddyInfo.alias << buddyInfo.flags;
|
||||
|
||||
EXEC(m_addBuddy, addBuddy(userId, buddyInfo));
|
||||
|
@ -463,7 +480,8 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
|||
|
||||
void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||
// "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?"
|
||||
*m_updateBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]);
|
||||
std::string groups = Util::serializeGroups(buddyInfo.groups);
|
||||
*m_updateBuddy << groups;
|
||||
*m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription;
|
||||
*m_updateBuddy << userId << buddyInfo.legacyName;
|
||||
|
||||
|
@ -491,8 +509,9 @@ bool MySQLBackend::getBuddies(long id, std::list<BuddyInfo> &roster) {
|
|||
std::string group;
|
||||
*m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags;
|
||||
|
||||
if (!group.empty())
|
||||
b.groups.push_back(group);
|
||||
if (!group.empty()) {
|
||||
b.groups = Util::deserializeGroups(group);
|
||||
}
|
||||
|
||||
roster.push_back(b);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "Swiften/Elements/AttentionPayload.h"
|
||||
#include "Swiften/Elements/XHTMLIMPayload.h"
|
||||
#include "Swiften/Elements/InvisiblePayload.h"
|
||||
#include "Swiften/Elements/SpectrumErrorPayload.h"
|
||||
#include "transport/protocol.pb.h"
|
||||
#include "log4cxx/logger.h"
|
||||
|
||||
|
@ -197,9 +198,11 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa
|
|||
}
|
||||
|
||||
// Change groups if it's not empty. The same as above...
|
||||
if (!payload.groups().empty()) {
|
||||
std::vector<std::string> groups;
|
||||
groups.push_back(payload.groups());
|
||||
std::vector<std::string> groups;
|
||||
for (int i = 0; i < payload.group_size(); i++) {
|
||||
groups.push_back(payload.group(i));
|
||||
}
|
||||
if (!groups.empty()) {
|
||||
buddy->setGroups(groups);
|
||||
}
|
||||
|
||||
|
@ -285,6 +288,7 @@ void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr<Swift::Con
|
|||
client->res = 0;
|
||||
client->init_res = 0;
|
||||
client->shared = 0;
|
||||
client->willDie = 0;
|
||||
// Backend does not accept new clients automatically if it's long-running
|
||||
client->acceptUsers = !m_isNextLongRun;
|
||||
client->longRun = m_isNextLongRun;
|
||||
|
@ -333,6 +337,9 @@ void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr<Swift::Con
|
|||
void NetworkPluginServer::handleSessionFinished(Backend *c) {
|
||||
LOG4CXX_INFO(logger, "Backend " << c << " disconnected. Current backend count=" << (m_clients.size() - 1));
|
||||
|
||||
// This backend will do, so we can't reconnect users to it in User::handleDisconnected call
|
||||
c->willDie = true;
|
||||
|
||||
// If there are users associated with this backend, it must have crashed, so print error output
|
||||
// and disconnect users
|
||||
for (std::list<User *>::const_iterator it = c->users.begin(); it != c->users.end(); it++) {
|
||||
|
@ -387,7 +394,7 @@ void NetworkPluginServer::handleDisconnectedPayload(const std::string &data) {
|
|||
if (!user) {
|
||||
return;
|
||||
}
|
||||
user->handleDisconnected(payload.message());
|
||||
user->handleDisconnected(payload.message(), (Swift::SpectrumErrorPayload::Error) payload.error());
|
||||
}
|
||||
|
||||
void NetworkPluginServer::handleVCardPayload(const std::string &data) {
|
||||
|
@ -932,7 +939,7 @@ void NetworkPluginServer::handleUserCreated(User *user) {
|
|||
user->setData(c);
|
||||
c->users.push_back(user);
|
||||
|
||||
// UserInfo userInfo = user->getUserInfo();
|
||||
// Don't forget to disconnect these in handleUserDestroyed!!!
|
||||
user->onReadyToConnect.connect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user));
|
||||
user->onPresenceChanged.connect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1));
|
||||
user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4));
|
||||
|
@ -1051,6 +1058,11 @@ void NetworkPluginServer::handleUserDestroyed(User *user) {
|
|||
m_waitingUsers.remove(user);
|
||||
UserInfo userInfo = user->getUserInfo();
|
||||
|
||||
user->onReadyToConnect.disconnect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user));
|
||||
user->onPresenceChanged.disconnect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1));
|
||||
user->onRoomJoined.disconnect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4));
|
||||
user->onRoomLeft.disconnect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1));
|
||||
|
||||
pbnetwork::Logout logout;
|
||||
logout.set_user(user->getJID().toBare());
|
||||
logout.set_legacyname(userInfo.uin);
|
||||
|
@ -1162,7 +1174,9 @@ void NetworkPluginServer::handleBuddyRemoved(Buddy *b) {
|
|||
buddy.set_username(user->getJID().toBare());
|
||||
buddy.set_buddyname(b->getName());
|
||||
buddy.set_alias(b->getAlias());
|
||||
buddy.set_groups(b->getGroups().size() == 0 ? "" : b->getGroups()[0]);
|
||||
BOOST_FOREACH(const std::string &g, b->getGroups()) {
|
||||
buddy.add_group(g);
|
||||
}
|
||||
buddy.set_status(pbnetwork::STATUS_NONE);
|
||||
|
||||
std::string message;
|
||||
|
@ -1188,7 +1202,9 @@ void NetworkPluginServer::handleBuddyUpdated(Buddy *b, const Swift::RosterItemPa
|
|||
buddy.set_username(user->getJID().toBare());
|
||||
buddy.set_buddyname(b->getName());
|
||||
buddy.set_alias(b->getAlias());
|
||||
buddy.set_groups(b->getGroups().size() == 0 ? "" : b->getGroups()[0]);
|
||||
BOOST_FOREACH(const std::string &g, b->getGroups()) {
|
||||
buddy.add_group(g);
|
||||
}
|
||||
buddy.set_status(pbnetwork::STATUS_NONE);
|
||||
|
||||
std::string message;
|
||||
|
@ -1214,7 +1230,9 @@ void NetworkPluginServer::handleBlockToggled(Buddy *b) {
|
|||
buddy.set_username(user->getJID().toBare());
|
||||
buddy.set_buddyname(b->getName());
|
||||
buddy.set_alias(b->getAlias());
|
||||
buddy.set_groups(b->getGroups().size() == 0 ? "" : b->getGroups()[0]);
|
||||
BOOST_FOREACH(const std::string &g, b->getGroups()) {
|
||||
buddy.add_group(g);
|
||||
}
|
||||
buddy.set_status(pbnetwork::STATUS_NONE);
|
||||
buddy.set_blocked(!b->isBlocked());
|
||||
|
||||
|
@ -1343,7 +1361,7 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUser
|
|||
|
||||
// Check all backends and find free one
|
||||
for (std::list<Backend *>::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) {
|
||||
if ((*it)->acceptUsers == acceptUsers && (*it)->users.size() < CONFIG_INT(m_config, "service.users_per_backend") && (*it)->connection && (*it)->longRun == longRun) {
|
||||
if ((*it)->willDie == false && (*it)->acceptUsers == acceptUsers && (*it)->users.size() < CONFIG_INT(m_config, "service.users_per_backend") && (*it)->connection && (*it)->longRun == longRun) {
|
||||
c = *it;
|
||||
// if we're not reusing all backends and backend is full, stop accepting new users on this backend
|
||||
if (!CONFIG_BOOL(m_config, "service.reuse_old_backends")) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifdef WITH_SQLITE
|
||||
|
||||
#include "transport/sqlite3backend.h"
|
||||
#include "transport/util.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include "log4cxx/logger.h"
|
||||
|
||||
|
@ -98,6 +99,7 @@ SQLite3Backend::~SQLite3Backend(){
|
|||
FINALIZE_STMT(m_updateUserSetting);
|
||||
FINALIZE_STMT(m_updateBuddySetting);
|
||||
FINALIZE_STMT(m_setUserOnline);
|
||||
FINALIZE_STMT(m_getOnlineUsers);
|
||||
sqlite3_close(m_db);
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +133,7 @@ bool SQLite3Backend::connect() {
|
|||
PREP_STMT(m_updateUserSetting, "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?");
|
||||
|
||||
PREP_STMT(m_setUserOnline, "UPDATE " + m_prefix + "users SET online=?, last_login=DATETIME('NOW') WHERE id=?");
|
||||
PREP_STMT(m_getOnlineUsers, "SELECT jid FROM " + m_prefix + "users WHERE online=1");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -248,13 +251,30 @@ void SQLite3Backend::setUserOnline(long id, bool online) {
|
|||
EXECUTE_STATEMENT(m_setUserOnline, "setUserOnline query");
|
||||
}
|
||||
|
||||
bool SQLite3Backend::getOnlineUsers(std::vector<std::string> &users) {
|
||||
sqlite3_reset(m_getOnlineUsers);
|
||||
|
||||
int ret;
|
||||
while((ret = sqlite3_step(m_getOnlineUsers)) == SQLITE_ROW) {
|
||||
std::string jid = (const char *) sqlite3_column_text(m_getOnlineUsers, 0);
|
||||
users.push_back(jid);
|
||||
}
|
||||
|
||||
if (ret != SQLITE_DONE) {
|
||||
LOG4CXX_ERROR(logger, "getOnlineUsers query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||
// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)"
|
||||
BEGIN(m_addBuddy);
|
||||
BIND_INT(m_addBuddy, userId);
|
||||
BIND_STR(m_addBuddy, buddyInfo.legacyName);
|
||||
BIND_STR(m_addBuddy, buddyInfo.subscription);
|
||||
BIND_STR(m_addBuddy, buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); // TODO: serialize groups
|
||||
BIND_STR(m_addBuddy, Util::serializeGroups(buddyInfo.groups));
|
||||
BIND_STR(m_addBuddy, buddyInfo.alias);
|
||||
BIND_INT(m_addBuddy, buddyInfo.flags);
|
||||
|
||||
|
@ -280,7 +300,7 @@ long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) {
|
|||
void SQLite3Backend::updateBuddy(long userId, const BuddyInfo &buddyInfo) {
|
||||
// UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?
|
||||
BEGIN(m_updateBuddy);
|
||||
BIND_STR(m_updateBuddy, buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); // TODO: serialize groups
|
||||
BIND_STR(m_updateBuddy, Util::serializeGroups(buddyInfo.groups));
|
||||
BIND_STR(m_updateBuddy, buddyInfo.alias);
|
||||
BIND_INT(m_updateBuddy, buddyInfo.flags);
|
||||
BIND_STR(m_updateBuddy, buddyInfo.subscription);
|
||||
|
@ -321,7 +341,8 @@ bool SQLite3Backend::getBuddies(long id, std::list<BuddyInfo> &roster) {
|
|||
b.legacyName = GET_STR(m_getBuddies);
|
||||
b.subscription = GET_STR(m_getBuddies);
|
||||
b.alias = GET_STR(m_getBuddies);
|
||||
b.groups.push_back(GET_STR(m_getBuddies));
|
||||
std::string groups = GET_STR(m_getBuddies);
|
||||
b.groups = Util::deserializeGroups(groups);
|
||||
b.flags = GET_INT(m_getBuddies);
|
||||
|
||||
if (buddy_id == b.id) {
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "Swiften/Serializer/PayloadSerializers/XHTMLIMSerializer.h"
|
||||
#include "Swiften/Parser/PayloadParsers/StatsParser.h"
|
||||
#include "Swiften/Serializer/PayloadSerializers/StatsSerializer.h"
|
||||
#include "Swiften/Serializer/PayloadSerializers/SpectrumErrorSerializer.h"
|
||||
#include "transport/BlockParser.h"
|
||||
#include "transport/BlockSerializer.h"
|
||||
#include "Swiften/Parser/PayloadParsers/InvisibleParser.h"
|
||||
|
@ -99,6 +100,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
|
|||
m_server->addPayloadSerializer(new Transport::BlockSerializer());
|
||||
m_server->addPayloadSerializer(new Swift::InvisibleSerializer());
|
||||
m_server->addPayloadSerializer(new Swift::StatsSerializer());
|
||||
m_server->addPayloadSerializer(new Swift::SpectrumErrorSerializer());
|
||||
|
||||
m_server->onDataRead.connect(boost::bind(&Component::handleDataRead, this, _1));
|
||||
m_server->onDataWritten.connect(boost::bind(&Component::handleDataWritten, this, _1));
|
||||
|
@ -124,6 +126,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories,
|
|||
m_component->addPayloadSerializer(new Transport::BlockSerializer());
|
||||
m_component->addPayloadSerializer(new Swift::InvisibleSerializer());
|
||||
m_component->addPayloadSerializer(new Swift::StatsSerializer());
|
||||
m_component->addPayloadSerializer(new Swift::SpectrumErrorSerializer());
|
||||
|
||||
m_stanzaChannel = m_component->getStanzaChannel();
|
||||
m_iqRouter = m_component->getIQRouter();
|
||||
|
@ -194,6 +197,8 @@ void Component::start() {
|
|||
else if (m_server) {
|
||||
LOG4CXX_INFO(logger, "Starting component in server mode on port " << CONFIG_INT(m_config, "service.port"));
|
||||
m_server->start();
|
||||
// We're connected right here, because we're in server mode...
|
||||
handleConnected();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
18
src/user.cpp
18
src/user.cpp
|
@ -28,6 +28,7 @@
|
|||
#include "Swiften/Server/ServerStanzaChannel.h"
|
||||
#include "Swiften/Elements/StreamError.h"
|
||||
#include "Swiften/Elements/MUCPayload.h"
|
||||
#include "Swiften/Elements/SpectrumErrorPayload.h"
|
||||
#include "log4cxx/logger.h"
|
||||
#include <boost/foreach.hpp>
|
||||
#include <stdio.h>
|
||||
|
@ -55,6 +56,7 @@ User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, User
|
|||
m_readyForConnect = false;
|
||||
m_ignoreDisconnect = false;
|
||||
m_resources = 0;
|
||||
m_reconnectCounter = 0;
|
||||
|
||||
m_reconnectTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(10000);
|
||||
m_reconnectTimer->onTick.connect(boost::bind(&User::onConnectingTimeout, this));
|
||||
|
@ -169,6 +171,7 @@ void User::sendCurrentPresence() {
|
|||
|
||||
void User::setConnected(bool connected) {
|
||||
m_connected = connected;
|
||||
m_reconnectCounter = 0;
|
||||
setIgnoreDisconnect(false);
|
||||
updateLastActivity();
|
||||
|
||||
|
@ -315,12 +318,24 @@ void User::setIgnoreDisconnect(bool ignoreDisconnect) {
|
|||
LOG4CXX_INFO(logger, m_jid.toString() << ": Setting ignoreDisconnect=" << m_ignoreDisconnect);
|
||||
}
|
||||
|
||||
void User::handleDisconnected(const std::string &error) {
|
||||
void User::handleDisconnected(const std::string &error, Swift::SpectrumErrorPayload::Error e) {
|
||||
if (m_ignoreDisconnect) {
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnecting from legacy network ignored (probably moving between backends)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (e == Swift::SpectrumErrorPayload::CONNECTION_ERROR_OTHER_ERROR || e == Swift::SpectrumErrorPayload::CONNECTION_ERROR_NETWORK_ERROR) {
|
||||
if (m_reconnectCounter < 3) {
|
||||
m_reconnectCounter++;
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnecting from legacy network for, trying to reconnect automatically.");
|
||||
// Simulate destruction/resurrection :)
|
||||
// TODO: If this stops working, create onReconnect signal
|
||||
m_userManager->onUserDestroyed(this);
|
||||
m_userManager->onUserCreated(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (error.empty()) {
|
||||
LOG4CXX_INFO(logger, m_jid.toString() << ": Disconnected from legacy network");
|
||||
}
|
||||
|
@ -333,6 +348,7 @@ void User::handleDisconnected(const std::string &error) {
|
|||
msg->setBody(error);
|
||||
msg->setTo(m_jid.toBare());
|
||||
msg->setFrom(m_component->getJID());
|
||||
msg->addPayload(boost::make_shared<Swift::SpectrumErrorPayload>(e));
|
||||
m_component->getStanzaChannel()->sendMessage(msg);
|
||||
|
||||
// In server mode, server finishes the session and pass unavailable session to userManager if we're connected to legacy network,
|
||||
|
|
|
@ -101,7 +101,7 @@ Swift::DiscoInfo::ref UserManager::getCaps(const Swift::JID &jid) const {
|
|||
return user->getCaps(jid);
|
||||
}
|
||||
|
||||
void UserManager::removeUser(User *user) {
|
||||
void UserManager::removeUser(User *user, bool onUserBehalf) {
|
||||
m_users.erase(user->getJID().toBare().toString());
|
||||
if (m_cachedUser == user)
|
||||
m_cachedUser = NULL;
|
||||
|
@ -110,7 +110,7 @@ void UserManager::removeUser(User *user) {
|
|||
disconnectUser(user->getJID());
|
||||
}
|
||||
|
||||
if (m_storageBackend) {
|
||||
if (m_storageBackend && onUserBehalf) {
|
||||
m_storageBackend->setUserOnline(user->getUserInfo().id, false);
|
||||
}
|
||||
|
||||
|
@ -122,9 +122,9 @@ void UserManager::removeUser(User *user) {
|
|||
// VALGRIND_DO_LEAK_CHECK;
|
||||
}
|
||||
|
||||
void UserManager::removeAllUsers() {
|
||||
void UserManager::removeAllUsers(bool onUserBehalf) {
|
||||
while(m_users.begin() != m_users.end()) {
|
||||
removeUser((*m_users.begin()).second);
|
||||
removeUser((*m_users.begin()).second, onUserBehalf);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
89
src/usersreconnecter.cpp
Normal file
89
src/usersreconnecter.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* XMPP - libpurple transport
|
||||
*
|
||||
* Copyright (C) 2009, Jan Kaluza <hanzz@soc.pidgin.im>
|
||||
*
|
||||
* 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/usersreconnecter.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include "Swiften/Queries/IQRouter.h"
|
||||
#include "Swiften/Swiften.h"
|
||||
#include "transport/storagebackend.h"
|
||||
#include "transport/transport.h"
|
||||
#include "log4cxx/logger.h"
|
||||
|
||||
using namespace log4cxx;
|
||||
|
||||
using namespace Swift;
|
||||
using namespace boost;
|
||||
|
||||
namespace Transport {
|
||||
|
||||
static LoggerPtr logger = Logger::getLogger("UserReconnecter");
|
||||
|
||||
UsersReconnecter::UsersReconnecter(Component *component, StorageBackend *storageBackend) {
|
||||
m_component = component;
|
||||
m_storageBackend = storageBackend;
|
||||
m_started = false;
|
||||
|
||||
m_nextUserTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(1000);
|
||||
m_nextUserTimer->onTick.connect(boost::bind(&UsersReconnecter::reconnectNextUser, this));
|
||||
|
||||
m_component->onConnected.connect(bind(&UsersReconnecter::handleConnected, this));
|
||||
}
|
||||
|
||||
UsersReconnecter::~UsersReconnecter() {
|
||||
m_component->onConnected.disconnect(bind(&UsersReconnecter::handleConnected, this));
|
||||
m_nextUserTimer->stop();
|
||||
m_nextUserTimer->onTick.disconnect(boost::bind(&UsersReconnecter::reconnectNextUser, this));
|
||||
}
|
||||
|
||||
void UsersReconnecter::reconnectNextUser() {
|
||||
if (m_users.empty()) {
|
||||
LOG4CXX_INFO(logger, "All users reconnected, stopping UserReconnecter.");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string user = m_users.back();
|
||||
m_users.pop_back();
|
||||
|
||||
LOG4CXX_INFO(logger, "Sending probe presence to " << user);
|
||||
Swift::Presence::ref response = Swift::Presence::create();
|
||||
response->setTo(user);
|
||||
response->setFrom(m_component->getJID());
|
||||
response->setType(Swift::Presence::Probe);
|
||||
|
||||
m_component->getStanzaChannel()->sendPresence(response);
|
||||
m_nextUserTimer->start();
|
||||
}
|
||||
|
||||
void UsersReconnecter::handleConnected() {
|
||||
if (m_started)
|
||||
return;
|
||||
|
||||
LOG4CXX_INFO(logger, "Starting UserReconnecter.");
|
||||
m_started = true;
|
||||
|
||||
m_storageBackend->getOnlineUsers(m_users);
|
||||
|
||||
reconnectNextUser();
|
||||
}
|
||||
|
||||
|
||||
}
|
25
src/util.cpp
25
src/util.cpp
|
@ -24,6 +24,7 @@
|
|||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
using namespace boost::filesystem;
|
||||
|
||||
|
@ -103,6 +104,30 @@ std::string decryptPassword(std::string &encrypted, const std::string &key) {
|
|||
return password;
|
||||
}
|
||||
|
||||
std::string serializeGroups(const std::vector<std::string> &groups) {
|
||||
std::string ret;
|
||||
BOOST_FOREACH(const std::string &group, groups) {
|
||||
ret += group + "\n";
|
||||
}
|
||||
if (!ret.empty()) {
|
||||
ret.erase(ret.end() - 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> deserializeGroups(std::string &groups) {
|
||||
std::vector<std::string> ret;
|
||||
if (groups.empty()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
boost::split(ret, groups, boost::is_any_of("\n"));
|
||||
if (ret.back().empty()) {
|
||||
ret.erase(ret.end() - 1);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue