soc.2009.transport: 669444a2: First version of Jabber search (XEP-0055...

hanzz at soc.pidgin.im hanzz at soc.pidgin.im
Tue Jun 23 09:41:09 EDT 2009


-----------------------------------------------------------------
Revision: 669444a27ac7f3dbe0fd60ec24413e9c94a23476
Ancestor: 0dcf1c9187d398a246ba00598ccbcdec94448127
Author: hanzz at soc.pidgin.im
Date: 2009-06-23T13:38:35
Branch: im.pidgin.soc.2009.transport
URL: http://d.pidgin.im/viewmtn/revision/info/669444a27ac7f3dbe0fd60ec24413e9c94a23476

Added files:
        abstractpurplerequest.h searchhandler.cpp searchhandler.h
        searchrepeater.cpp searchrepeater.h
Modified files:
        CMakeLists.txt adhoccommandhandler.h adhochandler.cpp
        adhocrepeater.cpp adhocrepeater.h adhocsettings.cpp
        adhocsettings.h main.cpp main.h protocols/abstractprotocol.h
        protocols/facebook.cpp protocols/facebook.h statshandler.cpp
        user.h

ChangeLog: 

First version of Jabber search (XEP-0055). Currently it works only with protocols which uses PURPLE_REQUEST_INPUT to get sesearch string (tested with Facebook)

-------------- next part --------------
============================================================
--- abstractpurplerequest.h	f42fe4b5e20ebedd6aee76c45a2987f872292a1f
+++ abstractpurplerequest.h	f42fe4b5e20ebedd6aee76c45a2987f872292a1f
@@ -0,0 +1,44 @@
+/**
+ * XMPP - libpurple transport
+ *
+ * Copyright (C) 2009, Jan Kaluza <hanzz at 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 _HI_ABSTRACT_PURPLE_REQUEST_H
+#define _HI_ABSTRACT_PURPLE_REQUEST_H
+
+#include <string>
+#include <list>
+#include "user.h"
+
+using namespace gloox;
+
+class AbstractPurpleRequest
+{
+	public:
+		virtual ~AbstractPurpleRequest() {}
+
+		void setRequestType(AdhocDataCallerType type) { m_rtype = type; }
+		AdhocDataCallerType & requestType() { return m_rtype; }
+		
+	private:
+		AdhocDataCallerType m_rtype;
+	
+	
+};
+
+#endif
============================================================
--- searchhandler.cpp	78ac2eb4f1018e0bded8a7aa95cc95fb9878539e
+++ searchhandler.cpp	78ac2eb4f1018e0bded8a7aa95cc95fb9878539e
@@ -0,0 +1,116 @@
+/**
+ * XMPP - libpurple transport
+ *
+ * Copyright (C) 2009, Jan Kaluza <hanzz at 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 "searchhandler.h"
+#include "main.h"
+#include "gloox/search.h"
+#include "usermanager.h"
+#include "protocols/abstractprotocol.h"
+
+SearchExtension::SearchExtension() : StanzaExtension( ExtSearch )
+{
+	m_tag = NULL;
+}
+
+SearchExtension::SearchExtension(const Tag *tag) : StanzaExtension( ExtSearch )
+{
+	m_tag = tag->clone();
+}
+
+SearchExtension::~SearchExtension()
+{
+	Log().Get("SearchExtension") << "deleting SearchExtension()";
+	delete m_tag;
+}
+
+const std::string& SearchExtension::filterString() const
+{
+	static const std::string filter = "iq/query[@xmlns='jabber:iq:search']";
+	return filter;
+}
+
+Tag* SearchExtension::tag() const
+{
+	return m_tag->clone();
+}
+
+GlooxSearchHandler::GlooxSearchHandler(GlooxMessageHandler *parent) : IqHandler() {
+	p=parent;
+	p->j->registerStanzaExtension( new SearchExtension() );
+}
+
+GlooxSearchHandler::~GlooxSearchHandler() {
+}
+
+bool GlooxSearchHandler::hasSession(const std::string &jid) {
+	std::map<std::string,SearchRepeater *> ::iterator iter = m_sessions.begin();
+	iter = m_sessions.find(jid);
+	return iter != m_sessions.end();
+}
+
+void GlooxSearchHandler::searchResultsArrived(const std::string &from, PurpleNotifySearchResults *results) {
+	if (hasSession(from)) {
+		m_sessions[from]->sendSearchResults(results);
+	}
+}
+
+bool GlooxSearchHandler::handleIq (const IQ &iq) {
+	User *user = p->userManager()->getUserByJID(iq.from().bare());
+	if (!user) return true;
+
+	if(iq.subtype() == IQ::Get) {
+		AdhocData data;
+		data.id = iq.id();
+		data.from = iq.from().full();
+		data.node = p->protocol()->userSearchAction();
+		data.callerType = CALLER_SEARCH;
+		user->setAdhocData(data);
+		PurpleConnection *gc = purple_account_get_connection(user->account());
+		PurplePlugin *plugin = gc && PURPLE_CONNECTION_IS_CONNECTED(gc) ? gc->prpl : NULL;
+		if (plugin && PURPLE_PLUGIN_HAS_ACTIONS(plugin)) {
+			PurplePluginAction *action = NULL;
+			GList *actions, *l;
+
+			actions = PURPLE_PLUGIN_ACTIONS(plugin, gc);
+
+			for (l = actions; l != NULL; l = l->next) {
+				if (l->data) {
+					action = (PurplePluginAction *) l->data;
+					if (data.node == (std::string) action->label) {
+						action->plugin = plugin;
+						action->context = gc;
+						action->callback(action);
+						purple_plugin_action_free(action);
+						break;
+					}
+					purple_plugin_action_free(action);
+				}
+			}
+		}
+	}
+	else {
+		if (hasSession(iq.from().full())) {
+			m_sessions[iq.from().full()]->handleIq(iq);
+		}
+	}
+	return true;
+}
+
+void GlooxSearchHandler::handleIqID (const IQ &iq, int context) { }
============================================================
--- searchhandler.h	115e6f50a5e78943e92201de2712b9ad54ac7ed1
+++ searchhandler.h	115e6f50a5e78943e92201de2712b9ad54ac7ed1
@@ -0,0 +1,88 @@
+/**
+ * XMPP - libpurple transport
+ *
+ * Copyright (C) 2009, Jan Kaluza <hanzz at 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 _HI_SEARCH_HANDLER_H
+#define _HI_SEARCH_HANDLER_H
+
+#include <gloox/iqhandler.h>
+#include "searchrepeater.h"
+
+class GlooxMessageHandler;
+using namespace gloox;
+
+
+class SearchExtension : public StanzaExtension
+{
+
+public:
+	/**
+	* Constructs a new object from the given Tag.
+	*/
+	SearchExtension();
+	SearchExtension(const Tag *tag);
+
+	/**
+	* Virtual Destructor.
+	*/
+	virtual ~SearchExtension();
+
+	// reimplemented from StanzaExtension
+	virtual const std::string& filterString() const;
+
+	// reimplemented from StanzaExtension
+	virtual StanzaExtension* newInstance( const Tag* tag ) const
+	{
+	return new SearchExtension(tag);
+	}
+
+	// reimplemented from StanzaExtension
+	virtual Tag* tag() const;
+
+	// reimplemented from StanzaExtension
+	virtual StanzaExtension* clone() const
+	{
+		return new SearchExtension(m_tag);
+	}
+	
+private:
+	Tag *m_tag;
+
+};
+
+class GlooxSearchHandler : public IqHandler
+{
+
+public:
+	GlooxSearchHandler(GlooxMessageHandler *parent);
+	~GlooxSearchHandler();
+	bool handleIq (const IQ &iq);
+	void handleIqID (const IQ &iq, int context);
+	void searchResultsArrived(const std::string &from, PurpleNotifySearchResults *results);
+	
+	void registerSession(const std::string &jid, SearchRepeater *handler) {m_sessions[jid] = handler; }
+	void unregisterSession(std::string &jid) { m_sessions.erase(jid); }
+	bool hasSession(const std::string &jid);
+
+private:
+	std::map<std::string, SearchRepeater *> m_sessions;
+	GlooxMessageHandler *p;
+};
+
+#endif
\ No newline at end of file
============================================================
--- searchrepeater.cpp	b6dcbe7ab7046fe2116551bc126b0f617d2ea6c1
+++ searchrepeater.cpp	b6dcbe7ab7046fe2116551bc126b0f617d2ea6c1
@@ -0,0 +1,201 @@
+/**
+ * XMPP - libpurple transport
+ *
+ * Copyright (C) 2009, Jan Kaluza <hanzz at 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 "searchrepeater.h"
+#include "gloox/stanza.h"
+#include "log.h"
+#include "protocols/abstractprotocol.h"
+ 
+static gboolean removeRepeater(gpointer data){
+	SearchRepeater *repeater = (SearchRepeater*) data;
+	purple_request_close(repeater->type(),repeater);
+	Log().Get("SearchRepeater") << "repeater closed";
+	return FALSE;
+}
+ 
+SearchRepeater::SearchRepeater(GlooxMessageHandler *m, User *user, const std::string &title, const std::string &primaryString, const std::string &secondaryString, const std::string &value, gboolean multiline, gboolean masked, GCallback ok_cb, GCallback cancel_cb, void * user_data) {
+	main = m;
+	m_user = user;
+	m_ok_cb = ok_cb;
+	m_lastTag = NULL;
+	m_cancel_cb = cancel_cb;
+	m_requestData = user_data;
+	AdhocData data = user->adhocData();
+	m_from = data.from;
+	
+	setType(PURPLE_REQUEST_INPUT);
+	setRequestType(CALLER_SEARCH);
+
+	// <iq from="vjud.localhost" type="result" to="test at localhost/hanzz-laptop" id="aad1a" >
+	// <query xmlns="jabber:iq:search">
+	// <instructions>You need an x:data capable client to search</instructions>
+	// <x xmlns="jabber:x:data" type="form" >
+	// <title>Search users in vjud.localhost</title>
+	// <instructions>Fill in the form to search for any matching Jabber User (Add * to the end of field to match substring)</instructions>
+	// <field type="text-single" label="User" var="user" />
+	// <field type="text-single" label="Full Name" var="fn" />
+	// <field type="text-single" label="Name" var="first" />
+	// <field type="text-single" label="Middle Name" var="middle" />
+	// <field type="text-single" label="Family Name" var="last" />
+	// <field type="text-single" label="Nickname" var="nick" />
+	// <field type="text-single" label="Birthday" var="bday" />
+	// <field type="text-single" label="Country" var="ctry" />
+	// <field type="text-single" label="City" var="locality" />
+	// <field type="text-single" label="Email" var="email" />
+	// <field type="text-single" label="Organization Name" var="orgname" />
+	// <field type="text-single" label="Organization Unit" var="orgunit" />
+	// </x>
+	// </query>
+	// </iq>
+
+	IQ _response(IQ::Result, data.from, data.id);
+	Tag *response = _response.tag();
+	response->addAttribute("from",main->jid());
+
+	Tag *query = new Tag("query");
+	query->addAttribute("xmlns", "jabber:iq:search");
+	query->addChild( new Tag("instructions", "<instructions>You need an x:data capable client to search</instructions>") );
+	
+	Tag *xdata = new Tag("x");
+	xdata->addAttribute("xmlns","jabber:x:data");
+	xdata->addAttribute("type","form");
+	xdata->addChild(new Tag("title",title));
+	xdata->addChild(new Tag("instructions",primaryString));
+
+	Tag *field = new Tag("field");
+	if (multiline)
+		field->addAttribute("type","text-multi");
+	else
+		field->addAttribute("type","text-single");
+	field->addAttribute("label","Search field");
+	field->addAttribute("var","result");
+	field->addChild(new Tag("value",value));
+	
+	xdata->addChild(field);
+	query->addChild(xdata);
+	response->addChild(query);
+	main->j->send(response);
+}
+
+SearchRepeater::~SearchRepeater() {
+	if (m_lastTag)
+		delete m_lastTag;
+}
+
+void SearchRepeater::sendSearchResults(PurpleNotifySearchResults *results) {
+	GList *columniter;
+	GList *row, *column;
+	int i = 0;
+	std::map <int, std::string> columns;
+	std::cout << "SEARCH RESULTS\n";
+
+	IQ _response(IQ::Result, m_lastTag->findAttribute("from"), m_lastTag->findAttribute("id"));
+	Tag *response = _response.tag();
+	response->addAttribute("from",main->jid());
+
+	Tag *query = new Tag("query");
+	query->addAttribute("xmlns", "jabber:iq:search");
+	
+	Tag *xdata = new Tag("x");
+	xdata->addAttribute("xmlns","jabber:x:data");
+	xdata->addAttribute("type","result");
+	
+	Tag *reported = new Tag("reported");
+	
+	Tag *field = new Tag("field");
+	field->addAttribute("var","jid");
+	field->addAttribute("label","Jabber ID");
+	field->addAttribute("type","jid-single");
+	reported->addChild(field);
+
+	for (columniter = results->columns; columniter != NULL; columniter = columniter->next) {
+		PurpleNotifySearchColumn *column = (PurpleNotifySearchColumn *) columniter->data;
+		if (column) {
+			std::string c(column->title);
+			field = new Tag("field");
+			field->addAttribute("var",c);
+			field->addAttribute("label",c);
+			field->addAttribute("type","text-single");
+			reported->addChild(field);
+			columns[i] = c;
+		}
+		i++;
+	}
+	
+	xdata->addChild(reported);
+	std::string IDColumn = main->protocol()->userSearchColumn();
+	
+	for (row = results->rows; row != NULL; row = row->next) {
+		Tag *item = new Tag("item");
+		i = 0;
+		for (column = (GList *) row->data; column != NULL; column = column->next) {
+			if (column->data) {
+				std::string columnText((const char *) column->data);
+				Tag *value = new Tag("value", columnText);
+				field = new Tag("field");
+				field->addAttribute("var", columns[i]);
+				field->addChild(value);
+				item->addChild(field);
+				if (columns[i] == IDColumn) {
+					value = new Tag("value", columnText + "@" + main->jid());
+					field = new Tag("field");
+					field->addAttribute("var", "jid");
+					field->addChild(value);
+					item->addChild(field);
+				}
+			}
+			i++;
+		}
+		xdata->addChild(item);
+	}
+
+	query->addChild(xdata);
+	response->addChild(query);
+	main->j->send(response);
+
+	g_timeout_add(0,&removeRepeater,this);
+}
+
+bool SearchRepeater::handleIq(const IQ &stanza) {
+	Tag *stanzaTag = stanza.tag();
+	if (!stanzaTag) return false;
+
+	Tag * tag = stanzaTag->findChild("query");
+
+	Tag *x = tag->findChildWithAttrib("xmlns","jabber:x:data");
+	if (x) {
+		std::string result("");
+		for(std::list<Tag*>::const_iterator it = x->children().begin(); it != x->children().end(); ++it){
+			if ((*it)->hasAttribute("var","result")){
+				result = (*it)->findChild("value")->cdata();
+				break;
+			}
+		}
+
+		if (m_type == PURPLE_REQUEST_INPUT) {
+			((PurpleRequestInputCb) m_ok_cb)(m_requestData, result.c_str());
+		}
+				
+	}
+
+	m_lastTag = stanzaTag;
+	return false;
+}
+
============================================================
--- searchrepeater.h	47dc0a40ec702402816130b6a389ab806b81906a
+++ searchrepeater.h	47dc0a40ec702402816130b6a389ab806b81906a
@@ -0,0 +1,58 @@
+/**
+ * XMPP - libpurple transport
+ *
+ * Copyright (C) 2009, Jan Kaluza <hanzz at 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 _HI_SEARCH_REPEATER_H
+#define _HI_SEARCH_REPEATER_H
+
+#include <string>
+#include "account.h"
+#include "user.h"
+#include "glib.h"
+#include "request.h"
+#include "abstractpurplerequest.h"
+
+class GlooxMessageHandler;
+class User;
+
+class SearchRepeater : public AbstractPurpleRequest
+{
+	public:
+		SearchRepeater(GlooxMessageHandler *m, User *user, const std::string &title, const std::string &primaryString, const std::string &secondaryString, const std::string &value, gboolean multiline, gboolean masked, GCallback ok_cb, GCallback cancel_cb, void * user_data);
+		~SearchRepeater();
+		bool handleIq(const IQ &iq);
+		void sendSearchResults(PurpleNotifySearchResults *results);
+		void setType(PurpleRequestType t) { m_type = t; }
+		PurpleRequestType type() { return m_type; }
+		std::string & from() { return m_from; }
+	
+	private:
+		GlooxMessageHandler *main;
+		User *m_user;
+		Tag *m_lastTag;
+		void *m_requestData;
+		GCallback m_ok_cb;
+		GCallback m_cancel_cb;
+		PurpleRequestType m_type;
+		std::string m_from;
+		std::map<int, GCallback> m_actions;
+};
+
+#endif
+ 
\ No newline at end of file
============================================================
--- CMakeLists.txt	c2244a1c346875818ea8a2baafa183292d1e5313
+++ CMakeLists.txt	d88485fb15b2dd1d59bc694ffa5e0bb02ac72aa0
@@ -91,6 +91,8 @@
 	localization.cpp
 	muchandler.cpp
 	adhocsettings.cpp
+	searchhandler.cpp
+	searchrepeater.cpp
 	protocols/icq.cpp
 	protocols/facebook.cpp
 	protocols/gg.cpp
@@ -124,6 +126,9 @@
 	muchandler.h
 	adhoccommandhandler.h
 	adhocsettings.h
+	searchhandler.h
+	searchrepeater.h
+	abstractpurplerequest.h
 	protocols/abstractprotocol.h
 	protocols/icq.h
 	protocols/facebook.h
============================================================
--- adhoccommandhandler.h	2ff3ec88623eda46ab09f2a45b31dcc8fed54972
+++ adhoccommandhandler.h	3c0a4061d00f0a2302bc710077fff322b67eabb8
@@ -25,15 +25,17 @@
 #include <list>
 #include "glib.h"
 #include "gloox/iq.h"
+#include "abstractpurplerequest.h"
 
 using namespace gloox;
 
-class AdhocCommandHandler
+class AdhocCommandHandler : public AbstractPurpleRequest
 {
 	public:
 		virtual ~AdhocCommandHandler() {}
 
 		virtual bool handleIq(const IQ &iq) = 0;
+		virtual std::string & from() = 0;
 };
 
 #endif
============================================================
--- adhochandler.cpp	b978791f34b7a879fa9416525df64ba0eb5cb8ef
+++ adhochandler.cpp	73823e6a0d046f49df17b59161348fb02a829529
@@ -168,6 +168,7 @@ bool GlooxAdhocHandler::handleIq( const 
 								data.id = stanza.id();
 								data.from = stanza.from().full();
 								data.node = node;
+								data.callerType = CALLER_ADHOC;
 								user->setAdhocData(data);
 								action->plugin = plugin;
 								action->context = gc;
============================================================
--- adhocrepeater.cpp	32579e7a71c4f4bba6f3c2bffd7ee33502889529
+++ adhocrepeater.cpp	5e26e9b73e6d7498466932e4ee840641deb450f4
@@ -39,6 +39,7 @@ AdhocRepeater::AdhocRepeater(GlooxMessag
 	m_from = data.from;
 	
 	setType(PURPLE_REQUEST_INPUT);
+	setRequestType(CALLER_ADHOC);
 	
 	IQ _response(IQ::Result, data.from, data.id);
 	Tag *response = _response.tag();
@@ -84,6 +85,7 @@ AdhocRepeater::AdhocRepeater(GlooxMessag
 	m_requestData = user_data;
 	AdhocData data = user->adhocData();
 	m_from = data.from;
+	setRequestType(CALLER_ADHOC);
 //       <field type='list-single'
 //              label='Maximum number of subscribers'
 //              var='maxsubs'>
============================================================
--- adhocrepeater.h	579e6f42bcb123ea182300bdf7a7acbf26fab1f8
+++ adhocrepeater.h	4fdd4851f783ccaf563d64c88ce2b0e4df27d176
@@ -40,7 +40,7 @@ class AdhocRepeater : public AdhocComman
 		bool handleIq(const IQ &iq);
 		void setType(PurpleRequestType t) { m_type = t; }
 		PurpleRequestType type() { return m_type; }
-		std::string from() { return m_from; }
+		std::string & from() { return m_from; }
 	
 	private:
 		GlooxMessageHandler *main;
============================================================
--- adhocsettings.cpp	5eb4f8ad9a7dc72bf4828c5e708cfc53ae41c49f
+++ adhocsettings.cpp	0bc07fb98f2bacc89a4ebd68b50c6fbc6be56638
@@ -28,6 +28,8 @@ AdhocSettings::AdhocSettings(GlooxMessag
 	m_user = user;
 	PurpleValue *value;
 	Tag *field;
+	m_from = std::string(from);
+	setRequestType(CALLER_ADHOC);
 	
 	IQ _response(IQ::Result, from, id);
 	Tag *response = _response.tag();
============================================================
--- adhocsettings.h	f50f758f65f66b644f845eefa307e060a8a407bb
+++ adhocsettings.h	7440af0914d36c4159d6a102869c842914d004e6
@@ -37,9 +37,11 @@ class AdhocSettings : public AdhocComman
 		AdhocSettings(GlooxMessageHandler *m, User *user, const std::string &from, const std::string &id);
 		~AdhocSettings();
 		bool handleIq(const IQ &iq);
+		std::string & from() { return m_from; }
 	
 	private:
 		GlooxMessageHandler *main;
+		std::string m_from;
 		User *m_user;
 };
 
============================================================
--- main.cpp	6e913f09e3b6250d6f318eb8c25df021c8e5aeee
+++ main.cpp	bea78c0670edeb7b44112511498223bcbcfdc9d9
@@ -26,6 +26,8 @@
 #include "usermanager.h"
 #include "adhochandler.h"
 #include "adhocrepeater.h"
+#include "searchhandler.h"
+#include "searchrepeater.h"
 #include "protocols/abstractprotocol.h"
 #include "protocols/icq.h"
 #include "protocols/facebook.h"
@@ -230,12 +232,23 @@ static void * requestInput(const char *t
 		User *user = GlooxMessageHandler::instance()->userManager()->getUserByAccount(account);
 		if (!user) return NULL;
 		if (!user->adhocData().id.empty()) {
-			AdhocRepeater *repeater = new AdhocRepeater(GlooxMessageHandler::instance(), user, title ? std::string(title):std::string(), primaryString, secondary ? std::string(secondary):std::string(), default_value ? std::string(default_value):std::string(), multiline, masked, ok_cb, cancel_cb, user_data);
-			GlooxMessageHandler::instance()->adhoc()->registerSession(user->adhocData().from, repeater);
-			AdhocData data;
-			data.id="";
-			user->setAdhocData(data);
-			return repeater;
+			if (user->adhocData().callerType == CALLER_ADHOC) {
+				AdhocRepeater *repeater = new AdhocRepeater(GlooxMessageHandler::instance(), user, title ? std::string(title):std::string(), primaryString, secondary ? std::string(secondary):std::string(), default_value ? std::string(default_value):std::string(), multiline, masked, ok_cb, cancel_cb, user_data);
+				GlooxMessageHandler::instance()->adhoc()->registerSession(user->adhocData().from, repeater);
+				AdhocData data;
+				data.id="";
+				user->setAdhocData(data);
+				return repeater;
+			}
+			else if (user->adhocData().callerType == CALLER_SEARCH) {
+				SearchRepeater *repeater = new SearchRepeater(GlooxMessageHandler::instance(), user, title ? std::string(title):std::string(), primaryString, secondary ? std::string(secondary):std::string(), default_value ? std::string(default_value):std::string(), multiline, masked, ok_cb, cancel_cb, user_data);
+				GlooxMessageHandler::instance()->searchHandler()->registerSession(user->adhocData().from, repeater);
+// 				AdhocData data;
+// 				data.id="";
+// 				user->setAdhocData(data);
+				return repeater;
+			}
+
 		}
 		else {
 			if (primaryString=="Authorization Request Message:") {
@@ -253,6 +266,20 @@ static void * requestInput(const char *t
 	return NULL;
 }
 
+static void * notifySearchResults(PurpleConnection *gc, const char *title, const char *primary, const char *secondary, PurpleNotifySearchResults *results, gpointer user_data) {
+	User *user = GlooxMessageHandler::instance()->userManager()->getUserByAccount(purple_connection_get_account(gc));
+	if (!user) return NULL;
+	if (!user->adhocData().id.empty()) {
+		if (user->adhocData().callerType == CALLER_SEARCH) {
+			GlooxMessageHandler::instance()->searchHandler()->searchResultsArrived(user->adhocData().from, results);
+			AdhocData data;
+			data.id="";
+			user->setAdhocData(data);
+		}
+	}
+	return NULL;
+}
+
 static void * requestAction(const char *title, const char *primary,const char *secondary, int default_action,PurpleAccount *account, const char *who,PurpleConversation *conv, void *user_data,size_t action_count, va_list actions){
 	User *user = GlooxMessageHandler::instance()->userManager()->getUserByAccount(account);
 	if (user && !user->adhocData().id.empty()) {
@@ -276,10 +303,19 @@ static void requestClose(PurpleRequestTy
 
 static void requestClose(PurpleRequestType type, void *ui_handle) {
 	if (type == PURPLE_REQUEST_INPUT) {
-		AdhocRepeater *repeater = (AdhocRepeater *) ui_handle;
-		std::string from = repeater->from();
-		GlooxMessageHandler::instance()->adhoc()->unregisterSession(from);
-		delete repeater;
+		AbstractPurpleRequest *r = (AbstractPurpleRequest *) ui_handle;
+		if (r->requestType() == CALLER_ADHOC) {
+			AdhocCommandHandler * repeater = (AdhocCommandHandler *) r;
+			std::string from = repeater->from();
+			GlooxMessageHandler::instance()->adhoc()->unregisterSession(from);
+			delete repeater;
+		}
+		else if (r->requestType() == CALLER_SEARCH) {
+			SearchRepeater * repeater = (SearchRepeater *) r;
+			std::string from = repeater->from();
+			GlooxMessageHandler::instance()->searchHandler()->unregisterSession(from);
+			delete repeater;
+		}
 	}
 }
 
@@ -370,8 +406,8 @@ static PurpleNotifyUiOps notifyUiOps =
 		notifyEmail,
 		NULL,
 		NULL,
+		notifySearchResults,
 		NULL,
-		NULL,
 		notify_user_info,
 		NULL,
 		NULL,
@@ -570,6 +606,7 @@ GlooxMessageHandler::GlooxMessageHandler
 
 	m_sql = new SQLClass(this);
 	m_userManager = new UserManager(this);
+	m_searchHandler = NULL;
 
 	initPurple();
 	loadProtocol();
@@ -635,21 +672,10 @@ void GlooxMessageHandler::loadProtocol()
 		m_protocol = (AbstractProtocol*) new MSNProtocol(this);
 	else if (configuration().protocol == "irc")
 		m_protocol = (AbstractProtocol*) new IRCProtocol(this);
-// 	PurplePlugin *plugin = purple_find_prpl(m_protocol->protocol().c_str());
-// 	if (plugin && PURPLE_PLUGIN_HAS_ACTIONS(plugin)) {
-// 		PurplePluginAction *action = NULL;
-// 		GList *actions, *l;
-// 
-// 		actions = PURPLE_PLUGIN_ACTIONS(plugin, gc);
-// 
-// 		for (l = actions; l != NULL; l = l->next) {
-// 			if (l->data) {
-// 				action = (PurplePluginAction *) l->data;
-// 				m_adhoc->registerAdhocCommandProvider(adhocProvider, (std::string) action->label ,(std::string) action->label);
-// 				purple_plugin_action_free(action);
-// 			}
-// 		}
-// 	}
+	if (!m_protocol->userSearchAction().empty()) {
+		m_searchHandler = new GlooxSearchHandler(this);
+		j->registerIqHandler(m_searchHandler, ExtSearch);
+	}
 }
 
 void GlooxMessageHandler::onSessionCreateError (SessionCreateError error){
============================================================
--- main.h	3a5d4b88ab334ddd8b6004179607b72b6e21770c
+++ main.h	fad25b75f97770f0e3f5f8a40e7b1c0ac57261ac
@@ -97,6 +97,7 @@ class AdhocRepeater;
 class AbstractProtocol;
 // class AdhocHandler;
 class AdhocRepeater;
+class GlooxSearchHandler;
 
 struct User;
 struct UserRow;
@@ -200,6 +201,7 @@ public:
 	GlooxVCardHandler *vcard() { return m_vcard; }
 	AbstractProtocol *protocol() { return m_protocol; }
 	GlooxAdhocHandler *adhoc() { return m_adhoc; }
+	GlooxSearchHandler *searchHandler() { return m_searchHandler; }
 	
 	FileTransferManager* ftManager;
 	SIProfileFT* ft;
@@ -231,6 +233,7 @@ private:
 	GlooxXPingHandler *m_xping;
 	GlooxStatsHandler *m_stats;
 	GlooxVCardHandler *m_vcard;
+	GlooxSearchHandler *m_searchHandler;
 // 	std::list <GlooxAdhocHandler *> m_adhoc_handlers;
 	GlooxAdhocHandler *m_adhoc;
 	
============================================================
--- protocols/abstractprotocol.h	40e96f5fedad83c1d88b78f0d1d136a5543c9958
+++ protocols/abstractprotocol.h	f544b2fbcf8106db79f976d1ebaea8d22c5821fb
@@ -73,6 +73,14 @@ class AbstractProtocol
 		 * Returns the username of contact from which notifications will be sent
 		 */
 		virtual std::string notifyUsername() { return ""; }
+		/*
+		 * Returns the name of protocol actions for user search or empty string if there is not any
+		 */
+		virtual std::string userSearchAction() { return ""; }
+		/*
+		 * Returns ID of column used for UIN/name/ID of founded users in searchresults
+		 */
+		virtual std::string userSearchColumn() { return ""; }
 };
 
 #endif
============================================================
--- protocols/facebook.cpp	920d502b4fe0a4e5395baaf6f2d2485ac0b5ffd6
+++ protocols/facebook.cpp	29b0a4684dbd71637ad8d1ecb789a238d4373f60
@@ -29,6 +29,7 @@ FacebookProtocol::FacebookProtocol(Gloox
 	m_transportFeatures.push_back("http://jabber.org/protocol/chatstates");
 	m_transportFeatures.push_back("http://jabber.org/protocol/activity+notify");
 	m_transportFeatures.push_back("http://jabber.org/protocol/commands");
+	m_transportFeatures.push_back("jabber:iq:search");
 	
 	m_buddyFeatures.push_back("http://jabber.org/protocol/disco#info");
 	m_buddyFeatures.push_back("http://jabber.org/protocol/caps");
============================================================
--- protocols/facebook.h	8fe7c732eb015a334d8e9d7631d197cc9c98d5b4
+++ protocols/facebook.h	6006a42c2e131464efd8e9cbcf0dac9f82fae808
@@ -31,7 +31,7 @@ class FacebookProtocol : AbstractProtoco
 	public:
 		FacebookProtocol(GlooxMessageHandler *main);
 		~FacebookProtocol();
-		std::string gatewayIdentity() { return "fb"; }
+		std::string gatewayIdentity() { return "facebook"; }
 		std::string protocol() { return "prpl-bigbrownchunx-facebookim"; }
 		bool isValidUsername(std::string &username);
 		std::string prepareUserName(std::string &username);
@@ -41,8 +41,10 @@ class FacebookProtocol : AbstractProtoco
 		Tag *getVCardTag(User *user, GList *vcardEntries);
 		bool isMUC(User *user, const std::string &jid) { return false; }
 		std::string notifyUsername() { return "info"; }
+		std::string userSearchAction() { return "Search for buddies..."; }
 		
 		std::string replace(std::string &str, const char *string_to_replace, const char *new_string);
+		std::string userSearchColumn() { return "ID"; }
 	
 	private:
 		GlooxMessageHandler *m_main;
============================================================
--- statshandler.cpp	8c90bb62f61eec8e23008d23caa0932db6f8e6ff
+++ statshandler.cpp	177fd164b290c7fbfc059ae3eeb5cd86a4c11a76
@@ -29,7 +29,7 @@
 #include "sql.h"
 #include <sstream>
 
-StatsExtension::StatsExtension() : StanzaExtension( ExtGateway )
+StatsExtension::StatsExtension() : StanzaExtension( ExtStats )
 {
 	m_tag = NULL;
 }
============================================================
--- user.h	3d792633ded3e60107cb97410a2816cc1bc924d7
+++ user.h	778fae39a0d134a39feac04c54b723826b10d9f6
@@ -35,10 +35,15 @@ using namespace gloox;
 
 using namespace gloox;
 
+typedef enum { 	CALLER_ADHOC,
+				CALLER_SEARCH
+				} AdhocDataCallerType;
+
 struct AdhocData {
 	std::string id;
 	std::string from;
 	std::string node;
+	AdhocDataCallerType callerType;
 };
 
 struct authData{


More information about the Commits mailing list