Changeset - afe5ac506dd1
[Not reviewed]
0 3 0
HanzZ - 13 years ago 2012-03-30 15:28:49
hanzz.k@gmail.com
Store buddy changes only when there's a real change
3 files changed with 12 insertions and 6 deletions:
0 comments (0 inline, 0 general)
include/transport/localbuddy.h
Show inline comments
 
/**
 
 * 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
 
 */
 

	
 
#ifndef SPECTRUM_BUDDY_H
 
#define SPECTRUM_BUDDY_H
 

	
 
#include <string>
 
#include <algorithm>
 
#include "transport/buddy.h"
 
#include "transport/rostermanager.h"
 

	
 
namespace Transport {
 

	
 
class LocalBuddy : public Buddy {
 
	public:
 
		LocalBuddy(RosterManager *rosterManager, long id);
 
		virtual ~LocalBuddy();
 

	
 
		std::string getAlias() { return m_alias; }
 
		void setAlias(const std::string &alias);
 

	
 
		std::string getName() { return m_name; }
 
		void setName(const std::string &name) { m_name = name; }
 

	
 
		bool getStatus(Swift::StatusShow &status, std::string &statusMessage) {
 
			status = m_status;
 
			statusMessage = m_statusMessage;
 
			return true;
 
		}
 

	
 
		void setStatus(const Swift::StatusShow &status, const std::string &statusMessage) {
 
			m_status = status;
 
			m_statusMessage = statusMessage;
 
		}
 

	
 
		std::string getIconHash() { return m_iconHash; }
 
		void setIconHash(const std::string &iconHash) { m_iconHash = iconHash; }
 
		void setIconHash(const std::string &iconHash) {
 
			bool changed = m_iconHash != iconHash;
 
			m_iconHash = iconHash;
 
			if (changed)
 
				getRosterManager()->storeBuddy(this);
 
		}
 

	
 
		std::vector<std::string> getGroups() { return m_groups; }
 
		void setGroups(const std::vector<std::string> &groups) { m_groups = groups; }
 
		void setGroups(const std::vector<std::string> &groups) {
 
			bool changed = m_groups.size() != groups.size();
 
			m_groups = groups;
 
			if (changed)
 
				getRosterManager()->storeBuddy(this);
 
		}
 

	
 
	private:
 
		std::string m_name;
 
		std::string m_alias;
 
		std::vector<std::string> m_groups;
 
		std::string m_statusMessage;
 
		std::string m_iconHash;
 
		Swift::StatusShow m_status;
 
		bool m_firstSet;
 
};
 

	
 
}
 

	
 
#endif
src/buddy.cpp
Show inline comments
 
@@ -55,130 +55,129 @@ void Buddy::setFlags(BuddyFlag flags) {
 
}
 

	
 
BuddyFlag Buddy::getFlags() {
 
	return m_flags;
 
}
 

	
 
const Swift::JID &Buddy::getJID() {
 
	if (!m_jid.isValid() || m_jid.getNode().empty()) {
 
		generateJID();
 
	}
 
	return m_jid;
 
}
 

	
 
void Buddy::setSubscription(Subscription subscription) {
 
	m_subscription = subscription;
 
}
 

	
 
Buddy::Subscription Buddy::getSubscription() {
 
	return m_subscription;
 
}
 

	
 
Swift::Presence::ref Buddy::generatePresenceStanza(int features, bool only_new) {
 
	std::string alias = getAlias();
 
	std::string name = getSafeName();
 

	
 
	Swift::StatusShow s;
 
	std::string statusMessage;
 
	if (!getStatus(s, statusMessage))
 
		return Swift::Presence::ref();
 

	
 
	if (m_jid.getNode().empty()) {
 
		generateJID();
 
	}
 

	
 
	Swift::Presence::ref presence = Swift::Presence::create();
 
 	presence->setFrom(m_jid);
 
	presence->setTo(m_rosterManager->getUser()->getJID().toBare());
 
	presence->setType(Swift::Presence::Available);
 

	
 
	if (!statusMessage.empty())
 
		presence->setStatus(statusMessage);
 

	
 
	if (s.getType() == Swift::StatusShow::None)
 
		presence->setType(Swift::Presence::Unavailable);
 
	presence->setShow(s.getType());
 

	
 
	if (presence->getType() != Swift::Presence::Unavailable) {
 
		// caps
 
		
 
		presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::CapsInfo(m_rosterManager->getUser()->getComponent()->getBuddyCapsInfo())));
 

	
 
// 		if (features & 0/*TRANSPORT_FEATURE_AVATARS*/) {
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Swift::VCardUpdate (getIconHash())));
 
// 		}
 
		if (isBlocked()) {
 
			presence->addPayload(boost::shared_ptr<Swift::Payload>(new Transport::BlockPayload ()));
 
		}
 
	}
 

	
 
// 	if (only_new) {
 
// 		if (m_lastPresence)
 
// 			m_lastPresence->setTo(Swift::JID(""));
 
// 		if (m_lastPresence == presence) {
 
// 			return Swift::Presence::ref();
 
// 		}
 
// 		m_lastPresence = presence;
 
// 	}
 

	
 
	return presence;
 
}
 

	
 
std::string Buddy::getSafeName() {
 
	if (m_jid.isValid()) {
 
		return m_jid.getNode();
 
	}
 
	std::string name = getName();
 
// 	Transport::instance()->protocol()->prepareUsername(name, purple_buddy_get_account(m_buddy));
 
	if (getFlags() & BUDDY_JID_ESCAPING) {
 
		name = Swift::JID::getEscapedNode(name);
 
	}
 
	else {
 
		if (name.find_last_of("@") != std::string::npos) {
 
			name.replace(name.find_last_of("@"), 1, "%"); // OK
 
		}
 
	}
 
// 	if (name.empty()) {
 
// 		Log("SpectrumBuddy::getSafeName", "Name is EMPTY! Previous was " << getName() << ".");
 
// 	}
 
	return name;
 
}
 

	
 
void Buddy::handleBuddyChanged() {
 
	Swift::Presence::ref presence = generatePresenceStanza(255);
 
	if (presence) {
 
		m_rosterManager->getUser()->getComponent()->getStanzaChannel()->sendPresence(presence);
 
	}
 
	m_rosterManager->handleBuddyChanged(this);
 
}
 

	
 
void Buddy::handleVCardReceived(const std::string &id, Swift::VCard::ref vcard) {
 
	boost::shared_ptr<Swift::GenericRequest<Swift::VCard> > request(new Swift::GenericRequest<Swift::VCard>(Swift::IQ::Result, m_rosterManager->getUser()->getJID(), vcard, m_rosterManager->getUser()->getComponent()->getIQRouter()));
 
	request->send();
 
}
 

	
 
std::string Buddy::JIDToLegacyName(const Swift::JID &jid) {
 
	std::string name;
 
	if (jid.getUnescapedNode() == jid.getNode()) {
 
		name = jid.getNode();
 
		if (name.find_last_of("%") != std::string::npos) {
 
			name.replace(name.find_last_of("%"), 1, "@"); // OK
 
		}
 
	}
 
	else {
 
		name = jid.getUnescapedNode();
 
		// Psi sucks...
 
// 		if (name.find_last_of("\\40") != std::string::npos) {
 
// 			name.replace(name.find_last_of("\\40"), 1, "@"); // OK
 
// 		}
 
	}
 
	return name;
 
}
 

	
 
BuddyFlag Buddy::buddFlagsFromJID(const Swift::JID &jid) {
 
	if (jid.getUnescapedNode() == jid.getNode()) {
 
		return BUDDY_NO_FLAG;
 
	}
 
	return BUDDY_JID_ESCAPING;
 
}
 

	
 
}
src/rostermanager.cpp
Show inline comments
 
@@ -59,195 +59,192 @@ RosterManager::RosterManager(User *user, Component *component){
 
RosterManager::~RosterManager() {
 
	m_setBuddyTimer->stop();
 
	m_RIETimer->stop();
 
	if (m_rosterStorage) {
 
		m_rosterStorage->storeBuddies();
 
	}
 

	
 
	sendUnavailablePresences(m_user->getJID().toBare());
 

	
 
	if (m_remoteRosterRequest) {
 
		m_remoteRosterRequest->onResponse.disconnect_all_slots();
 
		m_component->getIQRouter()->removeHandler(m_remoteRosterRequest);
 
	}
 

	
 
	for (std::map<std::string, Buddy *, std::less<std::string>, boost::pool_allocator< std::pair<std::string, Buddy *> > >::iterator it = m_buddies.begin(); it != m_buddies.end(); it++) {
 
		Buddy *buddy = (*it).second;
 
		if (!buddy) {
 
			continue;
 
		}
 
		delete buddy;
 
	}
 

	
 
	if (m_requests.size() != 0) {
 
		LOG4CXX_INFO(logger, m_user->getJID().toString() <<  ": Removing " << m_requests.size() << " unresponded IQs");
 
		BOOST_FOREACH(Swift::SetRosterRequest::ref request, m_requests) {
 
			request->onResponse.disconnect_all_slots();
 
			m_component->getIQRouter()->removeHandler(request);
 
		}
 
		m_requests.clear();
 
	}
 

	
 
	boost::singleton_pool<boost::pool_allocator_tag, sizeof(unsigned int)>::release_memory();
 

	
 
	if (m_rosterStorage)
 
		delete m_rosterStorage;
 
}
 

	
 
void RosterManager::setBuddy(Buddy *buddy) {
 
// 	m_setBuddyTimer->onTick.connect(boost::bind(&RosterManager::setBuddyCallback, this, buddy));
 
// 	m_setBuddyTimer->start();
 
	setBuddyCallback(buddy);
 
}
 

	
 
void RosterManager::sendBuddyRosterPush(Buddy *buddy) {
 
	// user can't receive anything in server mode if he's not logged in.
 
	// He will ask for roster later (handled in rosterreponsder.cpp)
 
	if (m_component->inServerMode() && !m_user->isConnected())
 
		return;
 

	
 
	Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload());
 
	Swift::RosterItemPayload item;
 
	item.setJID(buddy->getJID().toBare());
 
	if (buddy->getAlias().empty()) {
 
		item.setName(buddy->getJID().toBare().toString());
 
	}
 
	else {
 
		item.setName(buddy->getAlias());
 
	}
 
	item.setGroups(buddy->getGroups());
 
	item.setSubscription(Swift::RosterItemPayload::Both);
 

	
 
	payload->addItem(item);
 

	
 
	// In server mode we have to send pushes to all resources, but in gateway-mode we send it only to bare JID
 
	if (m_component->inServerMode()) {
 
		std::vector<Swift::Presence::ref> presences = m_component->getPresenceOracle()->getAllPresence(m_user->getJID().toBare());
 
		BOOST_FOREACH(Swift::Presence::ref presence, presences) {
 
			Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, presence->getFrom(), m_component->getIQRouter());
 
			request->onResponse.connect(boost::bind(&RosterManager::handleBuddyRosterPushResponse, this, _1, request, buddy->getName()));
 
			request->send();
 
			m_requests.push_back(request);
 
		}
 
	}
 
	else {
 
		Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, m_user->getJID().toBare(), m_component->getIQRouter());
 
		request->onResponse.connect(boost::bind(&RosterManager::handleBuddyRosterPushResponse, this, _1, request, buddy->getName()));
 
		request->send();
 
		m_requests.push_back(request);
 
	}
 

	
 
	if (buddy->getSubscription() != Buddy::Both) {
 
		buddy->setSubscription(Buddy::Both);
 
		handleBuddyChanged(buddy);
 
	}
 
}
 

	
 
void RosterManager::sendBuddySubscribePresence(Buddy *buddy) {
 
	Swift::Presence::ref response = Swift::Presence::create();
 
	response->setTo(m_user->getJID());
 
	response->setFrom(buddy->getJID());
 
	response->setType(Swift::Presence::Subscribe);
 
// 	TODO: NICKNAME
 
	m_component->getStanzaChannel()->sendPresence(response);
 
}
 

	
 
void RosterManager::handleBuddyChanged(Buddy *buddy) {
 
	if (m_rosterStorage) {
 
		m_rosterStorage->storeBuddy(buddy);
 
	}
 
}
 

	
 
void RosterManager::setBuddyCallback(Buddy *buddy) {
 
	LOG4CXX_INFO(logger, "Associating buddy " << buddy->getName() << " with " << m_user->getJID().toString());
 
	m_buddies[buddy->getName()] = buddy;
 
	onBuddySet(buddy);
 

	
 
	// In server mode the only way is to send jabber:iq:roster push.
 
	// In component mode we send RIE or Subscribe presences, based on features.
 
	if (m_component->inServerMode()) {
 
		sendBuddyRosterPush(buddy);
 
	}
 
	else {
 
		if (buddy->getSubscription() == Buddy::Both) {
 
			LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Not forwarding this buddy, because subscription=both");
 
			return;
 
		}
 

	
 
		if (m_supportRemoteRoster) {
 
			sendBuddyRosterPush(buddy);
 
		}
 
		else {
 
			// Send RIE only if there's resource which supports it.
 
			Swift::JID jidWithRIE = m_user->getJIDWithFeature("http://jabber.org/protocol/rosterx");
 
			if (jidWithRIE.isValid()) {
 
				m_RIETimer->start();
 
			}
 
			else {
 
				sendBuddySubscribePresence(buddy);
 
			}
 
		}
 
	}
 

	
 
	if (m_rosterStorage)
 
		m_rosterStorage->storeBuddy(buddy);
 
}
 

	
 
void RosterManager::unsetBuddy(Buddy *buddy) {
 
	m_buddies.erase(buddy->getName());
 
	if (m_rosterStorage)
 
		m_rosterStorage->removeBuddyFromQueue(buddy);
 
	onBuddyUnset(buddy);
 
}
 

	
 
void RosterManager::storeBuddy(Buddy *buddy) {
 
	if (m_rosterStorage) {
 
		m_rosterStorage->storeBuddy(buddy);
 
	}
 
}
 

	
 
void RosterManager::handleBuddyRosterPushResponse(Swift::ErrorPayload::ref error, Swift::SetRosterRequest::ref request, const std::string &key) {
 
	LOG4CXX_INFO(logger, "handleBuddyRosterPushResponse called for buddy " << key);
 
	if (m_buddies[key] != NULL) {
 
		m_buddies[key]->handleBuddyChanged();
 
	}
 
	else {
 
		LOG4CXX_WARN(logger, "handleBuddyRosterPushResponse called for unknown buddy " << key);
 
	}
 

	
 
	m_requests.remove(request);
 
	request->onResponse.disconnect_all_slots();
 
}
 

	
 
void RosterManager::handleRemoteRosterResponse(boost::shared_ptr<Swift::RosterPayload> payload, Swift::ErrorPayload::ref error) {
 
	m_remoteRosterRequest.reset();
 
	if (error) {
 
		m_supportRemoteRoster = false;
 
		LOG4CXX_INFO(logger, m_user->getJID().toString() << ": This server does not support remote roster protoXEP");
 
		return;
 
	}
 

	
 
	LOG4CXX_INFO(logger, m_user->getJID().toString() << ": This server supports remote roster protoXEP");
 
	m_supportRemoteRoster = true;
 
	return;
 

	
 
	BOOST_FOREACH(const Swift::RosterItemPayload &item, payload->getItems()) {
 
		std::string legacyName = Buddy::JIDToLegacyName(item.getJID());
 
		if (m_buddies.find(legacyName) != m_buddies.end()) {
 
			continue;
 
		}
 
		std::cout << "LEGACYNAME " << legacyName << "\n";
 

	
 
		BuddyInfo buddyInfo;
 
		buddyInfo.id = -1;
 
		buddyInfo.alias = item.getName();
 
		buddyInfo.legacyName = legacyName;
 
		buddyInfo.subscription = "both";
 
		buddyInfo.flags = Buddy::buddFlagsFromJID(item.getJID());
 

	
 
		Buddy *buddy = m_component->getFactory()->createBuddy(this, buddyInfo);
 
		setBuddy(buddy);
 
	}
 
}
 

	
 
Buddy *RosterManager::getBuddy(const std::string &name) {
 
	return m_buddies[name];
0 comments (0 inline, 0 general)