diff src/protocols/jabber/buddy.c @ 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 9ddda2a86f50
children ecd471d1eeec
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);
+}