changeset 11675:828802f2251b

[gaim-migrate @ 13961] Jabber User Directory searching... This works when the stars are aligned, and breaks otherwise. It hasn't been tested on any "x:data" supporting servers (because I don't know of any yet). It doesn't let you know if there was an error. Really, it doesn't do a lot of things. But you can search. You do get results. The results themselves, however, are a tad off. users.jabber.org is sending back results along the lines of: <nick>faceprint@faceprint.com</nick><email>faceprint</email> which is obviously switched. I'll ping the appropriate people to figure that out. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Mon, 17 Oct 2005 01:43:09 +0000
parents e860157296d4
children 0c54f9b0e67c
files src/protocols/jabber/buddy.c src/protocols/jabber/buddy.h src/protocols/jabber/disco.c src/protocols/jabber/jabber.c src/protocols/jabber/jabber.h
diffstat 5 files changed, 275 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/protocols/jabber/buddy.c	Sun Oct 16 18:26:32 2005 +0000
+++ b/src/protocols/jabber/buddy.c	Mon Oct 17 01:43:09 2005 +0000
@@ -33,6 +33,7 @@
 #include "jabber.h"
 #include "iq.h"
 #include "presence.h"
+#include "xdata.h"
 
 void jabber_buddy_free(JabberBuddy *jb)
 {
@@ -1140,3 +1141,253 @@
 	}
 	return NULL;
 }
+
+static void user_search_result_add_buddy_cb(GaimConnection *gc, GList *row)
+{
+	/* XXX find out the jid */
+	gaim_blist_request_add_buddy(gaim_connection_get_account(gc),
+			g_list_nth_data(row, 0), NULL, NULL);
+}
+
+static void user_search_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	GaimNotifySearchResults *results;
+	GaimNotifySearchColumn *column;
+	xmlnode *x, *query, *item, *field;
+
+	/* XXX error checking? */
+	if(!(query = xmlnode_get_child(packet, "query")))
+		return;
+
+	results = gaim_notify_searchresults_new();
+	if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) {
+		xmlnode *reported;
+		gaim_debug_info("jabber", "new-skool\n");
+		if((reported = xmlnode_get_child(x, "reported"))) {
+			xmlnode *field = xmlnode_get_child(reported, "field");
+			while(field) {
+				/* XXX keep track of this order, use it below */
+				const char *var = xmlnode_get_attrib(field, "var");
+				const char *label = xmlnode_get_attrib(field, "label");
+				if(var) {
+					column = gaim_notify_searchresults_column_new(label ? label : var);
+					gaim_notify_searchresults_column_add(results, column);
+				}
+				field = xmlnode_get_next_twin(field);
+			}
+		}
+		item = xmlnode_get_child(x, "item");
+		while(item) {
+			GList *row = NULL;
+			field = xmlnode_get_child(item, "field");
+			while(field) {
+				xmlnode *valuenode = xmlnode_get_child(item, "value");
+				if(valuenode) {
+					char *value = xmlnode_get_data(valuenode);
+					row = g_list_append(row, value);
+				}
+				field = xmlnode_get_next_twin(field);
+			}
+			gaim_notify_searchresults_row_add(results, row);
+
+			item = xmlnode_get_next_twin(item);
+		}
+	} else {
+		/* old skool */
+		gaim_debug_info("jabber", "old-skool\n");
+
+		column = gaim_notify_searchresults_column_new("JID");
+		gaim_notify_searchresults_column_add(results, column);
+		column = gaim_notify_searchresults_column_new("First");
+		gaim_notify_searchresults_column_add(results, column);
+		column = gaim_notify_searchresults_column_new("Last");
+		gaim_notify_searchresults_column_add(results, column);
+		column = gaim_notify_searchresults_column_new("Nickname");
+		gaim_notify_searchresults_column_add(results, column);
+		column = gaim_notify_searchresults_column_new("E-Mail");
+		gaim_notify_searchresults_column_add(results, column);
+
+		for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item)) {
+			const char *jid;
+			xmlnode *node;
+			GList *row = NULL;
+
+			if(!(jid = xmlnode_get_attrib(item, "jid")))
+				continue;
+
+			row = g_list_append(row, g_strdup(jid));
+			node = xmlnode_get_child(item, "first");
+			row = g_list_append(row, node ? xmlnode_get_data(node) : NULL);
+			node = xmlnode_get_child(item, "last");
+			row = g_list_append(row, node ? xmlnode_get_data(node) : NULL);
+			node = xmlnode_get_child(item, "nick");
+			row = g_list_append(row, node ? xmlnode_get_data(node) : NULL);
+			node = xmlnode_get_child(item, "email");
+			row = g_list_append(row, node ? xmlnode_get_data(node) : NULL);
+			gaim_debug_info("jabber", "row=%d\n", row);
+			gaim_notify_searchresults_row_add(results, row);
+		}
+	}
+
+	gaim_notify_searchresults_button_add(results, GAIM_NOTIFY_BUTTON_ADD_BUDDY,
+			user_search_result_add_buddy_cb);
+
+	gaim_notify_searchresults(js->gc, NULL, NULL, _("The following are the results of your search"), results, NULL, NULL);
+}
+
+static void user_search_x_data_cb(JabberStream *js, xmlnode *result, gpointer data)
+{
+	xmlnode *query;
+	JabberIq *iq;
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search");
+	query = xmlnode_get_child(iq->node, "query");
+
+	xmlnode_insert_child(query, result);
+
+	jabber_iq_set_callback(iq, user_search_result_cb, NULL);
+	jabber_iq_send(iq);
+}
+
+struct user_search_info {
+	JabberStream *js;
+	char *directory_server;
+};
+
+static void user_search_cancel_cb(struct user_search_info *usi, GaimRequestFields *fields)
+{
+	g_free(usi->directory_server);
+	g_free(usi);
+}
+
+static void user_search_cb(struct user_search_info *usi, GaimRequestFields *fields)
+{
+	JabberStream *js = usi->js;
+	JabberIq *iq;
+	xmlnode *query;
+	GList *groups, *flds;
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:search");
+	query = xmlnode_get_child(iq->node, "query");
+
+	for(groups = gaim_request_fields_get_groups(fields); groups; groups = groups->next) {
+		for(flds = gaim_request_field_group_get_fields(groups->data);
+				flds; flds = flds->next) {
+			GaimRequestField *field = flds->data;
+			const char *id = gaim_request_field_get_id(field);
+			const char *value = gaim_request_field_string_get_value(field);
+
+			if(value && (!strcmp(id, "first") || !strcmp(id, "last") || !strcmp(id, "nick") || !strcmp(id, "email"))) {
+				xmlnode *y = xmlnode_new_child(query, id);
+				xmlnode_insert_data(y, value, -1);
+			}
+		}
+	}
+
+	jabber_iq_set_callback(iq, user_search_result_cb, NULL);
+	xmlnode_set_attrib(iq->node, "to", usi->directory_server);
+	jabber_iq_send(iq);
+
+	g_free(usi->directory_server);
+	g_free(usi);
+}
+
+static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+{
+	xmlnode *query, *x;
+	const char *from;
+
+	/* i forget, do i have to check for error? XXX */
+	if(!(from= xmlnode_get_attrib(packet, "from")))
+		return;
+
+
+	if(!(query = xmlnode_get_child(packet, "query")))
+		return;
+
+	if((x = xmlnode_get_child_with_namespace(packet, "x", "jabber:x:data"))) {
+		jabber_x_data_request(js, x, user_search_x_data_cb, NULL);
+		return;
+	} else {
+		struct user_search_info *usi;
+		xmlnode *instnode;
+		char *instructions;
+		GaimRequestFields *fields;
+		GaimRequestFieldGroup *group;
+		GaimRequestField *field;
+
+		/* old skool */
+		fields = gaim_request_fields_new();
+		group = gaim_request_field_group_new(NULL);
+		gaim_request_fields_add_group(fields, group);
+
+		if((instnode = xmlnode_get_child(query, "instructions")))
+			instructions = xmlnode_get_data(instnode);
+		else
+			instructions = g_strdup(_("Fill in one or more fields to search "
+						"for any matching Jabber users."));
+
+		if(xmlnode_get_child(query, "first")) {
+			field = gaim_request_field_string_new("first", _("First Name"),
+					NULL, FALSE);
+			gaim_request_field_group_add_field(group, field);
+		}
+		if(xmlnode_get_child(query, "last")) {
+			field = gaim_request_field_string_new("last", _("Last Name"),
+					NULL, FALSE);
+			gaim_request_field_group_add_field(group, field);
+		}
+		if(xmlnode_get_child(query, "nick")) {
+			field = gaim_request_field_string_new("nick", _("Nickname"),
+					NULL, FALSE);
+			gaim_request_field_group_add_field(group, field);
+		}
+		if(xmlnode_get_child(query, "email")) {
+			field = gaim_request_field_string_new("email", _("E-Mail Address"),
+					NULL, FALSE);
+			gaim_request_field_group_add_field(group, field);
+		}
+
+		usi = g_new0(struct user_search_info, 1);
+		usi->js = js;
+		usi->directory_server = g_strdup(from);
+
+		gaim_request_fields(js->gc, _("Search for Jabber users"),
+				_("Search for Jabber users"), instructions, fields,
+				_("Search"), G_CALLBACK(user_search_cb),
+				_("Cancel"), G_CALLBACK(user_search_cancel_cb), usi);
+
+		g_free(instructions);
+	}
+}
+
+static void jabber_user_search_ok(JabberStream *js, const char *directory)
+{
+	JabberIq *iq;
+
+	/* XXX: should probably better validate the directory we're given */
+	if(!directory || !*directory) {
+		gaim_notify_error(js->gc, _("Invalid Directory"), _("Invalid Directory"), NULL);
+		return;
+	}
+
+	iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:search");
+	xmlnode_set_attrib(iq->node, "to", directory);
+
+	jabber_iq_set_callback(iq, user_search_fields_result_cb, NULL);
+
+	jabber_iq_send(iq);
+}
+
+void jabber_user_search_begin(GaimPluginAction *action)
+{
+	GaimConnection *gc = (GaimConnection *) action->context;
+	JabberStream *js = gc->proto_data;
+
+	gaim_request_input(gc, _("Enter a User Directory"), _("Enter a User Directory"),
+			_("Select a user directory to search"),
+			js->user_directories ? js->user_directories->data : "users.jabber.org",
+			FALSE, FALSE, NULL,
+			_("Search Directory"), GAIM_CALLBACK(jabber_user_search_ok),
+			_("Cancel"), NULL, js);
+}
--- a/src/protocols/jabber/buddy.h	Sun Oct 16 18:26:32 2005 +0000
+++ b/src/protocols/jabber/buddy.h	Mon Oct 17 01:43:09 2005 +0000
@@ -87,4 +87,6 @@
 const char *jabber_buddy_state_get_status_id(JabberBuddyState state);
 JabberBuddyState jabber_buddy_status_id_get_state(const char *id);
 
+void jabber_user_search_begin(GaimPluginAction *);
+
 #endif /* _GAIM_JABBER_BUDDY_H_ */
--- a/src/protocols/jabber/disco.c	Sun Oct 16 18:26:32 2005 +0000
+++ b/src/protocols/jabber/disco.c	Mon Oct 17 01:43:09 2005 +0000
@@ -106,10 +106,14 @@
 				if(!category || !type)
 					continue;
 
-				/* we found a groupchat or MUC server, add it to the list */
-				/* XXX: actually check for protocol/muc or gc-1.0 support */
-				if(!strcmp(category, "conference") && !strcmp(type, "text"))
+				if(!strcmp(category, "conference") && !strcmp(type, "text")) {
+					/* we found a groupchat or MUC server, add it to the list */
+					/* XXX: actually check for protocol/muc or gc-1.0 support */
 					js->chat_servers = g_list_append(js->chat_servers, g_strdup(from));
+				} else if(!strcmp(category, "directory") && !strcmp(type, "user")) {
+					/* we found a JUD */
+					js->user_directories = g_list_append(js->user_directories, g_strdup(from));
+				}
 
 			} else if(!strcmp(child->name, "feature")) {
 				const char *var = xmlnode_get_attrib(child, "var");
@@ -122,6 +126,10 @@
 					capabilities |= JABBER_CAP_SI_FILE_XFER;
 				else if(!strcmp(var, "http://jabber.org/protocol/bytestreams"))
 					capabilities |= JABBER_CAP_BYTESTREAMS;
+				else if(!strcmp(var, "jabber:iq:search"))
+					capabilities |= JABBER_CAP_IQ_SEARCH;
+				else if(!strcmp(var, "jabber:iq:register"))
+					capabilities |= JABBER_CAP_IQ_REGISTER;
 			}
 		}
 
--- a/src/protocols/jabber/jabber.c	Sun Oct 16 18:26:32 2005 +0000
+++ b/src/protocols/jabber/jabber.c	Mon Oct 17 01:43:09 2005 +0000
@@ -810,6 +810,10 @@
 		g_free(js->chat_servers->data);
 		js->chat_servers = g_list_delete_link(js->chat_servers, js->chat_servers);
 	}
+	while(js->user_directories) {
+		g_free(js->user_directories->data);
+		js->user_directories = g_list_delete_link(js->user_directories, js->user_directories);
+	}
 	if(js->stream_id)
 		g_free(js->stream_id);
 	if(js->user)
@@ -1174,6 +1178,10 @@
 		m = g_list_append(m, act);
 	/* } */
 
+	act = gaim_plugin_action_new(_("Search for users"),
+			jabber_user_search_begin);
+	m = g_list_append(m, act);
+
 	return m;
 }
 
--- a/src/protocols/jabber/jabber.h	Sun Oct 16 18:26:32 2005 +0000
+++ b/src/protocols/jabber/jabber.h	Mon Oct 17 01:43:09 2005 +0000
@@ -39,6 +39,8 @@
 	JABBER_CAP_BYTESTREAMS    = 1 << 4,
 	JABBER_CAP_IBB            = 1 << 5,
 	JABBER_CAP_CHAT_STATES    = 1 << 6,
+	JABBER_CAP_IQ_SEARCH      = 1 << 7,
+	JABBER_CAP_IQ_REGISTER    = 1 << 8,
 	JABBER_CAP_RETRIEVED      = 1 << 31
 } JabberCapabilities;
 
@@ -80,6 +82,7 @@
 	GHashTable *chats;
 	GList *chat_servers;
 	GaimRoomlist *roomlist;
+	GList *user_directories;
 
 	GHashTable *iq_callbacks;
 	GHashTable *disco_callbacks;