Changeset - ddee629fe419
[Not reviewed]
0 3 0
Jan Kaluza - 10 years ago 2016-02-04 08:09:37
jkaluza@redhat.com
Libtransport: Fix crash in avatar handling code when storage backend is not set. Add extended_test for avatars using libpurple backend
3 files changed with 10 insertions and 3 deletions:
0 comments (0 inline, 0 general)
libtransport/User.cpp
Show inline comments
 
/**
 
 * 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/User.h"
 
#include "transport/Frontend.h"
 
#include "transport/Transport.h"
 
#include "transport/RosterManager.h"
 
#include "transport/UserManager.h"
 
#include "transport/Conversation.h"
 
#include "transport/Factory.h"
 
#include "transport/ConversationManager.h"
 
#include "transport/PresenceOracle.h"
 
#include "transport/Logging.h"
 
#include "transport/StorageBackend.h"
 
#include "transport/Buddy.h"
 
#include "Swiften/Server/ServerStanzaChannel.h"
 
#include "Swiften/Elements/MUCPayload.h"
 
#include "Swiften/Elements/SpectrumErrorPayload.h"
 
#include "Swiften/Elements/CapsInfo.h"
 
#include "Swiften/Elements/VCardUpdate.h"
 
#include <boost/foreach.hpp>
 
#include <stdio.h>
 
#include <stdlib.h>
 

	
 
using namespace boost;
 

	
 
#define foreach         BOOST_FOREACH
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "User");
 

	
 
User::User(const Swift::JID &jid, UserInfo &userInfo, Component *component, UserManager *userManager) {
 
	m_jid = jid.toBare();
 
	m_data = NULL;
 

	
 
	m_cacheMessages = false;
 
	m_component = component;
 
	m_presenceOracle = component->m_presenceOracle;
 
	m_userManager = userManager;
 
	m_userInfo = userInfo;
 
	m_connected = false;
 
	m_readyForConnect = false;
 
	m_ignoreDisconnect = false;
 
	m_resources = 0;
 
	m_reconnectCounter = 0;
 
	m_reconnectLimit = 3;
 
	m_storageBackend = NULL;
 

	
 
	m_reconnectTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(5000);
 
	m_reconnectTimer->onTick.connect(boost::bind(&User::onConnectingTimeout, this)); 
 

	
 
	m_rosterManager = component->getFrontend()->createRosterManager(this, m_component);
 
	m_conversationManager = new ConversationManager(this, m_component);
 

	
 
	LOG4CXX_INFO(logger, m_jid.toString() << ": Created");
 
	updateLastActivity();
 
}
 

	
 
User::~User(){
 
	LOG4CXX_INFO(logger, m_jid.toString() << ": Destroying");
 
// 	if (m_component->inServerMode()) {
 
// #if HAVE_SWIFTEN_3
 
// 		dynamic_cast<Swift::ServerStanzaChannel *>(m_component->getFrontend())->finishSession(m_jid, boost::shared_ptr<Swift::ToplevelElement>());
 
// #else
 
// 		dynamic_cast<Swift::ServerStanzaChannel *>(m_component->getFrontend())->finishSession(m_jid, boost::shared_ptr<Swift::Element>());
 
// #endif
 
// 	}
 

	
 

	
 
	m_reconnectTimer->stop();
 
	delete m_rosterManager;
 
	delete m_conversationManager;
 
}
 

	
 
const Swift::JID &User::getJID() {
 
	return m_jid;
 
}
 

	
 
void User::sendCurrentPresence() {
 
	if (m_component->inServerMode()) {
 
		return;
 
	}
 

	
 
	std::vector<Swift::Presence::ref> presences = m_presenceOracle->getAllPresence(m_jid);
 
	foreach(Swift::Presence::ref presence, presences) {
 
		if (presence->getType() == Swift::Presence::Unavailable) {
 
			continue;
 
		}
 

	
 
		if (m_connected) {
 
			Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare());
 
			if (highest) {
 
				Swift::Presence::ref response = Swift::Presence::create(highest);
 
				response->setTo(presence->getFrom());
 
				response->setFrom(m_component->getJID());
 
				m_component->getFrontend()->sendPresence(response);
 
			}
 
			else {
 
				Swift::Presence::ref response = Swift::Presence::create();
 
				response->setTo(presence->getFrom());
 
				response->setFrom(m_component->getJID());
 
				response->setType(Swift::Presence::Unavailable);
 
				m_component->getFrontend()->sendPresence(response);
 
			}
 
		}
 
		else {
 
			Swift::Presence::ref response = Swift::Presence::create();
 
			response->setTo(presence->getFrom());
 
			response->setFrom(m_component->getJID());
 
			response->setType(Swift::Presence::Unavailable);
 
			response->setStatus("Connecting");
 
			m_component->getFrontend()->sendPresence(response);
 
		}
 
	}
 
}
 

	
 
void User::setConnected(bool connected) {
 
	m_connected = connected;
 
	m_reconnectCounter = 0;
 
	setIgnoreDisconnect(false);
 
	updateLastActivity();
 

	
 
	sendCurrentPresence();
 

	
 
	if (m_connected) {
 
		BOOST_FOREACH(Swift::Presence::ref &presence, m_joinedRooms) {
 
			handlePresence(presence, true);
 
		}
 
	}
 
}
 

	
 
void User::setCacheMessages(bool cacheMessages) {
 
	if (m_component->inServerMode() && !m_cacheMessages && cacheMessages) {
 
		m_conversationManager->sendCachedChatMessages();
 
	}
 
	m_cacheMessages = cacheMessages;
 
}
 

	
 
void User::leaveRoom(const std::string &room) {
 
	onRoomLeft(room);
 

	
 
	BOOST_FOREACH(Swift::Presence::ref &p, m_joinedRooms) {
 
		if (Buddy::JIDToLegacyName(p->getTo()) == room) {
 
			m_joinedRooms.remove(p);
 
			break;
 
		}
 
	}
 

	
 
	Conversation *conv = m_conversationManager->getConversation(room);
 
	if (conv) {
 
		m_conversationManager->removeConversation(conv);
 
		delete conv;
 
	}
 
}
 

	
 
void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) {
 
	LOG4CXX_INFO(logger, "PRESENCE " << presence->getFrom().toString() << " " << presence->getTo().toString());
 

	
 
	if (m_storageBackend) {
 
	boost::shared_ptr<Swift::VCardUpdate> vcardUpdate = presence->getPayload<Swift::VCardUpdate>();
 
	if (vcardUpdate) {
 
		std::string value = "";
 
		int type = (int) TYPE_STRING;
 
		if (m_storageBackend) {
 
			m_storageBackend->getUserSetting(m_userInfo.id, "photohash", type, value);
 
		}
 
		if (value != vcardUpdate->getPhotoHash()) {
 
			LOG4CXX_INFO(logger, m_jid.toString() << ": Requesting VCard")
 
			if (m_storageBackend) {
 
				m_storageBackend->updateUserSetting(m_userInfo.id, "photohash", vcardUpdate->getPhotoHash());
 
				requestVCard();
 
			}
 
			requestVCard();
 
		}
 
	}
 

	
 
	if (!m_connected) {
 
		// we are not connected to legacy network, so we should do it when disco#info arrive :)
 
		if (m_readyForConnect == false) {
 
			boost::shared_ptr<Swift::CapsInfo> capsInfo = presence->getPayload<Swift::CapsInfo>();
 
			if (capsInfo && capsInfo->getHash() == "sha-1") {
 
				if (m_component->getFrontend()->sendCapabilitiesRequest(presence->getFrom()) != Swift::DiscoInfo::ref()) {
 
					LOG4CXX_INFO(logger, m_jid.toString() << ": Ready to be connected to legacy network");
 
					m_readyForConnect = true;
 
					onReadyToConnect();
 
				}
 
				else {
 
					m_reconnectTimer->start();
 
				}
 
			}
 
			else if (m_component->inServerMode()) {
 
				LOG4CXX_INFO(logger, m_jid.toString() << ": Ready to be connected to legacy network");
 
				m_readyForConnect = true;
 
				onReadyToConnect();
 
			}
 
			else {
 
				m_reconnectTimer->start();
 
			}
 
		}
 
	}
 

	
 
	if (!presence->getTo().getNode().empty()) {
 
		bool isMUC = presence->getPayload<Swift::MUCPayload>() != NULL || *presence->getTo().getNode().c_str() == '#';
 
		if (presence->getType() == Swift::Presence::Unavailable) {
 
			std::string room = Buddy::JIDToLegacyName(presence->getTo());
 
			Conversation *conv = m_conversationManager->getConversation(room);
 
			if (conv) {
 
				conv->removeJID(presence->getFrom());
 
				if (!conv->getJIDs().empty()) {
 
					return;
 
				}
 
			}
 
			else {
 
				return;
 
			}
 

	
 
			if (getUserSetting("stay_connected") != "1") {
 
				LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room);
 
				onRawPresenceReceived(presence);
 
				leaveRoom(room);
 
			}
 

	
 
			return;
 
		}
 
		else if (isMUC) {
 
			// force connection to legacy network to let backend to handle auto-join on connect.
 
			if (!m_readyForConnect) {
 
				LOG4CXX_INFO(logger, m_jid.toString() << ": Ready to be connected to legacy network");
 
				m_readyForConnect = true;
 
				onReadyToConnect();
 
			}
 

	
 
			std::string room = Buddy::JIDToLegacyName(presence->getTo());
 
			std::string password = "";
 
			if (presence->getPayload<Swift::MUCPayload>() != NULL) {
 
				password = presence->getPayload<Swift::MUCPayload>()->getPassword() ? *presence->getPayload<Swift::MUCPayload>()->getPassword() : "";
 
			}
 

	
 
			Conversation *conv = m_conversationManager->getConversation(room);
 
			if (conv != NULL) {
 
				if (std::find(conv->getJIDs().begin(), conv->getJIDs().end(), presence->getFrom()) != conv->getJIDs().end()) {
 
					LOG4CXX_INFO(logger, m_jid.toString() << ": User has already tried to join room " << room << " as " << presence->getTo().getResource());
 
				}
 
				else {
 
					conv->addJID(presence->getFrom());
 
					conv->sendParticipants(presence->getFrom());
 
					conv->sendCachedMessages(presence->getFrom());
 
				}
 

	
 
				if (forceJoin) {
 
					onRawPresenceReceived(presence);
 
					onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password);
 
				}
 
				return;
 
			}
 

	
 
			bool isInJoined = false;
 
			BOOST_FOREACH(Swift::Presence::ref &p, m_joinedRooms) {
 
				if (p->getTo() == presence->getTo()) {
 
					isInJoined = true;
 
				}
 
			}
 
			if (!isInJoined) {
 
				m_joinedRooms.push_back(presence);
 
			}
 

	
 
			if (!m_connected) {
 
				LOG4CXX_INFO(logger, m_jid.toString() << ": Joining room " << room << " postponed, because use is not connected to legacy network yet.");
 
				return;
spectrum/src/frontends/xmpp/vcardresponder.cpp
Show inline comments
 
@@ -14,115 +14,115 @@
 
 * 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 "vcardresponder.h"
 

	
 
#include <iostream>
 
#include <boost/bind.hpp>
 
#include "transport/User.h"
 
#include "transport/Buddy.h"
 
#include "transport/UserManager.h"
 
#include "transport/Transport.h"
 
#include "transport/Logging.h"
 
#include "Swiften/Queries/IQRouter.h"
 
#include <boost/foreach.hpp>
 

	
 
using namespace Swift;
 
using namespace boost;
 

	
 
namespace Transport {
 

	
 
DEFINE_LOGGER(logger, "VCardResponder");
 

	
 
VCardResponder::VCardResponder(Swift::IQRouter *router, Swift::NetworkFactories *factories, UserManager *userManager) : Swift::Responder<VCard>(router) {
 
	m_id = 0;
 
	m_userManager = userManager;
 
	m_collectTimer = factories->getTimerFactory()->createTimer(20000);
 
	m_collectTimer->onTick.connect(boost::bind(&VCardResponder::collectTimeouted, this));
 
	m_collectTimer->start();
 
}
 

	
 
VCardResponder::~VCardResponder() {
 
}
 

	
 
void VCardResponder::sendVCard(unsigned int id, boost::shared_ptr<Swift::VCard> vcard) {
 
	if (m_queries.find(id) == m_queries.end()) {
 
		LOG4CXX_WARN(logger, "Unexpected VCard from legacy network with id " << id);
 
		return;
 
	}
 

	
 
	LOG4CXX_INFO(logger, m_queries[id].from.toString() << ": Forwarding VCard of " << m_queries[id].to.toString() << " from legacy network");
 

	
 
	sendResponse(m_queries[id].from, m_queries[id].to, m_queries[id].id, vcard);
 
	m_queries.erase(id);
 
}
 

	
 
void VCardResponder::collectTimeouted() {
 
	time_t now = time(NULL);
 

	
 
	std::vector<unsigned int> candidates;
 
	for(std::map<unsigned int, VCardData>::iterator it = m_queries.begin(); it != m_queries.end(); it++) {
 
		if (now - (*it).second.received > 40) {
 
			candidates.push_back((*it).first);
 
		}
 
	}
 

	
 
	if (candidates.size() != 0) {
 
		LOG4CXX_INFO(logger, "Removing " << candidates.size() << " timeouted VCard requests");
 
	}
 

	
 
	BOOST_FOREACH(unsigned int id, candidates) {
 
		sendVCard(id, boost::shared_ptr<Swift::VCard>(new Swift::VCard()));
 
	}
 
	m_collectTimer->start();
 
}
 

	
 
bool VCardResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::VCard> payload) {
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return false;
 
	}
 

	
 
	Swift::JID to_ = to;
 

	
 
	std::string name = to_.getUnescapedNode();
 
	if (name.empty()) {
 
		to_ = user->getJID();
 
	}
 

	
 
	name = Buddy::JIDToLegacyName(to_, user);
 

	
 
	LOG4CXX_INFO(logger, from.toBare().toString() << ": Requested VCard of " << name);
 

	
 
	m_queries[m_id].from = from;
 
	m_queries[m_id].to = to;
 
	m_queries[m_id].id = id; 
 
	m_queries[m_id].received = time(NULL);
 
	onVCardRequired(user, name, m_id++);
 
	return true;
 
}
 

	
 
bool VCardResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr<Swift::VCard> payload) {
 
	if (!to.getNode().empty()) {
 
	if (!to.getNode().empty() && from.toBare().toString() != to.toBare().toString()) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": Tried to set VCard of somebody else");
 
		return false;
 
	}
 

	
 
	User *user = m_userManager->getUser(from.toBare().toString());
 
	if (!user) {
 
		LOG4CXX_WARN(logger, from.toBare().toString() << ": User is not logged in");
 
		return false;
 
	}
 

	
 
	LOG4CXX_INFO(logger, from.toBare().toString() << ": Setting VCard");
 
	onVCardUpdated(user, payload);
 

	
 
	sendResponse(from, id, boost::shared_ptr<VCard>(new VCard()));
 
	return true;
 
}
 

	
 
}
tests/start.py
Show inline comments
 
import optparse
 
import sys
 
import time
 
import subprocess
 
import os
 

	
 
import sleekxmpp
 
import imp
 

	
 
def registerXMPPAccount(user, password):
 
	responder = sleekxmpp.ClientXMPP(user, password)
 
	responder.register_plugin('xep_0030')  # Service Discovery
 
	responder.register_plugin('xep_0077')
 
	responder['feature_mechanisms'].unencrypted_plain = True
 

	
 
	if responder.connect(("127.0.0.1", 5222)):
 
		responder.process(block=False)
 
	else:
 
		print "connect() failed"
 
		sys.exit(1)
 

	
 
class BaseTest:
 
	def __init__(self, config, server_mode, room):
 
		self.config = config
 
		self.server_mode = server_mode
 
		self.room = room
 
		self.responder_jid = "responder@localhost"
 
		self.client_jid = "client@localhost"
 
		self.responder_password = "password"
 
		self.client_password = "password"
 
		self.client_room = room
 
		self.responder_room = room
 
		self.client_nick = "client"
 
		self.responder_nick = "responder"
 
		self.responder_roompassword = ""
 

	
 
	def skip_test(self, test):
 
		return False
 

	
 
	def start(self, Client, Responder):
 
		os.system("../../spectrum/src/spectrum2 -n ./" + self.config + " > spectrum2.log &")
 
		self.pre_test()
 
		time.sleep(1)
 

	
 
		responder = Responder(self.responder_jid, self.responder_password, self.responder_room, self.responder_roompassword, self.responder_nick)
 
		responder.register_plugin('xep_0030')  # Service Discovery
 
		responder.register_plugin('xep_0045')  # Multi-User Chat
 
		responder.register_plugin('xep_0199')  # XMPP Ping
 
		responder.register_plugin('xep_0153')
 
		responder.register_plugin('xep_0054')
 
		responder['feature_mechanisms'].unencrypted_plain = True
 

	
 
		to = ("127.0.0.1", 5223)
 
		if self.responder_password != "password":
 
			to = ()
 
		if responder.connect(to):
 
			responder.process(block=False)
 
		else:
 
			print "connect() failed"
 
			os.system("killall spectrum2")
 
			self.post_test()
 
			sys.exit(1)
 

	
 
		client = Client(self.client_jid, self.client_password, self.client_room, self.client_nick)
 
		client.register_plugin('xep_0030')  # Service Discovery
 
		client.register_plugin('xep_0045')  # Multi-User Chat
 
		client.register_plugin('xep_0199')  # XMPP Ping
 
		client.register_plugin('xep_0153')
 
		client.register_plugin('xep_0054')
 
		client['feature_mechanisms'].unencrypted_plain = True
 

	
 
		time.sleep(2)
 

	
 
		to = ("127.0.0.1", 5223)
 
		if self.responder_password != "password":
 
			to = ("127.0.0.1", 5222)
 
		if client.connect(to):
 
			client.process(block=False)
 
		else:
 
			print "connect() failed"
 
			os.system("killall spectrum2")
 
			self.post_test()
 
			sys.exit(1)
 

	
 
		max_time = 60
 
		while not client.finished and not responder.finished and max_time > 0:
 
			time.sleep(1)
 
			max_time -= 1
 
		client.disconnect()
 
		responder.disconnect()
 

	
 
		os.system("killall spectrum2")
 
		self.post_test()
 

	
 
		ret = True
 
		tests = []
 
		tests += client.tests.values()
 
		tests += responder.tests.values()
 
		for v in tests:
 
			if v[1]:
 
				print v[0] + ": PASSED"
 
			else:
 
				print v[0] + ": FAILED"
 
				ret = False
 

	
 
		if not ret:
 
			os.system("cat spectrum2.log")
 

	
 
		return ret
 

	
 
class LibcommuniServerModeSingleServerConf(BaseTest):
 
	def __init__(self):
 
		BaseTest.__init__(self, "../libcommuni/irc_test.cfg", True, "#channel@localhost")
 
		self.directory = "../libcommuni/"
 

	
 
	def pre_test(self):
 
		os.system("ngircd -f ../libcommuni/ngircd.conf &")
 

	
 
	def post_test(self):
 
		os.system("killall ngircd 2>/dev/null")
 
		os.system("killall spectrum2_libcommuni_backend 2>/dev/null")
 

	
 
class LibcommuniServerModeConf(BaseTest):
 
	def __init__(self):
 
		BaseTest.__init__(self, "../libcommuni/irc_test2.cfg", True, "#channel%localhost@localhost")
 
		self.directory = "../libcommuni/"
 

	
 
	def pre_test(self):
 
		os.system("ngircd -f ../libcommuni/ngircd.conf &")
 

	
 
	def post_test(self):
 
		os.system("killall ngircd 2>/dev/null")
 
		os.system("killall spectrum2_libcommuni_backend 2>/dev/null")
 

	
 
class JabberServerModeConf(BaseTest):
 
	def __init__(self):
 
		BaseTest.__init__(self, "../libpurple_jabber/jabber_test.cfg", True, "room%conference.localhost@localhostxmpp")
 
		self.directory = "../libpurple_jabber/"
 
		self.client_jid = "client%localhost@localhostxmpp"
 
		self.responder_jid = "responder%localhost@localhostxmpp"
 

	
 
	def skip_test(self, test):
 
		if test in ["muc_whois.py", "muc_change_topic.py"]:
 
			return True
 
		return False
 

	
 
	def pre_test(self):
 
		os.system("prosody --config ../libpurple_jabber/prosody.cfg.lua >prosody.log &")
 
		time.sleep(3)
 
		os.system("../../spectrum_manager/src/spectrum2_manager -c ../libpurple_jabber/manager.conf localhostxmpp register client%localhost@localhostxmpp client@localhost password 2>/dev/null >/dev/null")
 
		os.system("../../spectrum_manager/src/spectrum2_manager -c ../libpurple_jabber/manager.conf localhostxmpp register responder%localhost@localhostxmpp responder@localhost password 2>/dev/null >/dev/null")
 

	
 
	def post_test(self):
 
		os.system("killall lua-5.1 2>/dev/null")
 
		os.system("killall spectrum2_libpurple_backend 2>/dev/null")
 

	
 
class JabberSlackServerModeConf(BaseTest):
 
	def __init__(self):
 
		BaseTest.__init__(self, "../slack_jabber/jabber_slack_test.cfg", True, "room%conference.localhost@localhostxmpp")
 
		self.directory = "../slack_jabber/"
 
		self.client_jid = "client@localhost"
 
		self.client_room = "room@conference.localhost"
 
		self.responder_jid = "owner@spectrum2tests.xmpp.slack.com"
 
		self.responder_password = "spectrum2tests.e2zJwtKjLhLmt14VsMKq"
 
		self.responder_room = "spectrum2_room@conference.spectrum2tests.xmpp.slack.com"
0 comments (0 inline, 0 general)