soc.2009.transport: fcf47c38: Support for more resources (more clients...

hanzz at soc.pidgin.im hanzz at soc.pidgin.im
Tue Jun 30 02:50:41 EDT 2009


-----------------------------------------------------------------
Revision: fcf47c38bdb9ead72d80bebb8d437fcff97d1fd6
Ancestor: 4e09b6757ced5bf78b757d78eac947ad72268701
Author: hanzz at soc.pidgin.im
Date: 2009-06-30T06:45:23
Branch: im.pidgin.soc.2009.transport
URL: http://d.pidgin.im/viewmtn/revision/info/fcf47c38bdb9ead72d80bebb8d437fcff97d1fd6

Modified files:
        caps.cpp main.cpp user.cpp user.h

ChangeLog: 

Support for more resources (more clients connected to one PurpleAccount from the same JID)

-------------- next part --------------
============================================================
--- caps.cpp	c04a1bc5d73e0f91b21d5604d2a6ecd6f5831952
+++ caps.cpp	0107eb249451a3048b26f8c3d796099b433d4654
@@ -84,13 +84,15 @@ void GlooxDiscoHandler::handleDiscoInfo(
 		std::cout << "no user?! wtf...";
 	}
 	else{
-		std::cout << "1" << "\n";
-		if (user->capsVersion().empty()){
-			std::cout << "2" << "\n";
-			user->setCapsVersion(versions[context]);
-			if (user->readyForConnect()) {
-				std::cout << "3" << "\n";
-				user->connect();
+		if (user->hasResource(jid.resource())) {
+			std::cout << "1" << "\n";
+			if (user->getResource(jid.resource()).capsVersion.empty()){
+				std::cout << "2" << "\n";
+				user->setResource(jid.resource(), -256, versions[context]);
+				if (user->readyForConnect()) {
+					std::cout << "3" << "\n";
+					user->connect();
+				}
 			}
 		}
 	}
============================================================
--- main.cpp	f5b5e5764f40765b8feef2deb05074448df99975
+++ main.cpp	7c68f1161604e0f9abb3ae475d383a030392fb3c
@@ -1229,10 +1229,10 @@ void GlooxMessageHandler::handlePresence
 				}
 
 				Log().Get(stanza.from().full()) << "Creating new User instance";
-				user = new User(this, stanza.from().bare(), res.uin, res.password);
+				user = new User(this, stanza.from(), res.uin, res.password);
 				if (c!=NULL)
 					if(hasCaps(c->findAttribute("ver")))
-						user->setCapsVersion(c->findAttribute("ver"));
+						user->setResource(stanza.from().resource(), stanza.priority(), c->findAttribute("ver"));
 // 				if (!isVip)
 // 					user->features=features0;
 // 				else
============================================================
--- user.cpp	1bc78f76914b829a10162d3ebe1dee37bef950a1
+++ user.cpp	a0fdf613b7246e97fdfe441aecc25a6fd42f7610
@@ -48,9 +48,12 @@ static void sendXhtmlTag(Tag *tag, Tag *
 	GlooxMessageHandler::instance()->j->send(stanzaTag);
 }
 
-User::User(GlooxMessageHandler *parent, const std::string &jid, const std::string &username, const std::string &password){
+User::User(GlooxMessageHandler *parent, JID jid, const std::string &username, const std::string &password){
 	p = parent;
-	m_jid = jid;
+	m_jid = jid.bare();
+	Resource r;
+	m_resources[jid.resource()] = r;
+	m_resource = jid.resource();
 	m_username = username;
 	m_password = password;
 	m_connected = false;
@@ -114,10 +117,13 @@ bool User::syncCallback() {
  * Returns true if main JID for this User has feature `feature`,
  * otherwise returns false.
  */
-bool User::hasFeature(int feature){
-	if (m_capsVersion.empty())
+bool User::hasFeature(int feature, std::string resource){
+	if (resource.empty())
+		resource = m_resource;
+	std::string caps = m_resources[resource].capsVersion;
+	if (caps.empty())
 		return false;
-	if (p->capsCache[m_capsVersion]&feature)
+	if (p->capsCache[caps]&feature)
 		return true;
 	return false;
 }
@@ -167,7 +173,7 @@ bool User::isOpenedConversation(const st
  * Returns true if exists opened conversation with user with uin `name`.
  */
 bool User::isOpenedConversation(const std::string &name){
-	std::map<std::string,PurpleConversation *>::iterator iter = m_conversations.begin();
+	std::map<std::string, Conversation>::iterator iter = m_conversations.begin();
 	iter = m_conversations.find(name);
 	if(iter != m_conversations.end())
 		return true;
@@ -514,7 +520,7 @@ void User::purpleMessageReceived(PurpleA
 	if (conv==NULL){
 		// make conversation if it doesn't exist
 		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,account,name);
-		m_conversations[(std::string)name]=conv;
+		m_conversations[(std::string)name].conv = conv;
 	}
 }
 
@@ -525,7 +531,7 @@ void User::purpleConversationWriteChat(P
 	std::string name(who);
 	MUCHandler *muc = (MUCHandler*) g_hash_table_lookup(m_mucs, purple_conversation_get_name(conv));
 	if (!isOpenedConversation(name)) {
-		m_conversations[name] = conv;
+		m_conversations[name].conv = conv;
 		if (muc)
 			muc->setConversation(conv);
 	}
@@ -554,7 +560,7 @@ void User::purpleConversationWriteIM(Pur
 	std::for_each( name.begin(), name.end(), replaceBadJidCharacters() );
 	// new message from legacy network has been received
 	if (!isOpenedConversation(name)) {
-			m_conversations[name] = conv;
+			m_conversations[name].conv = conv;
 	}
 
 	Log().Get(m_jid) <<  "purpleConversationWriteIM:" << name << msg;
@@ -564,7 +570,12 @@ void User::purpleConversationWriteIM(Pur
 	char *strip = purple_markup_strip_html(newline);
 
 	std::string message(strip);
-	Message s(Message::Chat, m_jid, message);
+	std::string to;
+	if (m_conversations[name].resource.empty())
+		to = m_jid;
+	else
+		to = m_jid + "/" + m_conversations[name].resource;
+	Message s(Message::Chat, to, message);
 	std::string from;
 	from.append(name);
 	from.append("@");
@@ -623,7 +634,7 @@ void User::purpleChatAddUsers(PurpleConv
 	if (!muc)
 		return;
 	if (!isOpenedConversation(name)) {
-		m_conversations[name] = conv;
+		m_conversations[name].conv = conv;
 		muc->setConversation(conv);
 	}
 	muc->addUsers(cbuddies);
@@ -745,10 +756,12 @@ void User::receivedMessage(const Message
 	// open new conversation or get the opened one
 	if (!isOpenedConversation(username)){
 		conv = purple_conversation_new(PURPLE_CONV_TYPE_IM,m_account,username.c_str());
-		m_conversations[username]=conv;
+		m_conversations[username].conv = conv;
+		m_conversations[username].resource = msg.from().resource();
 	}
 	else{
-		conv = m_conversations[username];
+		conv = m_conversations[username].conv;
+		m_conversations[username].resource = msg.from().resource();
 	}
 	
 	std::string body = msg.body();
@@ -837,8 +850,7 @@ void User::connect(){
 	if (m_account) {
 		Log().Get(m_jid) << "connect() has been called before";
 		return;
-	}
-	Log().Get(m_jid) << "Connecting with caps: " << m_capsVersion;
+	};
 	if (purple_accounts_find(m_username.c_str(), this->p->protocol()->protocol().c_str()) != NULL){
 		Log().Get(m_jid) << "this account already exists";
 		m_account = purple_accounts_find(m_username.c_str(), this->p->protocol()->protocol().c_str());
@@ -1075,13 +1087,11 @@ void User::receivedPresence(const Presen
 		}
 	}
 
+	Tag *stanzaTag = stanza.tag();
+	if (!stanzaTag)
+		return;
 	if (m_lang == NULL) {
-		Tag *tag = stanza.tag();
-		if (!tag)
-			return;
-		std::string lang = tag->findAttribute("xml:lang");
-		Log().Get("LANG") << tag->xml();
-		delete tag;
+		std::string lang = stanzaTag->findAttribute("xml:lang");
 		if (lang == "")
 			lang = "en";
 		setLang(lang.c_str());
@@ -1093,11 +1103,16 @@ void User::receivedPresence(const Presen
 	if(stanza.to().username() == ""){
 		if(stanza.presence() == Presence::Unavailable) {
 			// disconnect from legacy network if we are connected
-			std::map<std::string,int> ::iterator iter = m_resources.begin();
+			std::map<std::string,Resource> ::iterator iter = m_resources.begin();
 			if ((m_connected==false && int(time(NULL))>int(m_connectionStart)+10) || m_connected==true){
 				iter = m_resources.find(stanza.from().resource());
 				if(iter != m_resources.end()){
 					m_resources.erase(stanza.from().resource());
+					for(std::map<std::string, Conversation>::iterator u = m_conversations.begin(); u != m_conversations.end() ; u++){
+						if ((*u).second.resource == stanza.from().resource()){
+							m_conversations[(*u).first].resource = "";
+						}
+					}
 				}
 			}
 			if (m_connected){
@@ -1123,20 +1138,29 @@ void User::receivedPresence(const Presen
 				}
 			}
 		} else {
-			m_resource=stanza.from().resource();
-			std::map<std::string,int> ::iterator iter = m_resources.begin();
-			iter = m_resources.find(m_resource);
+			std::string resource=stanza.from().resource();
+			std::map<std::string,Resource> ::iterator iter = m_resources.begin();
+			iter = m_resources.find(resource);
 			if(iter == m_resources.end()){
-				m_resources[m_resource]=stanza.priority();
+				m_resources[resource].priority = stanza.priority();
+				Tag *c = stanzaTag->findChildWithAttrib("xmlns","http://jabber.org/protocol/caps");
+				// presence has caps
+				if (c!=NULL){
+					if (p->hasCaps(c->findAttribute("ver"))){
+						m_resources[resource].capsVersion = c->findAttribute("ver");
+					}
+				}
+				if (m_resources[resource].priority > m_resources[m_resource].priority)
+					m_resource = resource;
 			}
 
 			Log().Get(m_jid) << "resource: " << m_resource;
 			if (!m_connected){
 				// we are not connected to legacy network, so we should do it when disco#info arrive :)
-				Log().Get(m_jid) << "connecting: capsVersion=" << m_capsVersion;
+				Log().Get(m_jid) << "connecting: resource=" << m_resource;
 				if (m_readyForConnect==false){
 					m_readyForConnect=true;
-					if (m_capsVersion.empty()){
+					if (m_resources[m_resource].capsVersion.empty()){
 						// caps not arrived yet, so we can't connect just now and we have to wait for caps
 					}
 					else{
@@ -1193,7 +1217,6 @@ void User::receivedPresence(const Presen
 			}
 			
 		}
-		
 		// send presence about tranport status to user
 		if(m_connected || m_readyForConnect) {
 			Presence tag(stanza.presence(), m_jid, stanza.status());
@@ -1208,6 +1231,7 @@ void User::receivedPresence(const Presen
 				p->j->send( tag );
 			}
 		}
+	delete stanzaTag;
 	}
 }
 
============================================================
--- user.h	778fae39a0d134a39feac04c54b723826b10d9f6
+++ user.h	f503f466694a21d92372913b62b677da498fca60
@@ -63,9 +63,19 @@ struct subscribeContact {
 	std::string	group;
 };
 
+struct Resource {
+	int priority;
+	std::string capsVersion;
+};
+
+struct Conversation {
+	PurpleConversation *conv;
+	std::string resource;
+};
+
 class User {
 	public:
-		User(GlooxMessageHandler *parent, const std::string &jid, const std::string &username, const std::string &password);
+		User(GlooxMessageHandler *parent, JID jid, const std::string &username, const std::string &password);
 		~User();
 
 		void connect();
@@ -77,7 +87,7 @@ class User {
 		bool syncCallback();
 		bool isInRoster(const std::string &name,const std::string &subscription);
 		bool isOpenedConversation(const std::string &name);
-		bool hasFeature(int feature);
+		bool hasFeature(int feature, std::string resource = "");
 		
 		// XMPP stuff
 		Tag *generatePresenceStanza(PurpleBuddy *buddy);
@@ -118,10 +128,6 @@ class User {
 		PurpleValue *getSetting(const char *key);
 		void updateSetting(const std::string &key, PurpleValue *value);
 
-		// Entity Capabilities
-		std::string & capsVersion() { return m_capsVersion; }
-		void setCapsVersion(const std::string &capsVersion) { m_capsVersion = capsVersion; }
-		
 		// Authorization requests
 		bool hasAuthRequest(const std::string &name);
 		void removeAuthRequest(const std::string &name);
@@ -132,8 +138,15 @@ class User {
 		// connection start
 		time_t connectionStart() { return m_connectionStart; }
 		
+		void setResource(const std::string resource, int priority = -256, const std::string caps = "") {
+			if (priority != -256) m_resources[resource].priority = priority;
+			if (!caps.empty()) m_resources[resource].capsVersion = caps;
+		}
+		bool hasResource(const std::string r) {return m_resources.find(r) == m_resources.end(); }
+		Resource & getResource(const std::string r) { return m_resources[r];}
+		
 		PurpleAccount *account() { return m_account; }
-		std::map<std::string,int> & resources() { return m_resources; }
+		std::map<std::string,Resource> & resources() { return m_resources; }
 		int reconnectCount() { return m_reconnectCount; }
 		bool isVIP() { return m_vip; }
 		bool readyForConnect() { return m_readyForConnect; }
@@ -163,14 +176,13 @@ class User {
 		std::string m_username;		// legacy network user name
 		std::string m_jid;			// Jabber ID of this user
 		std::string m_resource;		// active resource
-		std::string m_capsVersion;	// caps version of client which connected as first (TODO: this should be changed with active resource)
 		const char *m_lang;			// xml:lang
 		time_t m_connectionStart;	// connection start timestamp
 		GHashTable *m_mucs;			// MUCs
 		std::map<std::string,RosterRow> m_roster;	// jabber roster of this user
-		std::map<std::string,int> m_resources;	// list of all resources which are connected to the transport
+		std::map<std::string,Resource> m_resources;	// list of all resources which are connected to the transport
 		std::map<std::string,authRequest> m_authRequests;	// list of authorization requests (holds callbacks and user data)
-		std::map<std::string,PurpleConversation *> m_conversations; // list of opened conversations
+		std::map<std::string,Conversation> m_conversations; // list of opened conversations
 		std::map<std::string,PurpleBuddy *> m_subscribeCache;	// cache for contacts for roster X
 		GHashTable *m_settings;		// user settings
 };


More information about the Commits mailing list