src/protocols/jabber/buddy.c

changeset 14253
b63ebf84c42b
parent 14252
d10dda2777a9
child 14254
77edc7a6191a
--- a/src/protocols/jabber/buddy.c	Sat Aug 19 00:24:14 2006 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1765 +0,0 @@
-/*
- * gaim - Jabber Protocol Plugin
- *
- * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-#include "internal.h"
-#include "cipher.h"
-#include "debug.h"
-#include "imgstore.h"
-#include "prpl.h"
-#include "notify.h"
-#include "request.h"
-#include "util.h"
-#include "xmlnode.h"
-
-#include "buddy.h"
-#include "chat.h"
-#include "jabber.h"
-#include "iq.h"
-#include "presence.h"
-#include "xdata.h"
-
-typedef struct {
-	long idle_seconds;
-} JabberBuddyInfoResource;
-
-typedef struct {
-	JabberStream *js;
-	JabberBuddy *jb;
-	char *jid;
-	GSList *ids;
-	GHashTable *resources;
-	int timeout_handle;
-	char *vcard_text;
-	GSList *vcard_imgids;
-} JabberBuddyInfo;
-
-void jabber_buddy_free(JabberBuddy *jb)
-{
-	g_return_if_fail(jb != NULL);
-
-	if(jb->error_msg)
-		g_free(jb->error_msg);
-	while(jb->resources)
-		jabber_buddy_resource_free(jb->resources->data);
-
-	g_free(jb);
-}
-
-JabberBuddy *jabber_buddy_find(JabberStream *js, const char *name,
-		gboolean create)
-{
-	JabberBuddy *jb;
-	const char *realname;
-
-	if(!(realname = jabber_normalize(js->gc->account, name)))
-		return NULL;
-
-	jb = g_hash_table_lookup(js->buddies, realname);
-
-	if(!jb && create) {
-		jb = g_new0(JabberBuddy, 1);
-		g_hash_table_insert(js->buddies, g_strdup(realname), jb);
-	}
-
-	return jb;
-}
-
-
-JabberBuddyResource *jabber_buddy_find_resource(JabberBuddy *jb,
-		const char *resource)
-{
-	JabberBuddyResource *jbr = NULL;
-	GList *l;
-
-	if(!jb)
-		return NULL;
-
-	for(l = jb->resources; l; l = l->next)
-	{
-		if(!jbr && !resource) {
-			jbr = l->data;
-		} else if(!resource) {
-			if(((JabberBuddyResource *)l->data)->priority >= jbr->priority)
-				jbr = l->data;
-		} else if(((JabberBuddyResource *)l->data)->name) {
-			if(!strcmp(((JabberBuddyResource *)l->data)->name, resource)) {
-				jbr = l->data;
-				break;
-			}
-		}
-	}
-
-	return jbr;
-}
-
-JabberBuddyResource *jabber_buddy_track_resource(JabberBuddy *jb, const char *resource,
-		int priority, JabberBuddyState state, const char *status)
-{
-	JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource);
-
-	if(!jbr) {
-		jbr = g_new0(JabberBuddyResource, 1);
-		jbr->jb = jb;
-		jbr->name = g_strdup(resource);
-		jbr->capabilities = JABBER_CAP_XHTML;
-		jb->resources = g_list_append(jb->resources, jbr);
-	}
-	jbr->priority = priority;
-	jbr->state = state;
-	if(jbr->status)
-		g_free(jbr->status);
-        if (status)
-		jbr->status = g_markup_escape_text(status, -1);
-	else
-		jbr->status = NULL;
-
-	return jbr;
-}
-
-void jabber_buddy_resource_free(JabberBuddyResource *jbr)
-{
-	g_return_if_fail(jbr != NULL);
-
-	jbr->jb->resources = g_list_remove(jbr->jb->resources, jbr);
-
-	g_free(jbr->name);
-	g_free(jbr->status);
-	g_free(jbr->thread_id);
-	g_free(jbr->client.name);
-	g_free(jbr->client.version);
-	g_free(jbr->client.os);
-	g_free(jbr);
-}
-
-void jabber_buddy_remove_resource(JabberBuddy *jb, const char *resource)
-{
-	JabberBuddyResource *jbr = jabber_buddy_find_resource(jb, resource);
-
-	if(!jbr)
-		return;
-
-	jabber_buddy_resource_free(jbr);
-}
-
-const char *jabber_buddy_get_status_msg(JabberBuddy *jb)
-{
-	JabberBuddyResource *jbr;
-
-	if(!jb)
-		return NULL;
-
-	jbr = jabber_buddy_find_resource(jb, NULL);
-
-	if(!jbr)
-		return NULL;
-
-	return jbr->status;
-}
-
-/*******
- * This is the old vCard stuff taken from the old prpl.  vCards, by definition
- * are a temporary thing until jabber can get its act together and come up
- * with a format for user information, hence the namespace of 'vcard-temp'
- *
- * Since I don't feel like putting that much work into something that's
- * _supposed_ to go away, i'm going to just copy the kludgy old code here,
- * and make it purdy when jabber comes up with a standards-track JEP to
- * replace vcard-temp
- *                                 --Nathan
- *******/
-
-/*---------------------------------------*/
-/* Jabber "set info" (vCard) support     */
-/*---------------------------------------*/
-
-/*
- * V-Card format:
- *
- *  <vCard prodid='' version='' xmlns=''>
- *    <FN></FN>
- *    <N>
- *	<FAMILY/>
- *	<GIVEN/>
- *    </N>
- *    <NICKNAME/>
- *    <URL/>
- *    <ADR>
- *	<STREET/>
- *	<EXTADD/>
- *	<LOCALITY/>
- *	<REGION/>
- *	<PCODE/>
- *	<COUNTRY/>
- *    </ADR>
- *    <TEL/>
- *    <EMAIL/>
- *    <ORG>
- *	<ORGNAME/>
- *	<ORGUNIT/>
- *    </ORG>
- *    <TITLE/>
- *    <ROLE/>
- *    <DESC/>
- *    <BDAY/>
- *  </vCard>
- *
- * See also:
- *
- *	http://docs.jabber.org/proto/html/vcard-temp.html
- *	http://www.vcard-xml.org/dtd/vCard-XML-v2-20010520.dtd
- */
-
-/*
- * Cross-reference user-friendly V-Card entry labels to vCard XML tags
- * and attributes.
- *
- * Order is (or should be) unimportant.  For example: we have no way of
- * knowing in what order real data will arrive.
- *
- * Format: Label, Pre-set text, "visible" flag, "editable" flag, XML tag
- *         name, XML tag's parent tag "path" (relative to vCard node).
- *
- *         List is terminated by a NULL label pointer.
- *
- *	   Entries with no label text, but with XML tag and parent tag
- *	   entries, are used by V-Card XML construction routines to
- *	   "automagically" construct the appropriate XML node tree.
- *
- * Thoughts on future direction/expansion
- *
- *	This is a "simple" vCard.
- *
- *	It is possible for nodes other than the "vCard" node to have
- *      attributes.  Should that prove necessary/desirable, add an
- *      "attributes" pointer to the vcard_template struct, create the
- *      necessary tag_attr structs, and add 'em to the vcard_dflt_data
- *      array.
- *
- *	The above changes will (obviously) require changes to the vCard
- *      construction routines.
- */
-
-struct vcard_template {
-	char *label;			/* label text pointer */
-	char *text;			/* entry text pointer */
-	int  visible;			/* should entry field be "visible?" */
-	int  editable;			/* should entry field be editable? */
-	char *tag;			/* tag text */
-	char *ptag;			/* parent tag "path" text */
-	char *url;			/* vCard display format if URL */
-} vcard_template_data[] = {
-	{N_("Full Name"),          NULL, TRUE, TRUE, "FN",        NULL,  NULL},
-	{N_("Family Name"),        NULL, TRUE, TRUE, "FAMILY",    "N",   NULL},
-	{N_("Given Name"),         NULL, TRUE, TRUE, "GIVEN",     "N",   NULL},
-	{N_("Nickname"),           NULL, TRUE, TRUE, "NICKNAME",  NULL,  NULL},
-	{N_("URL"),                NULL, TRUE, TRUE, "URL",       NULL,  "<A HREF=\"%s\">%s</A>"},
-	{N_("Street Address"),     NULL, TRUE, TRUE, "STREET",    "ADR", NULL},
-	{N_("Extended Address"),   NULL, TRUE, TRUE, "EXTADD",    "ADR", NULL},
-	{N_("Locality"),           NULL, TRUE, TRUE, "LOCALITY",  "ADR", NULL},
-	{N_("Region"),             NULL, TRUE, TRUE, "REGION",    "ADR", NULL},
-	{N_("Postal Code"),        NULL, TRUE, TRUE, "PCODE",     "ADR", NULL},
-	{N_("Country"),            NULL, TRUE, TRUE, "CTRY",      "ADR", NULL},
-	{N_("Telephone"),          NULL, TRUE, TRUE, "NUMBER",    "TEL",  NULL},
-	{N_("E-Mail"),             NULL, TRUE, TRUE, "USERID",    "EMAIL",  "<A HREF=\"mailto:%s\">%s</A>"},
-	{N_("Organization Name"),  NULL, TRUE, TRUE, "ORGNAME",   "ORG", NULL},
-	{N_("Organization Unit"),  NULL, TRUE, TRUE, "ORGUNIT",   "ORG", NULL},
-	{N_("Title"),              NULL, TRUE, TRUE, "TITLE",     NULL,  NULL},
-	{N_("Role"),               NULL, TRUE, TRUE, "ROLE",      NULL,  NULL},
-	{N_("Birthday"),           NULL, TRUE, TRUE, "BDAY",      NULL,  NULL},
-	{N_("Description"),        NULL, TRUE, TRUE, "DESC",      NULL,  NULL},
-	{"", NULL, TRUE, TRUE, "N",     NULL, NULL},
-	{"", NULL, TRUE, TRUE, "ADR",   NULL, NULL},
-	{"", NULL, TRUE, TRUE, "ORG",   NULL, NULL},
-	{NULL, NULL, 0, 0, NULL, NULL, NULL}
-};
-
-/*
- * The "vCard" tag's attribute list...
- */
-struct tag_attr {
-	char *attr;
-	char *value;
-} vcard_tag_attr_list[] = {
-	{"prodid",   "-//HandGen//NONSGML vGen v1.0//EN"},
-	{"version",  "2.0",                             },
-	{"xmlns",    "vcard-temp",                      },
-	{NULL, NULL},
-};
-
-
-/*
- * Insert a tag node into an xmlnode tree, recursively inserting parent tag
- * nodes as necessary
- *
- * Returns pointer to inserted node
- *
- * Note to hackers: this code is designed to be re-entrant (it's recursive--it
- * calls itself), so don't put any "static"s in here!
- */
-static xmlnode *insert_tag_to_parent_tag(xmlnode *start, const char *parent_tag, const char *new_tag)
-{
-	xmlnode *x = NULL;
-
-	/*
-	 * If the parent tag wasn't specified, see if we can get it
-	 * from the vCard template struct.
-	 */
-	if(parent_tag == NULL) {
-		struct vcard_template *vc_tp = vcard_template_data;
-
-		while(vc_tp->label != NULL) {
-			if(strcmp(vc_tp->tag, new_tag) == 0) {
-				parent_tag = vc_tp->ptag;
-				break;
-			}
-			++vc_tp;
-		}
-	}
-
-	/*
-	 * If we have a parent tag...
-	 */
-	if(parent_tag != NULL ) {
-		/*
-		 * Try to get the parent node for a tag
-		 */
-		if((x = xmlnode_get_child(start, parent_tag)) == NULL) {
-			/*
-			 * Descend?
-			 */
-			char *grand_parent = g_strdup(parent_tag);
-			char *parent;
-
-			if((parent = strrchr(grand_parent, '/')) != NULL) {
-				*(parent++) = '\0';
-				x = insert_tag_to_parent_tag(start, grand_parent, parent);
-			} else {
-				x = xmlnode_new_child(start, grand_parent);
-			}
-			g_free(grand_parent);
-		} else {
-			/*
-			 * We found *something* to be the parent node.
-			 * Note: may be the "root" node!
-			 */
-			xmlnode *y;
-			if((y = xmlnode_get_child(x, new_tag)) != NULL) {
-				return(y);
-			}
-		}
-	}
-
-	/*
-	 * insert the new tag into its parent node
-	 */
-	return(xmlnode_new_child((x == NULL? start : x), new_tag));
-}
-
-/*
- * Send vCard info to Jabber server
- */
-void jabber_set_info(GaimConnection *gc, const char *info)
-{
-	JabberIq *iq;
-	JabberStream *js = gc->proto_data;
-	xmlnode *vc_node;
-	char *avatar_file = NULL;
-	struct tag_attr *tag_attr;
-
-	if(js->avatar_hash)
-		g_free(js->avatar_hash);
-	js->avatar_hash = NULL;
-
-	/*
-	 * Send only if there's actually any *information* to send
-	 */
-	vc_node = info ? xmlnode_from_str(info, -1) : NULL;
-	avatar_file = gaim_buddy_icons_get_full_path(gaim_account_get_buddy_icon(gc->account));
-
-	if(!vc_node && avatar_file) {
-		vc_node = xmlnode_new("vCard");
-		for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr)
-			xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value);
-	}
-
-	if(vc_node) {
-		if (vc_node->name &&
-				!g_ascii_strncasecmp(vc_node->name, "vCard", 5)) {
-			GError *error = NULL;
-			gchar *avatar_data_tmp;
-			guchar *avatar_data;
-			gsize avatar_len;
-
-			if(avatar_file && g_file_get_contents(avatar_file, &avatar_data_tmp, &avatar_len, &error)) {
-				xmlnode *photo, *binval;
-				gchar *enc;
-				int i;
-				unsigned char hashval[20];
-				char *p, hash[41];
-
-				avatar_data = (guchar *) avatar_data_tmp;
-				photo = xmlnode_new_child(vc_node, "PHOTO");
-				binval = xmlnode_new_child(photo, "BINVAL");
-				enc = gaim_base64_encode(avatar_data, avatar_len);
-
-				gaim_cipher_digest_region("sha1", (guchar *)avatar_data,
-										  avatar_len, sizeof(hashval),
-										  hashval, NULL);
-
-				p = hash;
-				for(i=0; i<20; i++, p+=2)
-					snprintf(p, 3, "%02x", hashval[i]);
-				js->avatar_hash = g_strdup(hash);
-
-				xmlnode_insert_data(binval, enc, -1);
-				g_free(enc);
-				g_free(avatar_data);
-			} else if (error != NULL) {
-				g_error_free(error);
-			}
-			g_free(avatar_file);
-
-			iq = jabber_iq_new(js, JABBER_IQ_SET);
-			xmlnode_insert_child(iq->node, vc_node);
-			jabber_iq_send(iq);
-		} else {
-			xmlnode_free(vc_node);
-		}
-	}
-}
-
-void jabber_set_buddy_icon(GaimConnection *gc, const char *iconfile)
-{
-	GaimPresence *gpresence;
-	GaimStatus *status;
-
-	jabber_set_info(gc, gaim_account_get_user_info(gc->account));
-
-	gpresence = gaim_account_get_presence(gc->account);
-	status = gaim_presence_get_active_status(gpresence);
-	jabber_presence_send(gc->account, status);
-}
-
-/*
- * This is the callback from the "ok clicked" for "set vCard"
- *
- * Formats GSList data into XML-encoded string and returns a pointer
- * to said string.
- *
- * g_free()'ing the returned string space is the responsibility of
- * the caller.
- */
-static void
-jabber_format_info(GaimConnection *gc, GaimRequestFields *fields)
-{
-	xmlnode *vc_node;
-	GaimRequestField *field;
-	const char *text;
-	char *p;
-	const struct vcard_template *vc_tp;
-	struct tag_attr *tag_attr;
-
-	vc_node = xmlnode_new("vCard");
-
-	for(tag_attr = vcard_tag_attr_list; tag_attr->attr != NULL; ++tag_attr)
-		xmlnode_set_attrib(vc_node, tag_attr->attr, tag_attr->value);
-
-	for (vc_tp = vcard_template_data; vc_tp->label != NULL; vc_tp++) {
-		if (*vc_tp->label == '\0')
-			continue;
-
-		field = gaim_request_fields_get_field(fields, vc_tp->tag);
-		text  = gaim_request_field_string_get_value(field);
-
-
-		if (text != NULL && *text != '\0') {
-			xmlnode *xp;
-
-			gaim_debug(GAIM_DEBUG_INFO, "jabber",
-					"Setting %s to '%s'\n", vc_tp->tag, text);
-
-			if ((xp = insert_tag_to_parent_tag(vc_node,
-											   NULL, vc_tp->tag)) != NULL) {
-
-				xmlnode_insert_data(xp, text, -1);
-			}
-		}
-	}
-
-	p = xmlnode_to_str(vc_node, NULL);
-	xmlnode_free(vc_node);
-
-	if (gc != NULL) {
-		GaimAccount *account = gaim_connection_get_account(gc);
-
-		if (account != NULL) {
-			gaim_account_set_user_info(account, p);
-			serv_set_info(gc, p);
-		}
-	}
-
-	g_free(p);
-}
-
-/*
- * This gets executed by the proto action
- *
- * Creates a new GaimRequestFields struct, gets the XML-formatted user_info
- * string (if any) into GSLists for the (multi-entry) edit dialog and
- * calls the set_vcard dialog.
- */
-void jabber_setup_set_info(GaimPluginAction *action)
-{
-	GaimConnection *gc = (GaimConnection *) action->context;
-	GaimRequestFields *fields;
-	GaimRequestFieldGroup *group;
-	GaimRequestField *field;
-	const struct vcard_template *vc_tp;
-	const char *user_info;
-	char *cdata = NULL;
-	xmlnode *x_vc_data = NULL;
-
-	fields = gaim_request_fields_new();
-	group = gaim_request_field_group_new(NULL);
-	gaim_request_fields_add_group(fields, group);
-
-	/*
-	 * Get existing, XML-formatted, user info
-	 */
-	if((user_info = gaim_account_get_user_info(gc->account)) != NULL)
-		x_vc_data = xmlnode_from_str(user_info, -1);
-
-	/*
-	 * Set up GSLists for edit with labels from "template," data from user info
-	 */
-	for(vc_tp = vcard_template_data; vc_tp->label != NULL; ++vc_tp) {
-		xmlnode *data_node;
-		if((vc_tp->label)[0] == '\0')
-			continue;
-
-		if (x_vc_data != NULL) {
-			if(vc_tp->ptag == NULL) {
-				data_node = xmlnode_get_child(x_vc_data, vc_tp->tag);
-			} else {
-				gchar *tag = g_strdup_printf("%s/%s", vc_tp->ptag, vc_tp->tag);
-				data_node = xmlnode_get_child(x_vc_data, tag);
-				g_free(tag);
-			}
-			if(data_node)
-				cdata = xmlnode_get_data(data_node);
-		}
-
-		if(strcmp(vc_tp->tag, "DESC") == 0) {
-			field = gaim_request_field_string_new(vc_tp->tag,
-												  _(vc_tp->label), cdata,
-												  TRUE);
-		} else {
-			field = gaim_request_field_string_new(vc_tp->tag,
-												  _(vc_tp->label), cdata,
-												  FALSE);
-		}
-
-		g_free(cdata);
-		cdata = NULL;
-
-		gaim_request_field_group_add_field(group, field);
-	}
-
-	if(x_vc_data != NULL)
-		xmlnode_free(x_vc_data);
-
-	gaim_request_fields(gc, _("Edit Jabber vCard"),
-						_("Edit Jabber vCard"),
-						_("All items below are optional. Enter only the "
-						  "information with which you feel comfortable."),
-						fields,
-						_("Save"), G_CALLBACK(jabber_format_info),
-						_("Cancel"), NULL,
-						gc);
-}
-
-/*---------------------------------------*/
-/* End Jabber "set info" (vCard) support */
-/*---------------------------------------*/
-
-/******
- * end of that ancient crap that needs to die
- ******/
-
-static void jabber_buddy_info_show_if_ready(JabberBuddyInfo *jbi)
-{
-	GString *info_text;
-	char *resource_name;
-	JabberBuddyResource *jbr;
-	JabberBuddyInfoResource *jbir;
-	GList *resources;
-
-	/* not yet */
-	if(jbi->ids)
-		return;
-
-	info_text = g_string_new("");
-	resource_name = jabber_get_resource(jbi->jid);
-
-	if(resource_name) {
-		jbr = jabber_buddy_find_resource(jbi->jb, resource_name);
-		jbir = g_hash_table_lookup(jbi->resources, resource_name);
-		if(jbr) {
-			char *purdy = NULL;
-			if(jbr->status)
-				purdy = gaim_strdup_withhtml(jbr->status);
-			g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/>",
-					_("Status"), jabber_buddy_state_get_name(jbr->state),
-					purdy ? ": " : "",
-					purdy ? purdy : "");
-			if(purdy)
-				g_free(purdy);
-		} else {
-			g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-					_("Status"), _("Unknown"));
-		}
-		if(jbir) {
-			if(jbir->idle_seconds > 0) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Idle"), gaim_str_seconds_to_string(jbir->idle_seconds));
-			}
-		}
-		if(jbr && jbr->client.name) {
-			g_string_append_printf(info_text, "<b>%s:</b> %s %s<br/>",
-					_("Client:"), jbr->client.name,
-					jbr->client.version ? jbr->client.version : "");
-			if(jbr->client.os) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Operating System"), jbr->client.os);
-			}
-		}
-	} else {
-		for(resources = jbi->jb->resources; resources; resources = resources->next) {
-			char *purdy = NULL;
-			jbr = resources->data;
-			if(jbr->status)
-				purdy = gaim_strdup_withhtml(jbr->status);
-			g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-					_("Resource"), jbr->name);
-			g_string_append_printf(info_text, "<b>%s:</b> %s%s%s<br/>",
-					_("Status"), jabber_buddy_state_get_name(jbr->state),
-					purdy ? ": " : "",
-					purdy ? purdy : "");
-			if(purdy)
-				g_free(purdy);
-
-			jbir = g_hash_table_lookup(jbi->resources, jbr->name);
-			if(jbir) {
-				if(jbir->idle_seconds > 0) {
-					g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-							_("Idle"), gaim_str_seconds_to_string(jbir->idle_seconds));
-				}
-			}
-			if(jbr->client.name) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s %s<br/>",
-						_("Client"), jbr->client.name,
-						jbr->client.version ? jbr->client.version : "");
-				if(jbr->client.os) {
-					g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-							_("Operating System"), jbr->client.os);
-				}
-			}
-
-			g_string_append_printf(info_text, "<br/>");
-		}
-	}
-
-	g_free(resource_name);
-
-	if (jbi->vcard_text != NULL)
-		info_text = g_string_append(info_text, jbi->vcard_text);
-
-	gaim_notify_userinfo(jbi->js->gc, jbi->jid, info_text->str, NULL, NULL);
-
-	while(jbi->vcard_imgids) {
-		gaim_imgstore_unref(GPOINTER_TO_INT(jbi->vcard_imgids->data));
-		jbi->vcard_imgids = g_slist_delete_link(jbi->vcard_imgids, jbi->vcard_imgids);
-	}
-
-	g_string_free(info_text, TRUE);
-
-	if (jbi->timeout_handle > 0)
-		gaim_timeout_remove(jbi->timeout_handle);
-
-	g_free(jbi->jid);
-	g_hash_table_destroy(jbi->resources);
-	g_free(jbi->vcard_text);
-	g_free(jbi);
-}
-
-static void jabber_buddy_info_remove_id(JabberBuddyInfo *jbi, const char *id)
-{
-	GSList *l = jbi->ids;
-
-	if(!id)
-		return;
-
-	while(l) {
-		if(!strcmp(id, l->data)) {
-			jbi->ids = g_slist_remove(jbi->ids, l->data);
-			return;
-		}
-		l = l->next;
-	}
-}
-
-static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data)
-{
-	const char *id, *from;
-	GString *info_text;
-	char *bare_jid;
-	char *text;
-	xmlnode *vcard;
-	GaimBuddy *b;
-	JabberBuddyInfo *jbi = data;
-
-	from = xmlnode_get_attrib(packet, "from");
-	id = xmlnode_get_attrib(packet, "id");
-
-	if(!jbi)
-		return;
-
-	jabber_buddy_info_remove_id(jbi, id);
-
-	if(!from)
-		return;
-
-	if(!jabber_buddy_find(js, from, FALSE))
-		return;
-
-	/* XXX: handle the error case */
-
-	bare_jid = jabber_get_bare_jid(from);
-
-	b = gaim_find_buddy(js->gc->account, bare_jid);
-
-	info_text = g_string_new("");
-
-	if((vcard = xmlnode_get_child(packet, "vCard")) ||
-			(vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp"))) {
-		xmlnode *child;
-		for(child = vcard->child; child; child = child->next)
-		{
-			xmlnode *child2;
-
-			if(child->type != XMLNODE_TYPE_TAG)
-				continue;
-
-			text = xmlnode_get_data(child);
-			if(text && !strcmp(child->name, "FN")) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Full Name"), text);
-			} else if(!strcmp(child->name, "N")) {
-				for(child2 = child->child; child2; child2 = child2->next)
-				{
-					char *text2;
-
-					if(child2->type != XMLNODE_TYPE_TAG)
-						continue;
-
-					text2 = xmlnode_get_data(child2);
-					if(text2 && !strcmp(child2->name, "FAMILY")) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> %s<br/>",
-								_("Family Name"), text2);
-					} else if(text2 && !strcmp(child2->name, "GIVEN")) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> %s<br/>",
-								_("Given Name"), text2);
-					} else if(text2 && !strcmp(child2->name, "MIDDLE")) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> %s<br/>",
-								_("Middle Name"), text2);
-					}
-					g_free(text2);
-				}
-			} else if(text && !strcmp(child->name, "NICKNAME")) {
-				serv_got_alias(js->gc, from, text);
-				if(b) {
-					gaim_blist_node_set_string((GaimBlistNode*)b, "servernick", text);
-				}
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Nickname"), text);
-			} else if(text && !strcmp(child->name, "BDAY")) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Birthday"), text);
-			} else if(!strcmp(child->name, "ADR")) {
-				gboolean address_line_added = FALSE;
-
-				for(child2 = child->child; child2; child2 = child2->next)
-				{
-					char *text2;
-
-					if(child2->type != XMLNODE_TYPE_TAG)
-						continue;
-
-					text2 = xmlnode_get_data(child2);
-					if (text2 == NULL)
-						continue;
-
-					/* We do this here so that it's not added if all the child
-					 * elements are empty. */
-					if (!address_line_added)
-					{
-						g_string_append_printf(info_text, "<b>%s:</b><br/>",
-								_("Address"));
-						address_line_added = TRUE;
-					}
-
-					if(!strcmp(child2->name, "POBOX")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("P.O. Box"), text2);
-					} else if(!strcmp(child2->name, "EXTADR")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("Extended Address"), text2);
-					} else if(!strcmp(child2->name, "STREET")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("Street Address"), text2);
-					} else if(!strcmp(child2->name, "LOCALITY")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("Locality"), text2);
-					} else if(!strcmp(child2->name, "REGION")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("Region"), text2);
-					} else if(!strcmp(child2->name, "PCODE")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("Postal Code"), text2);
-					} else if(!strcmp(child2->name, "CTRY")
-								|| !strcmp(child2->name, "COUNTRY")) {
-						g_string_append_printf(info_text,
-								"&nbsp;<b>%s:</b> %s<br/>",
-								_("Country"), text2);
-					}
-					g_free(text2);
-				}
-			} else if(!strcmp(child->name, "TEL")) {
-				char *number;
-				if((child2 = xmlnode_get_child(child, "NUMBER"))) {
-					/* show what kind of number it is */
-					number = xmlnode_get_data(child2);
-					if(number) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> %s<br/>", _("Telephone"), number);
-						g_free(number);
-					}
-				} else if((number = xmlnode_get_data(child))) {
-					/* lots of clients (including gaim) do this, but it's
-					 * out of spec */
-					g_string_append_printf(info_text,
-							"<b>%s:</b> %s<br/>", _("Telephone"), number);
-					g_free(number);
-				}
-			} else if(!strcmp(child->name, "EMAIL")) {
-				char *userid;
-				if((child2 = xmlnode_get_child(child, "USERID"))) {
-					/* show what kind of email it is */
-					userid = xmlnode_get_data(child2);
-					if(userid) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> <a href='mailto:%s'>%s</a><br/>",
-								_("E-Mail"), userid, userid);
-						g_free(userid);
-					}
-				} else if((userid = xmlnode_get_data(child))) {
-					/* lots of clients (including gaim) do this, but it's
-					 * out of spec */
-						g_string_append_printf(info_text,
-								"<b>%s:</b> <a href='mailto:%s'>%s</a><br/>",
-								_("E-Mail"), userid, userid);
-					g_free(userid);
-				}
-			} else if(!strcmp(child->name, "ORG")) {
-				for(child2 = child->child; child2; child2 = child2->next)
-				{
-					char *text2;
-
-					if(child2->type != XMLNODE_TYPE_TAG)
-						continue;
-
-					text2 = xmlnode_get_data(child2);
-					if(text2 && !strcmp(child2->name, "ORGNAME")) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> %s<br/>",
-								_("Organization Name"), text2);
-					} else if(text2 && !strcmp(child2->name, "ORGUNIT")) {
-						g_string_append_printf(info_text,
-								"<b>%s:</b> %s<br/>",
-								_("Organization Unit"), text2);
-					}
-					g_free(text2);
-				}
-			} else if(text && !strcmp(child->name, "TITLE")) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Title"), text);
-			} else if(text && !strcmp(child->name, "ROLE")) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Role"), text);
-			} else if(text && !strcmp(child->name, "DESC")) {
-				g_string_append_printf(info_text, "<b>%s:</b> %s<br/>",
-						_("Description"), text);
-			} else if(!strcmp(child->name, "PHOTO") ||
-					!strcmp(child->name, "LOGO")) {
-				char *bintext = NULL;
-				xmlnode *binval;
-
-				if( ((binval = xmlnode_get_child(child, "BINVAL")) &&
-						(bintext = xmlnode_get_data(binval))) ||
-						(bintext = xmlnode_get_data(child))) {
-					gsize size;
-					guchar *data;
-					int i;
-					unsigned char hashval[20];
-					char *p, hash[41];
-					gboolean photo = (strcmp(child->name, "PHOTO") == 0);
-
-					data = gaim_base64_decode(bintext, &size);
-
-					jbi->vcard_imgids = g_slist_prepend(jbi->vcard_imgids, GINT_TO_POINTER(gaim_imgstore_add(data, size, "logo.png")));
-					g_string_append_printf(info_text,
-							"<b>%s:</b> <img id='%d'><br/>",
-							photo ? _("Photo") : _("Logo"),
-							GPOINTER_TO_INT(jbi->vcard_imgids->data));
-
-					gaim_buddy_icons_set_for_user(js->gc->account, bare_jid,
-							data, size);
-
-					gaim_cipher_digest_region("sha1", (guchar *)data, size,
-							sizeof(hashval), hashval, NULL);
-					p = hash;
-					for(i=0; i<20; i++, p+=2)
-						snprintf(p, 3, "%02x", hashval[i]);
-					gaim_blist_node_set_string((GaimBlistNode*)b, "avatar_hash", hash);
-
-					g_free(data);
-					g_free(bintext);
-				}
-			}
-			g_free(text);
-		}
-	}
-
-	jbi->vcard_text = gaim_strdup_withhtml(info_text->str);
-	g_string_free(info_text, TRUE);
-	g_free(bare_jid);
-
-	jabber_buddy_info_show_if_ready(jbi);
-}
-
-
-static void jabber_buddy_info_resource_free(gpointer data)
-{
-	JabberBuddyInfoResource *jbri = data;
-	g_free(jbri);
-}
-
-static void jabber_version_parse(JabberStream *js, xmlnode *packet, gpointer data)
-{
-	JabberBuddyInfo *jbi = data;
-	const char *type, *id, *from;
-	xmlnode *query;
-	char *resource_name;
-
-	g_return_if_fail(jbi != NULL);
-
-	type = xmlnode_get_attrib(packet, "type");
-	id = xmlnode_get_attrib(packet, "id");
-	from = xmlnode_get_attrib(packet, "from");
-
-	jabber_buddy_info_remove_id(jbi, id);
-
-	if(!from)
-		return;
-
-	resource_name = jabber_get_resource(from);
-
-	if(resource_name) {
-		if(type && !strcmp(type, "result")) {
-			if((query = xmlnode_get_child(packet, "query"))) {
-				JabberBuddyResource *jbr = jabber_buddy_find_resource(jbi->jb, resource_name);
-				if(jbr) {
-					xmlnode *node;
-					if((node = xmlnode_get_child(query, "name"))) {
-						jbr->client.name = xmlnode_get_data(node);
-					}
-					if((node = xmlnode_get_child(query, "version"))) {
-						jbr->client.version = xmlnode_get_data(node);
-					}
-					if((node = xmlnode_get_child(query, "os"))) {
-						jbr->client.os = xmlnode_get_data(node);
-					}
-				}
-			}
-		}
-		g_free(resource_name);
-	}
-
-	jabber_buddy_info_show_if_ready(jbi);
-}
-
-static void jabber_last_parse(JabberStream *js, xmlnode *packet, gpointer data)
-{
-	JabberBuddyInfo *jbi = data;
-	xmlnode *query;
-	char *resource_name;
-	const char *type, *id, *from, *seconds;
-
-	g_return_if_fail(jbi != NULL);
-
-	type = xmlnode_get_attrib(packet, "type");
-	id = xmlnode_get_attrib(packet, "id");
-	from = xmlnode_get_attrib(packet, "from");
-
-	jabber_buddy_info_remove_id(jbi, id);
-
-	if(!from)
-		return;
-
-	resource_name = jabber_get_resource(from);
-
-	if(resource_name) {
-		if(type && !strcmp(type, "result")) {
-			if((query = xmlnode_get_child(packet, "query"))) {
-				seconds = xmlnode_get_attrib(query, "seconds");
-				if(seconds) {
-					char *end = NULL;
-					long sec = strtol(seconds, &end, 10);
-					if(end != seconds) {
-						JabberBuddyInfoResource *jbir = g_hash_table_lookup(jbi->resources, resource_name);
-						if(jbir) {
-							jbir->idle_seconds = sec;
-						}
-					}
-				}
-			}
-		}
-		g_free(resource_name);
-	}
-
-	jabber_buddy_info_show_if_ready(jbi);
-}
-
-static gboolean jabber_buddy_get_info_timeout(gpointer data)
-{
-	JabberBuddyInfo *jbi = data;
-
-	/* remove the pending callbacks */
-	while(jbi->ids) {
-		char *id = jbi->ids->data;
-		jabber_iq_remove_callback_by_id(jbi->js, id);
-		g_free(id);
-		jbi->ids = g_slist_remove(jbi->ids, id);
-	}
-
-	jbi->timeout_handle = 0;
-
-	jabber_buddy_info_show_if_ready(jbi);
-
-	return FALSE;
-}
-
-static void jabber_buddy_get_info_for_jid(JabberStream *js, const char *jid)
-{
-	JabberIq *iq;
-	xmlnode *vcard;
-	GList *resources;
-	JabberBuddy *jb;
-	JabberBuddyInfo *jbi;
-
-	jb = jabber_buddy_find(js, jid, TRUE);
-
-	/* invalid JID */
-	if(!jb)
-		return;
-
-	jbi = g_new0(JabberBuddyInfo, 1);
-	jbi->jid = g_strdup(jid);
-	jbi->js = js;
-	jbi->jb = jb;
-	jbi->resources = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, jabber_buddy_info_resource_free);
-
-	iq = jabber_iq_new(js, JABBER_IQ_GET);
-
-	xmlnode_set_attrib(iq->node, "to", jid);
-	vcard = xmlnode_new_child(iq->node, "vCard");
-	xmlnode_set_namespace(vcard, "vcard-temp");
-
-	jabber_iq_set_callback(iq, jabber_vcard_parse, jbi);
-	jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
-
-	jabber_iq_send(iq);
-
-	for(resources = jb->resources; resources; resources = resources->next)
-	{
-		JabberBuddyResource *jbr = resources->data;
-		JabberBuddyInfoResource *jbir;
-		char *full_jid;
-
-		if ((strchr(jid, '/') == NULL) && (jbr->name != NULL)) {
-			full_jid = g_strdup_printf("%s/%s", jid, jbr->name);
-		} else {
-			full_jid = g_strdup(jid);
-		}
-
-		if (jbr->name != NULL)
-		{
-			jbir = g_new0(JabberBuddyInfoResource, 1);
-			g_hash_table_insert(jbi->resources, g_strdup(jbr->name), jbir);
-		}
-
-		if(!jbr->client.name) {
-			iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:version");
-			xmlnode_set_attrib(iq->node, "to", full_jid);
-			jabber_iq_set_callback(iq, jabber_version_parse, jbi);
-			jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
-			jabber_iq_send(iq);
-		}
-
-		iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:last");
-		xmlnode_set_attrib(iq->node, "to", full_jid);
-		jabber_iq_set_callback(iq, jabber_last_parse, jbi);
-		jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
-		jabber_iq_send(iq);
-
-		g_free(full_jid);
-	}
-
-	jbi->timeout_handle = gaim_timeout_add(30000, jabber_buddy_get_info_timeout, jbi);
-}
-
-void jabber_buddy_get_info(GaimConnection *gc, const char *who)
-{
-	JabberStream *js = gc->proto_data;
-	char *bare_jid = jabber_get_bare_jid(who);
-
-	if(bare_jid) {
-		jabber_buddy_get_info_for_jid(js, bare_jid);
-		g_free(bare_jid);
-	}
-}
-
-void jabber_buddy_get_info_chat(GaimConnection *gc, int id,
-		const char *resource)
-{
-	JabberStream *js = gc->proto_data;
-	JabberChat *chat = jabber_chat_find_by_id(js, id);
-	char *full_jid;
-
-	if(!chat)
-		return;
-
-	full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, resource);
-	jabber_buddy_get_info_for_jid(js, full_jid);
-	g_free(full_jid);
-}
-
-
-static void jabber_buddy_set_invisibility(JabberStream *js, const char *who,
-		gboolean invisible)
-{
-	GaimPresence *gpresence;
-	GaimAccount *account;
-	GaimStatus *status;
-	JabberBuddy *jb = jabber_buddy_find(js, who, TRUE);
-	xmlnode *presence;
-	JabberBuddyState state;
-	const char *msg;
-	int priority;
-
-	account   = gaim_connection_get_account(js->gc);
-	gpresence = gaim_account_get_presence(account);
-	status    = gaim_presence_get_active_status(gpresence);
-
-	gaim_status_to_jabber(status, &state, &msg, &priority);
-	presence = jabber_presence_create(state, msg, priority);
-
-	xmlnode_set_attrib(presence, "to", who);
-	if(invisible) {
-		xmlnode_set_attrib(presence, "type", "invisible");
-		jb->invisible |= JABBER_INVIS_BUDDY;
-	} else {
-		jb->invisible &= ~JABBER_INVIS_BUDDY;
-	}
-
-	jabber_send(js, presence);
-	xmlnode_free(presence);
-}
-
-static void jabber_buddy_make_invisible(GaimBlistNode *node, gpointer data)
-{
-	GaimBuddy *buddy;
-	GaimConnection *gc;
-	JabberStream *js;
-
-	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (GaimBuddy *) node;
-	gc = gaim_account_get_connection(buddy->account);
-	js = gc->proto_data;
-
-	jabber_buddy_set_invisibility(js, buddy->name, TRUE);
-}
-
-static void jabber_buddy_make_visible(GaimBlistNode *node, gpointer data)
-{
-	GaimBuddy *buddy;
-	GaimConnection *gc;
-	JabberStream *js;
-
-	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (GaimBuddy *) node;
-	gc = gaim_account_get_connection(buddy->account);
-	js = gc->proto_data;
-
-	jabber_buddy_set_invisibility(js, buddy->name, FALSE);
-}
-
-static void jabber_buddy_cancel_presence_notification(GaimBlistNode *node,
-		gpointer data)
-{
-	GaimBuddy *buddy;
-	GaimConnection *gc;
-	JabberStream *js;
-
-	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (GaimBuddy *) node;
-	gc = gaim_account_get_connection(buddy->account);
-	js = gc->proto_data;
-
-	/* I wonder if we should prompt the user before doing this */
-	jabber_presence_subscription_set(js, buddy->name, "unsubscribed");
-}
-
-static void jabber_buddy_rerequest_auth(GaimBlistNode *node, gpointer data)
-{
-	GaimBuddy *buddy;
-	GaimConnection *gc;
-	JabberStream *js;
-
-	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (GaimBuddy *) node;
-	gc = gaim_account_get_connection(buddy->account);
-	js = gc->proto_data;
-
-	jabber_presence_subscription_set(js, buddy->name, "subscribe");
-}
-
-
-static void jabber_buddy_unsubscribe(GaimBlistNode *node, gpointer data)
-{
-	GaimBuddy *buddy;
-	GaimConnection *gc;
-	JabberStream *js;
-
-	g_return_if_fail(GAIM_BLIST_NODE_IS_BUDDY(node));
-
-	buddy = (GaimBuddy *) node;
-	gc = gaim_account_get_connection(buddy->account);
-	js = gc->proto_data;
-
-	jabber_presence_subscription_set(js, buddy->name, "unsubscribe");
-}
-
-
-static GList *jabber_buddy_menu(GaimBuddy *buddy)
-{
-	GaimConnection *gc = gaim_account_get_connection(buddy->account);
-	JabberStream *js = gc->proto_data;
-	JabberBuddy *jb = jabber_buddy_find(js, buddy->name, TRUE);
-
-	GList *m = NULL;
-	GaimMenuAction *act;
-
-	if(!jb)
-		return m;
-
-	/* XXX: fix the NOT ME below */
-
-	if(js->protocol_version == JABBER_PROTO_0_9 /* && NOT ME */) {
-		if(jb->invisible & JABBER_INVIS_BUDDY) {
-			act = gaim_menu_action_new(_("Un-hide From"),
-			                           GAIM_CALLBACK(jabber_buddy_make_visible),
-			                           NULL, NULL);
-		} else {
-			act = gaim_menu_action_new(_("Temporarily Hide From"),
-			                           GAIM_CALLBACK(jabber_buddy_make_invisible),
-			                           NULL, NULL);
-		}
-		m = g_list_append(m, act);
-	}
-
-	if(jb->subscription & JABBER_SUB_FROM /* && NOT ME */) {
-		act = gaim_menu_action_new(_("Cancel Presence Notification"),
-		                           GAIM_CALLBACK(jabber_buddy_cancel_presence_notification),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-	}
-
-	if(!(jb->subscription & JABBER_SUB_TO)) {
-		act = gaim_menu_action_new(_("(Re-)Request authorization"),
-		                           GAIM_CALLBACK(jabber_buddy_rerequest_auth),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-
-	} else /* if(NOT ME) */{
-
-		/* shouldn't this just happen automatically when the buddy is
-		   removed? */
-		act = gaim_menu_action_new(_("Unsubscribe"),
-		                           GAIM_CALLBACK(jabber_buddy_unsubscribe),
-		                           NULL, NULL);
-		m = g_list_append(m, act);
-	}
-
-	return m;
-}
-
-GList *
-jabber_blist_node_menu(GaimBlistNode *node)
-{
-	if(GAIM_BLIST_NODE_IS_BUDDY(node)) {
-		return jabber_buddy_menu((GaimBuddy *) node);
-	} else {
-		return NULL;
-	}
-}
-
-
-const char *
-jabber_buddy_state_get_name(JabberBuddyState state)
-{
-	switch(state) {
-		case JABBER_BUDDY_STATE_UNKNOWN:
-			return _("Unknown");
-		case JABBER_BUDDY_STATE_ERROR:
-			return _("Error");
-		case JABBER_BUDDY_STATE_UNAVAILABLE:
-			return _("Offline");
-		case JABBER_BUDDY_STATE_ONLINE:
-			return _("Available");
-		case JABBER_BUDDY_STATE_CHAT:
-			return _("Chatty");
-		case JABBER_BUDDY_STATE_AWAY:
-			return _("Away");
-		case JABBER_BUDDY_STATE_XA:
-			return _("Extended Away");
-		case JABBER_BUDDY_STATE_DND:
-			return _("Do Not Disturb");
-	}
-
-	return _("Unknown");
-}
-
-JabberBuddyState jabber_buddy_status_id_get_state(const char *id) {
-	if(!id)
-		return JABBER_BUDDY_STATE_UNKNOWN;
-	if(!strcmp(id, "available"))
-		return JABBER_BUDDY_STATE_ONLINE;
-	if(!strcmp(id, "freeforchat"))
-		return JABBER_BUDDY_STATE_CHAT;
-	if(!strcmp(id, "away"))
-		return JABBER_BUDDY_STATE_AWAY;
-	if(!strcmp(id, "extended_away"))
-		return JABBER_BUDDY_STATE_XA;
-	if(!strcmp(id, "dnd"))
-		return JABBER_BUDDY_STATE_DND;
-	if(!strcmp(id, "offline"))
-		return JABBER_BUDDY_STATE_UNAVAILABLE;
-	if(!strcmp(id, "error"))
-		return JABBER_BUDDY_STATE_ERROR;
-
-	return JABBER_BUDDY_STATE_UNKNOWN;
-}
-
-JabberBuddyState jabber_buddy_show_get_state(const char *id) {
-	if(!id)
-		return JABBER_BUDDY_STATE_UNKNOWN;
-	if(!strcmp(id, "available"))
-		return JABBER_BUDDY_STATE_ONLINE;
-	if(!strcmp(id, "chat"))
-		return JABBER_BUDDY_STATE_CHAT;
-	if(!strcmp(id, "away"))
-		return JABBER_BUDDY_STATE_AWAY;
-	if(!strcmp(id, "xa"))
-		return JABBER_BUDDY_STATE_XA;
-	if(!strcmp(id, "dnd"))
-		return JABBER_BUDDY_STATE_DND;
-	if(!strcmp(id, "offline"))
-		return JABBER_BUDDY_STATE_UNAVAILABLE;
-	if(!strcmp(id, "error"))
-		return JABBER_BUDDY_STATE_ERROR;
-
-	return JABBER_BUDDY_STATE_UNKNOWN;
-}
-
-const char *jabber_buddy_state_get_show(JabberBuddyState state) {
-	switch(state) {
-		case JABBER_BUDDY_STATE_CHAT:
-			return "chat";
-		case JABBER_BUDDY_STATE_AWAY:
-			return "away";
-		case JABBER_BUDDY_STATE_XA:
-			return "xa";
-		case JABBER_BUDDY_STATE_DND:
-			return "dnd";
-		case JABBER_BUDDY_STATE_ONLINE:
-			return "available";
-		case JABBER_BUDDY_STATE_UNKNOWN:
-		case JABBER_BUDDY_STATE_ERROR:
-			return NULL;
-		case JABBER_BUDDY_STATE_UNAVAILABLE:
-			return "offline";
-	}
-	return NULL;
-}
-
-const char *jabber_buddy_state_get_status_id(JabberBuddyState state) {
-	switch(state) {
-		case JABBER_BUDDY_STATE_CHAT:
-			return "freeforchat";
-		case JABBER_BUDDY_STATE_AWAY:
-			return "away";
-		case JABBER_BUDDY_STATE_XA:
-			return "extended_away";
-		case JABBER_BUDDY_STATE_DND:
-			return "dnd";
-		case JABBER_BUDDY_STATE_ONLINE:
-			return "available";
-		case JABBER_BUDDY_STATE_UNKNOWN:
-			return "available";
-		case JABBER_BUDDY_STATE_ERROR:
-			return "error";
-		case JABBER_BUDDY_STATE_UNAVAILABLE:
-			return "offline";
-	}
-	return NULL;
-}
-
-static void user_search_result_add_buddy_cb(GaimConnection *gc, GList *row, void *user_data)
-{
-	/* 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(field, "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 Name"));
-		gaim_notify_searchresults_column_add(results, column);
-		column = gaim_notify_searchresults_column_new(_("Last Name"));
-		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,
-			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;
-	char *dir_server = data;
-
-	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);
-	xmlnode_set_attrib(iq->node, "to", dir_server);
-	jabber_iq_send(iq);
-	g_free(dir_server);
-}
-
-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);
-}
-
-#if 0
-/* This is for gettext only -- it will see this even though there's an #if 0. */
-
-/*
- * An incomplete list of server generated original language search
- * comments for Jabber User Directories
- *
- * See discussion thread "Search comment for Jabber is not translatable"
- * in gaim-i18n@lists.sourceforge.net (March 2006)
- */
-static const char * jabber_user_dir_comments [] = {
-       /* current comment from Jabber User Directory users.jabber.org */
-       N_("Find a contact by entering the search criteria in the given fields. "
-          "Note: Each field supports wild card searches (%)"),
-       NULL
-};
-#endif
-
-static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
-{
-	xmlnode *query, *x;
-	const char *from, *type;
-
-	if(!(from = xmlnode_get_attrib(packet, "from")))
-		return;
-
-	if(!(type = xmlnode_get_attrib(packet, "type")) || !strcmp(type, "error")) {
-		char *msg = jabber_parse_error(js, packet);
-
-		if(!msg)
-			msg = g_strdup(_("Unknown error"));
-
-		gaim_notify_error(js->gc, _("Directory Query Failed"),
-				  _("Could not query the directory server."), msg);
-		g_free(msg);
-
-		return;
-	}
-
-
-	if(!(query = xmlnode_get_child(packet, "query")))
-		return;
-
-	if((x = xmlnode_get_child_with_namespace(query, "x", "jabber:x:data"))) {
-		jabber_x_data_request(js, x, user_search_x_data_cb, g_strdup(from));
-		return;
-	} else {
-		struct user_search_info *usi;
-		xmlnode *instnode;
-		char *instructions = NULL;
-		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")))
-		{
-			char *tmp = xmlnode_get_data(instnode);
-
-			if(tmp)
-			{
-				/* Try to translate the message (see static message
-				   list in jabber_user_dir_comments[]) */
-				instructions = g_strdup_printf(_("Server Instructions: %s"), _(tmp));
-				g_free(tmp);
-			}
-		}
-
-		if(!instructions)
-		{
-			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);
-}
-
-
-

mercurial