changeset 1345:d6e6fcaa1f39

[gaim-migrate @ 1355] ok. messages work. transports sort of work (you'll sign into them if you have them, but you won't see them and you can't add or remove them). resource is not a part of buddy's names, which is a very very big plus, since it means things will work incredibly well now. at some point the resource may be added back somehow but if it is it won't be part of the name. committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Thu, 21 Dec 2000 13:54:22 +0000
parents 8b5ed2f0496c
children 83f78eb7c472
files plugins/jabber/jabber.c
diffstat 1 files changed, 474 insertions(+), 369 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/jabber/jabber.c	Thu Dec 21 10:31:42 2000 +0000
+++ b/plugins/jabber/jabber.c	Thu Dec 21 13:54:22 2000 +0000
@@ -58,27 +58,26 @@
 #define IQ_AUTH 0
 #define IQ_ROSTER 1
 
-typedef struct gjconn_struct
-{
-        /* Core structure */
-        pool        p;             /* Memory allocation pool */
-        int         state;     /* Connection state flag */
-        int         fd;            /* Connection file descriptor */
-        jid         user;      /* User info */
-        char        *pass;     /* User passwd */
+typedef struct gjconn_struct {
+	/* Core structure */
+	pool p;			/* Memory allocation pool */
+	int state;		/* Connection state flag */
+	int fd;			/* Connection file descriptor */
+	jid user;		/* User info */
+	char *pass;		/* User passwd */
 
-        /* Stream stuff */
-        int         id;        /* id counter for jab_getid() function */
-        char        idbuf[9];  /* temporary storage for jab_getid() */
-        char        *sid;      /* stream id from server, for digest auth */
-        XML_Parser  parser;    /* Parser instance */
-        xmlnode     current;   /* Current node in parsing instance.. */
+	/* Stream stuff */
+	int id;			/* id counter for jab_getid() function */
+	char idbuf[9];		/* temporary storage for jab_getid() */
+	char *sid;		/* stream id from server, for digest auth */
+	XML_Parser parser;	/* Parser instance */
+	xmlnode current;	/* Current node in parsing instance.. */
 
-        /* Event callback ptrs */
-        void (*on_state)(struct gjconn_struct *j, int state);
-        void (*on_packet)(struct gjconn_struct *j, jpacket p);
+	/* Event callback ptrs */
+	void (*on_state) (struct gjconn_struct * j, int state);
+	void (*on_packet) (struct gjconn_struct * j, jpacket p);
 
-        void *priv;
+	void *priv;
 
 } *gjconn, gjconn_struct;
 
@@ -101,18 +100,21 @@
 static char *gjab_auth(gjconn j);
 
 struct jabber_data {
-        gjconn jc;
+	gjconn jc;
 };
 
-static char *jabber_name() {
+static char *jabber_name()
+{
 	return "Jabber";
 }
 
-char *name() {
+char *name()
+{
 	return "Jabber";
 }
 
-char *description() {
+char *description()
+{
 	return "Allows gaim to use the Jabber protocol";
 }
 
@@ -120,547 +122,648 @@
 
 static gjconn gjab_new(char *user, char *pass, void *priv)
 {
-    pool p;
-    gjconn j;
+	pool p;
+	gjconn j;
 
-    if(!user) 
-            return(NULL);
+	if (!user)
+		return (NULL);
 
-    p = pool_new();
-    if(!p) 
-            return(NULL);
-    j = pmalloc_x(p, sizeof(gjconn_struct), 0);
-    if(!j) 
-            return(NULL);
-    j->p = p;
+	p = pool_new();
+	if (!p)
+		return (NULL);
+	j = pmalloc_x(p, sizeof(gjconn_struct), 0);
+	if (!j)
+		return (NULL);
+	j->p = p;
 
-    j->user = jid_new(p, user);
-    j->pass = pstrdup(p, pass);
+	j->user = jid_new(p, user);
+	j->pass = pstrdup(p, pass);
 
-    j->state = JCONN_STATE_OFF;
-    j->id = 1;
-    j->fd = -1;
+	j->state = JCONN_STATE_OFF;
+	j->id = 1;
+	j->fd = -1;
 
-    j->priv = priv;
+	j->priv = priv;
 
-    return j;
+	return j;
 }
 
 static void gjab_delete(gjconn j)
 {
-    if(!j) 
-            return;
+	if (!j)
+		return;
 
-    gjab_stop(j);
-    pool_free(j->p);
+	gjab_stop(j);
+	pool_free(j->p);
 }
 
 static void gjab_state_handler(gjconn j, gjconn_state_h h)
 {
-    if(!j)      
-            return;
+	if (!j)
+		return;
 
-    j->on_state = h;
+	j->on_state = h;
 }
 
 static void gjab_packet_handler(gjconn j, gjconn_packet_h h)
 {
-    if(!j)
-            return;
+	if (!j)
+		return;
 
-    j->on_packet = h;
+	j->on_packet = h;
 }
 
 static void gjab_stop(gjconn j)
 {
-    if(!j || j->state == JCONN_STATE_OFF) 
-            return;
+	if (!j || j->state == JCONN_STATE_OFF)
+		return;
 
-    j->state = JCONN_STATE_OFF;
-    close(j->fd);
-    j->fd = -1;
-    XML_ParserFree(j->parser);
+	j->state = JCONN_STATE_OFF;
+	gjab_send_raw(j, "</stream:stream>");
+	close(j->fd);
+	j->fd = -1;
+	XML_ParserFree(j->parser);
 }
 
 static int gjab_getfd(gjconn j)
 {
-    if(j)
-        return j->fd;
-    else
-        return -1;
+	if (j)
+		return j->fd;
+	else
+		return -1;
 }
 
 static jid gjab_getjid(gjconn j)
 {
-    if(j)
-        return(j->user);
-    else
-        return NULL;
+	if (j)
+		return (j->user);
+	else
+		return NULL;
 }
 
 static char *gjab_getsid(gjconn j)
 {
-    if(j)
-        return(j->sid);
-    else
-        return NULL;
+	if (j)
+		return (j->sid);
+	else
+		return NULL;
 }
 
 static char *gjab_getid(gjconn j)
 {
-    snprintf(j->idbuf, 8, "%d", j->id++);
-    return &j->idbuf[0];
+	snprintf(j->idbuf, 8, "%d", j->id++);
+	return &j->idbuf[0];
 }
 
 static void gjab_send(gjconn j, xmlnode x)
 {
-    if (j && j->state != JCONN_STATE_OFF) {
-            char *buf = xmlnode2str(x);
-            if (buf) 
-                    write(j->fd, buf, strlen(buf));
-            debug_printf("gjab_send: %s\n", buf);
-    }
+	if (j && j->state != JCONN_STATE_OFF) {
+		char *buf = xmlnode2str(x);
+		if (buf)
+			write(j->fd, buf, strlen(buf));
+		debug_printf("gjab_send: %s\n", buf);
+	}
 }
 
 static void gjab_send_raw(gjconn j, const char *str)
 {
-        if (j && j->state != JCONN_STATE_OFF) {
-                write(j->fd, str, strlen(str));
-                debug_printf("gjab_send_raw: %s\n", str);
-        }
+	if (j && j->state != JCONN_STATE_OFF) {
+		write(j->fd, str, strlen(str));
+		debug_printf("gjab_send_raw: %s\n", str);
+	}
 }
 
 static void gjab_reqroster(gjconn j)
 {
-        xmlnode x;
-        char *id;
+	xmlnode x;
+	char *id;
 
-        x = jutil_iqnew(JPACKET__GET, NS_ROSTER);
-        id = gjab_getid(j);
-        xmlnode_put_attrib(x, "id", id);
+	x = jutil_iqnew(JPACKET__GET, NS_ROSTER);
+	id = gjab_getid(j);
+	xmlnode_put_attrib(x, "id", id);
 
-        gjab_send(j, x);
-        xmlnode_free(x);
+	gjab_send(j, x);
+	xmlnode_free(x);
 }
 
 static char *gjab_auth(gjconn j)
 {
-    xmlnode x,y,z;
-    char *hash, *user, *id;
+	xmlnode x, y, z;
+	char *hash, *user, *id;
 
-    if(!j) 
-            return NULL;
+	if (!j)
+		return NULL;
 
-    x = jutil_iqnew(JPACKET__SET, NS_AUTH);
-    id = gjab_getid(j);
-    xmlnode_put_attrib(x, "id", id);
-    y = xmlnode_get_tag(x,"query");
+	x = jutil_iqnew(JPACKET__SET, NS_AUTH);
+	id = gjab_getid(j);
+	xmlnode_put_attrib(x, "id", id);
+	y = xmlnode_get_tag(x, "query");
 
-    user = j->user->user;
+	user = j->user->user;
 
-    if (user) {
-            z = xmlnode_insert_tag(y, "username");
-            xmlnode_insert_cdata(z, user, -1);
-    }
+	if (user) {
+		z = xmlnode_insert_tag(y, "username");
+		xmlnode_insert_cdata(z, user, -1);
+	}
 
-    z = xmlnode_insert_tag(y, "resource");
-    xmlnode_insert_cdata(z, j->user->resource, -1);
+	z = xmlnode_insert_tag(y, "resource");
+	xmlnode_insert_cdata(z, j->user->resource, -1);
 
-    if (j->sid) {
-            z = xmlnode_insert_tag(y, "digest");
-            hash = pmalloc(x->p, strlen(j->sid)+strlen(j->pass)+1);
-            strcpy(hash, j->sid);
-            strcat(hash, j->pass);
-            hash = shahash(hash);
-            xmlnode_insert_cdata(z, hash, 40);
-    } else {
-            z = xmlnode_insert_tag(y, "password");
-            xmlnode_insert_cdata(z, j->pass, -1);
-    }
+	if (j->sid) {
+		z = xmlnode_insert_tag(y, "digest");
+		hash = pmalloc(x->p, strlen(j->sid) + strlen(j->pass) + 1);
+		strcpy(hash, j->sid);
+		strcat(hash, j->pass);
+		hash = shahash(hash);
+		xmlnode_insert_cdata(z, hash, 40);
+	} else {
+		z = xmlnode_insert_tag(y, "password");
+		xmlnode_insert_cdata(z, j->pass, -1);
+	}
 
-    gjab_send(j, x);
-    xmlnode_free(x);
+	gjab_send(j, x);
+	xmlnode_free(x);
 
-    return id;
+	return id;
 }
 
 static void gjab_recv(gjconn j)
 {
-        static char buf[4096];
-        int len;
+	static char buf[4096];
+	int len;
 
-        if(!j || j->state == JCONN_STATE_OFF)
-                return;
+	if (!j || j->state == JCONN_STATE_OFF)
+		return;
 
-        if ((len = read(j->fd, buf, sizeof(buf)-1))) {
-                buf[len] = '\0';
-                debug_printf("input: %s\n", buf);
-                XML_Parse(j->parser, buf, len, 0);
-        } else if (len < 0) {
-                STATE_EVT(JCONN_STATE_OFF);
-                gjab_stop(j);
-        }
+	if ((len = read(j->fd, buf, sizeof(buf) - 1))) {
+		buf[len] = '\0';
+		debug_printf("input: %s\n", buf);
+		XML_Parse(j->parser, buf, len, 0);
+	} else if (len < 0) {
+		STATE_EVT(JCONN_STATE_OFF);
+		gjab_stop(j);
+	}
 }
 
 static void startElement(void *userdata, const char *name, const char **attribs)
 {
-    xmlnode x;
-    gjconn j = (gjconn)userdata;
+	xmlnode x;
+	gjconn j = (gjconn) userdata;
 
-    if(j->current) {
-            /* Append the node to the current one */
-            x = xmlnode_insert_tag(j->current, name);
-            xmlnode_put_expat_attribs(x, attribs);
+	if (j->current) {
+		/* Append the node to the current one */
+		x = xmlnode_insert_tag(j->current, name);
+		xmlnode_put_expat_attribs(x, attribs);
 
-            j->current = x;
-    } else {
-            x = xmlnode_new_tag(name);
-            xmlnode_put_expat_attribs(x, attribs);
-            if(strcmp(name, "stream:stream") == 0) {
-                    /* special case: name == stream:stream */
-                    /* id attrib of stream is stored for digest auth */
-                    j->sid = xmlnode_get_attrib(x, "id");
-                    /* STATE_EVT(JCONN_STATE_AUTH) */
-            } else {
-                    j->current = x;
-            }
-    }
+		j->current = x;
+	} else {
+		x = xmlnode_new_tag(name);
+		xmlnode_put_expat_attribs(x, attribs);
+		if (strcmp(name, "stream:stream") == 0) {
+			/* special case: name == stream:stream */
+			/* id attrib of stream is stored for digest auth */
+			j->sid = xmlnode_get_attrib(x, "id");
+			/* STATE_EVT(JCONN_STATE_AUTH) */
+		} else {
+			j->current = x;
+		}
+	}
 }
 
 static void endElement(void *userdata, const char *name)
 {
-    gjconn j = (gjconn)userdata;
-    xmlnode x;
-    jpacket p;
+	gjconn j = (gjconn) userdata;
+	xmlnode x;
+	jpacket p;
 
-    if(j->current == NULL) {
-        /* we got </stream:stream> */
-        STATE_EVT(JCONN_STATE_OFF)
-        return;
-    }
+	if (j->current == NULL) {
+		/* we got </stream:stream> */
+		STATE_EVT(JCONN_STATE_OFF)
+		    return;
+	}
 
-    x = xmlnode_get_parent(j->current);
+	x = xmlnode_get_parent(j->current);
 
-    if(!x) {
-            /* it is time to fire the event */
-            p = jpacket_new(j->current);
+	if (!x) {
+		/* it is time to fire the event */
+		p = jpacket_new(j->current);
 
-            if(j->on_packet)
-                    (j->on_packet)(j, p);
-            else
-                    xmlnode_free(j->current);
-    }
+		if (j->on_packet)
+			(j->on_packet) (j, p);
+		else
+			xmlnode_free(j->current);
+	}
 
-    j->current = x;
+	j->current = x;
 }
 
 static void charData(void *userdata, const char *s, int slen)
 {
-    gjconn j = (gjconn)userdata;
+	gjconn j = (gjconn) userdata;
 
-    if (j->current)
-        xmlnode_insert_cdata(j->current, s, slen);
+	if (j->current)
+		xmlnode_insert_cdata(j->current, s, slen);
 }
 
 static void gjab_start(gjconn j)
 {
-    xmlnode x;
-    char *t,*t2;
+	xmlnode x;
+	char *t, *t2;
 
-    if(!j || j->state != JCONN_STATE_OFF) 
-            return;
+	if (!j || j->state != JCONN_STATE_OFF)
+		return;
 
-    j->parser = XML_ParserCreate(NULL);
-    XML_SetUserData(j->parser, (void *)j);
-    XML_SetElementHandler(j->parser, startElement, endElement);
-    XML_SetCharacterDataHandler(j->parser, charData);
+	j->parser = XML_ParserCreate(NULL);
+	XML_SetUserData(j->parser, (void *)j);
+	XML_SetElementHandler(j->parser, startElement, endElement);
+	XML_SetCharacterDataHandler(j->parser, charData);
 
-    j->fd = make_netsocket(5222, j->user->server, NETSOCKET_CLIENT);
-    if(j->fd < 0) {
-        STATE_EVT(JCONN_STATE_OFF)
-        return;
-    }
-    j->state = JCONN_STATE_CONNECTED;
-    STATE_EVT(JCONN_STATE_CONNECTED)
+	j->fd = make_netsocket(5222, j->user->server, NETSOCKET_CLIENT);
+	if (j->fd < 0) {
+		STATE_EVT(JCONN_STATE_OFF)
+		    return;
+	}
+	j->state = JCONN_STATE_CONNECTED;
+	STATE_EVT(JCONN_STATE_CONNECTED)
 
-    /* start stream */
-    x = jutil_header(NS_CLIENT, j->user->server);
-    t = xmlnode2str(x);
-    /* this is ugly, we can create the string here instead of jutil_header */
-    /* what do you think about it? -madcat */
-    t2 = strstr(t,"/>");
-    *t2++ = '>';
-    *t2 = '\0';
-    gjab_send_raw(j,"<?xml version='1.0'?>");
-    gjab_send_raw(j,t);
-    xmlnode_free(x);
+	    /* start stream */
+	    x = jutil_header(NS_CLIENT, j->user->server);
+	t = xmlnode2str(x);
+	/* this is ugly, we can create the string here instead of jutil_header */
+	/* what do you think about it? -madcat */
+	t2 = strstr(t, "/>");
+	*t2++ = '>';
+	*t2 = '\0';
+	gjab_send_raw(j, "<?xml version='1.0'?>");
+	gjab_send_raw(j, t);
+	xmlnode_free(x);
 
-    j->state = JCONN_STATE_ON;
-    STATE_EVT(JCONN_STATE_ON)
+	j->state = JCONN_STATE_ON;
+	STATE_EVT(JCONN_STATE_ON)
 }
 
-static void jabber_callback(gpointer data, gint source, GdkInputCondition condition) {
+static void jabber_callback(gpointer data, gint source, GdkInputCondition condition)
+{
 	struct gaim_connection *gc = (struct gaim_connection *)data;
 	struct jabber_data *jd = (struct jabber_data *)gc->proto_data;
 
-        debug_printf("jabber_callback!\n");
-
-        gjab_recv(jd->jc);
+	gjab_recv(jd->jc);
 }
 
 static void jabber_handlemessage(gjconn j, jpacket p)
 {
-  xmlnode y;
-
-  char *from = NULL, *msg = NULL;
+	xmlnode y;
 
-  from = jid_full(p->from);
-  if ((y = xmlnode_get_tag(p->x, "body"))) {
-    msg = xmlnode_get_data(y);
-  }
+	char *from = NULL, *msg = NULL;
 
-  if (!from || !msg) {
-    return;
-  }
+	from = jid_full(p->from);
+	if ((y = xmlnode_get_tag(p->x, "body"))) {
+		msg = xmlnode_get_data(y);
+	}
 
-  debug_printf("jabber: msg from %s: %s\n", from, msg);
+	if (!from || !msg) {
+		return;
+	}
 
-  serv_got_im(GJ_GC(j), from, msg, 0);
+	serv_got_im(GJ_GC(j), from, msg, 0);
 
-  return;
+	return;
 }
 
 static void jabber_handlepresence(gjconn j, jpacket p)
 {
-  char *to, *from, *type;
-  struct buddy *b;
+	char *to, *from, *type;
+	struct buddy *b;
+	jid who;
+	char *buddy;
+
+	to = xmlnode_get_attrib(p->x, "to");
+	from = xmlnode_get_attrib(p->x, "from");
+	type = xmlnode_get_attrib(p->x, "type");
 
-  to = xmlnode_get_attrib(p->x, "to");
-  from = xmlnode_get_attrib(p->x, "from");
-  type = xmlnode_get_attrib(p->x, "type");
+	debug_printf("jabber: presence: %s, %s %s\n", to, from, type);
+	who = jid_new(j->p, from);
+	if (who->user == NULL) {
+		/* FIXME: transport */
+		debug_printf("user was NULL in handlepresence!\n");
+		return;
+	}
 
-  debug_printf("jabber: presence: %s, %s %s\n", to, from, type);
+	buddy = g_strdup_printf("%s@%s", who->user, who->server);
 
-  if (!(b = find_buddy(GJ_GC(j), from))) {
-          add_buddy(GJ_GC(j), "Buddies", from, from);
-	  do_export(NULL, NULL);
-  }
+	if (!(b = find_buddy(GJ_GC(j), buddy))) {
+		add_buddy(GJ_GC(j), "Buddies", buddy, buddy);
+		build_edit_tree();
+		do_export(NULL, NULL);
+	}
 
-  if (type && (strcasecmp(type, "unavailable") == 0))
-          serv_got_update(GJ_GC(j), from, 0, 0, 0, 0, 0, 0);
-  else
-          serv_got_update(GJ_GC(j), from, 1, 0, 0, 0, 0, 0);
+	if (type && (strcasecmp(type, "unavailable") == 0))
+		serv_got_update(GJ_GC(j), buddy, 0, 0, 0, 0, 0, 0);
+	else
+		serv_got_update(GJ_GC(j), buddy, 1, 0, 0, 0, 0, 0);
 
-  return;
+	g_free(buddy);
+
+	return;
+}
+
+static void jabber_handles10n(gjconn j, jpacket p)
+{
 }
 
 static void jabber_handleroster(gjconn j, xmlnode querynode)
 {
-        xmlnode x;
+	xmlnode x;
 
-        x = xmlnode_get_firstchild(querynode);
-        while (x) {
-                xmlnode g;
-                char *jid, *name, *sub, *ask;
+	x = xmlnode_get_firstchild(querynode);
+	while (x) {
+		xmlnode g;
+		char *Jid, *name, *sub, *ask;
+		jid who;
+
+		Jid = xmlnode_get_attrib(x, "jid");
+		name = xmlnode_get_attrib(x, "name");
+		sub = xmlnode_get_attrib(x, "subscription");
+		ask = xmlnode_get_attrib(x, "ask");
 
-                jid = xmlnode_get_attrib(x, "jid");
-                name = xmlnode_get_attrib(x, "name");
-                if (name)
-                        debug_printf("name = %s\n", name);
-                sub = xmlnode_get_attrib(x, "subscription");
-                ask = xmlnode_get_attrib(x, "ask");
+		if (ask) {
+			/* XXX do something
+			debug_printf("jabber: unhandled subscription request (%s/%s/%s/%s)\n", Jid, name,
+				     sub, ask);
+			*/
+		}
 
-                if (ask) {
-                        /* XXX do something */
-                        debug_printf("jabber: unhandled subscription request (%s/%s/%s/%s)\n", jid, name, sub, ask);
-                }
-
-                if ((g = xmlnode_get_firstchild(x))) {
-                        while (g) {
-                                if (strncasecmp(xmlnode_get_name(g), "group", 5) == 0) {
-                                        struct buddy *b;
-                                        char *groupname;
+		if ((g = xmlnode_get_firstchild(x))) {
+			while (g) {
+				if (strncasecmp(xmlnode_get_name(g), "group", 5) == 0) {
+					struct buddy *b;
+					char *groupname, *buddyname;
 
-                                        groupname = xmlnode_get_data(xmlnode_get_firstchild(g));
-                                        if (!(b = find_buddy(GJ_GC(j), jid))) {
-                                                debug_printf("adding buddy: %s\n", jid);
-                                                b = add_buddy(GJ_GC(j), groupname, jid, name?name:jid);
+					groupname = xmlnode_get_data(xmlnode_get_firstchild(g));
+					who = jid_new(j->p, Jid);
+					if (who->user == NULL) {
+						/* FIXME: transport */
+						debug_printf("user was NULL in handleroster!\n");
+						g = xmlnode_get_nextsibling(g);
+						continue;
+					}
+					buddyname = g_strdup_printf("%s@%s", who->user, who->server);
+					if (!(b = find_buddy(GJ_GC(j), buddyname))) {
+						debug_printf("adding buddy: %s\n", buddyname);
+						b =
+						    add_buddy(GJ_GC(j), groupname, buddyname,
+							      name ? name : buddyname);
+						build_edit_tree();
 						do_export(0, 0);
-                                        } else {
-                                                debug_printf("updating buddy: %s/%s\n", jid, name);
-                                                g_snprintf(b->name, sizeof(b->name), "%s", jid);
-                                                g_snprintf(b->show, sizeof(b->show), "%s", name?name:jid);
-                                        }
-                                        //serv_got_update(GJ_GC(j), b->name, 1, 0, 0, 0, 0, 0);
-                                }
-                                g = xmlnode_get_nextsibling(g);
-                        }
-                } else {
-                        struct buddy *b;
-                        if (!(b = find_buddy(GJ_GC(j), jid))) {
-                                b = add_buddy(GJ_GC(j), "Buddies", jid, name?name:jid);
+					} else {
+						debug_printf("updating buddy: %s/%s\n", buddyname, name);
+						g_snprintf(b->name, sizeof(b->name), "%s", buddyname);
+						g_snprintf(b->show, sizeof(b->show), "%s",
+							   name ? name : buddyname);
+					}
+					g_free(buddyname);
+				}
+				g = xmlnode_get_nextsibling(g);
+			}
+		} else {
+			struct buddy *b;
+			char *buddyname;
+
+			who = jid_new(j->p, Jid);
+			if (who->user == NULL) {
+				/* FIXME: transport */
+				debug_printf("user was NULL in handleroster!\n");
+				x = xmlnode_get_nextsibling(x);
+				continue;
+			}
+			buddyname = g_strdup_printf("%s@%s", who->user, who->server);
+			if (!(b = find_buddy(GJ_GC(j), buddyname))) {
+				b = add_buddy(GJ_GC(j), "Buddies", buddyname, name ? name : Jid);
+				build_edit_tree();
 				do_export(0, 0);
-                        }
-                }
+			}
+			g_free(buddyname);
+		}
 
-                x = xmlnode_get_nextsibling(x);
-        }
+		x = xmlnode_get_nextsibling(x);
+	}
 
-	x = jutil_presnew(0, NULL, NULL);
+	x = jutil_presnew(0, NULL, "Online");
 	gjab_send(j, x);
 	xmlnode_free(x);
 }
 
 static void jabber_handlepacket(gjconn j, jpacket p)
 {
-  switch (p->type) {
-  case JPACKET_MESSAGE:
-          jabber_handlemessage(j, p);
-          break;
-  case JPACKET_PRESENCE:
-          jabber_handlepresence(j, p);
-          break;
-  case JPACKET_IQ: {
-
-          if (jpacket_subtype(p) == JPACKET__RESULT) {
-                  xmlnode querynode;
-                  char *xmlns;
+	switch (p->type) {
+	case JPACKET_MESSAGE:
+		jabber_handlemessage(j, p);
+		break;
+	case JPACKET_PRESENCE:
+		jabber_handlepresence(j, p);
+		break;
+	case JPACKET_IQ:
+		debug_printf("jpacket_subtype: %d\n", jpacket_subtype(p));
 
-                  querynode = xmlnode_get_tag(p->x, "query");
-                  xmlns = xmlnode_get_attrib(querynode, "xmlns");
+		if (jpacket_subtype(p) == JPACKET__SET) {
+		} else if (jpacket_subtype(p) == JPACKET__RESULT) {
+			xmlnode querynode;
+			char *xmlns;
+
+			querynode = xmlnode_get_tag(p->x, "query");
+			xmlns = xmlnode_get_attrib(querynode, "xmlns");
 
-                  if (!xmlns || NSCHECK(querynode, NS_AUTH)) {
-                          debug_printf("auth success\n");
-                          
-                          account_online(GJ_GC(j));
-                          serv_finish_login(GJ_GC(j));
+			if (!xmlns || NSCHECK(querynode, NS_AUTH)) {
+				debug_printf("auth success\n");
 
-			  if (bud_list_cache_exists(GJ_GC(j)))
-				  do_import(NULL, GJ_GC(j));
-                          
-                          gjab_reqroster(j);
+				account_online(GJ_GC(j));
+				serv_finish_login(GJ_GC(j));
+
+				if (bud_list_cache_exists(GJ_GC(j)))
+					do_import(NULL, GJ_GC(j));
+
+				gjab_reqroster(j);
 
-                  } else if (NSCHECK(querynode, NS_ROSTER)) {
-                          jabber_handleroster(j, querynode);
-                  } else {
-                          debug_printf("jabber:iq:query: %s\n", xmlns);
-                  }
+			} else if (NSCHECK(querynode, NS_ROSTER)) {
+				jabber_handleroster(j, querynode);
+			} else {
+				/* debug_printf("jabber:iq:query: %s\n", xmlns); */
+			}
+		} else {
+			xmlnode x;
 
-          } else {
-                  xmlnode x;
+			debug_printf("auth failed\n");
+			x = xmlnode_get_tag(p->x, "error");
+			if (x) {
+				debug_printf("error %d: %s\n\n",
+					     atoi(xmlnode_get_attrib(x, "code")),
+					     xmlnode_get_data(xmlnode_get_firstchild(x)));
+				hide_login_progress(GJ_GC(j),
+						    xmlnode_get_data(xmlnode_get_firstchild(x)));
 
-                  debug_printf("auth failed\n");
-                  x = xmlnode_get_tag(p->x, "error");
-                  if (x) {
-                          debug_printf("error %d: %s\n\n", 
-                                       atoi(xmlnode_get_attrib(x, "code")), 
-                                       xmlnode_get_data(xmlnode_get_firstchild(x)));
-                          hide_login_progress(GJ_GC(j), xmlnode_get_data(xmlnode_get_firstchild(x)));
-
-                  } else
-                          hide_login_progress(GJ_GC(j), "unknown error");
+			} else
+				hide_login_progress(GJ_GC(j), "unknown error");
 
-                  signoff(GJ_GC(j));
-          }
-          break;
-  }
-  default:
-          debug_printf("jabber: packet type %d (%s)\n", p->type, xmlnode2str(p->x));
-  }
+			signoff(GJ_GC(j));
+		}
+		break;
+	case JPACKET_S10N:
+		jabber_handles10n(j, p);
+		break;
+	default:
+		debug_printf("jabber: packet type %d (%s)\n", p->type, xmlnode2str(p->x));
+	}
 
-  xmlnode_free(p->x);
+	xmlnode_free(p->x);
 
-  return;
+	return;
 }
 
 static void jabber_handlestate(gjconn j, int state)
 {
-  switch (state) {
-  case JCONN_STATE_OFF:
-          debug_printf("jabber: connection closed\n");
-          hide_login_progress(GJ_GC(j), "Unable to connect");
-          signoff(GJ_GC(j));
-          break;
-  case JCONN_STATE_CONNECTED:
-          debug_printf("jabber: connected.\n");
-          set_login_progress(GJ_GC(j), 3, "Connected");
-          break;
-  case JCONN_STATE_ON:
-          debug_printf("jabber: logging in...\n");
-          set_login_progress(GJ_GC(j), 5, "Logging in...");
-          gjab_auth(j);
-          break;
-  default:
-          debug_printf("state change: %d\n", state);
-  }
-  return;
+	switch (state) {
+	case JCONN_STATE_OFF:
+		hide_login_progress(GJ_GC(j), "Unable to connect");
+		signoff(GJ_GC(j));
+		break;
+	case JCONN_STATE_CONNECTED:
+		set_login_progress(GJ_GC(j), 3, "Connected");
+		break;
+	case JCONN_STATE_ON:
+		set_login_progress(GJ_GC(j), 5, "Logging in...");
+		gjab_auth(j);
+		break;
+	default:
+		debug_printf("state change: %d\n", state);
+	}
+	return;
 }
 
-static void jabber_login(struct aim_user *user) {
+static void jabber_login(struct aim_user *user)
+{
 	struct gaim_connection *gc = new_gaim_conn(user);
 	struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1);
 
 	set_login_progress(gc, 1, "Connecting");
 
-        if (!(jd->jc = gjab_new(user->username, user->password, gc))) {
+	if (!(jd->jc = gjab_new(user->username, user->password, gc))) {
 		debug_printf("jabber: unable to connect (jab_new failed)\n");
 		hide_login_progress(gc, "Unable to connect");
 		signoff(gc);
-                return;
-        }
+		return;
+	}
 
-        gjab_state_handler(jd->jc, jabber_handlestate);
-        gjab_packet_handler(jd->jc, jabber_handlepacket);
-        gjab_start(jd->jc);
+	gjab_state_handler(jd->jc, jabber_handlestate);
+	gjab_packet_handler(jd->jc, jabber_handlepacket);
+	gjab_start(jd->jc);
 
 
-	gc->inpa = gdk_input_add(jd->jc->fd, 
-                                 GDK_INPUT_READ | GDK_INPUT_EXCEPTION,
-                                 jabber_callback, gc);
+	gc->inpa = gdk_input_add(jd->jc->fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, jabber_callback, gc);
 
-        return;
+	return;
 }
 
-static void jabber_close(struct gaim_connection *gc) {
+static void jabber_close(struct gaim_connection *gc)
+{
 	struct jabber_data *jd = gc->proto_data;
 	gdk_input_remove(gc->inpa);
 	gjab_stop(jd->jc);
 	g_free(jd);
 }
 
-static void jabber_send_im(struct gaim_connection *gc, char *who, char *message, int away) {
-        xmlnode x, y;
+static void jabber_send_im(struct gaim_connection *gc, char *who, char *message, int away)
+{
+	xmlnode x, y;
 	char *realwho;
 	gjconn j = ((struct jabber_data *)gc->proto_data)->jc;
 
-        if (!who || !message)
-                return;
+	if (!who || !message)
+		return;
 
-        x = xmlnode_new_tag("message");
+	x = xmlnode_new_tag("message");
 	if (!strchr(who, '@'))
 		realwho = g_strdup_printf("%s@%s", who, j->user->server);
 	else
 		realwho = g_strdup(who);
-        xmlnode_put_attrib(x, "to", realwho);
+	xmlnode_put_attrib(x, "to", realwho);
 	g_free(realwho);
 
-        xmlnode_put_attrib(x, "type", "chat");
+	xmlnode_put_attrib(x, "type", "chat");
+
+	if (message && strlen(message)) {
+		y = xmlnode_insert_tag(x, "body");
+		xmlnode_insert_cdata(y, message, -1);
+	}
+
+	gjab_send(((struct jabber_data *)gc->proto_data)->jc, x);
+}
+
+static void jabber_add_buddy(struct gaim_connection *gc, char *name)
+{
+	xmlnode x;
+	char *realwho;
+	gjconn j = ((struct jabber_data *)gc->proto_data)->jc;
+
+	if (!name)
+		return;
+
+	x = xmlnode_new_tag("presence");
 
-        if (message && strlen(message)) {
-                y = xmlnode_insert_tag(x, "body");
-                xmlnode_insert_cdata(y, message, -1);
-        }
+	if (!strchr(name, '@'))
+		realwho = g_strdup_printf("%s@%s", name, j->user->server);
+	else {
+		jid who = jid_new(j->p, name);
+		if (who->user == NULL) {
+			/* FIXME: transport */
+			debug_printf("user was NULL in add_buddy!\n");
+			return;
+		}
+		realwho = g_strdup_printf("%s@%s", who->user, who->server);
+	}
+	xmlnode_put_attrib(x, "to", realwho);
+	g_free(realwho);
+
+	xmlnode_put_attrib(x, "type", "subscribe");
+
+	gjab_send(((struct jabber_data *)gc->proto_data)->jc, x);
+}
 
-        gjab_send(((struct jabber_data *)gc->proto_data)->jc, x);
+static void jabber_remove_buddy(struct gaim_connection *gc, char *name)
+{
+	xmlnode x;
+	char *realwho;
+	gjconn j = ((struct jabber_data *)gc->proto_data)->jc;
+
+	if (!name)
+		return;
+
+	x = xmlnode_new_tag("presence");
+
+	if (!strchr(name, '@'))
+		realwho = g_strdup_printf("%s@%s", name, j->user->server);
+	else
+		realwho = g_strdup(name);
+	xmlnode_put_attrib(x, "to", realwho);
+	g_free(realwho);
+
+	xmlnode_put_attrib(x, "type", "unsubscribe");
+
+	gjab_send(((struct jabber_data *)gc->proto_data)->jc, x);
+}
+
+static char **jabber_list_icon(int uc)
+{
+	return available_xpm;
 }
 
 static struct prpl *my_protocol = NULL;
 
-void Jabber_init(struct prpl *ret) {
+void Jabber_init(struct prpl *ret)
+{
 	/* the NULL's aren't required but they're nice to have */
 	ret->protocol = PROTO_JABBER;
 	ret->name = jabber_name;
-	ret->list_icon = NULL;
+	ret->list_icon = jabber_list_icon;
 	ret->action_menu = NULL;
 	ret->user_opts = NULL;
 	ret->login = jabber_login;
@@ -675,9 +778,9 @@
 	ret->dir_search = NULL;
 	ret->set_idle = NULL;
 	ret->change_passwd = NULL;
-	ret->add_buddy = NULL;
+	ret->add_buddy = jabber_add_buddy;
 	ret->add_buddies = NULL;
-	ret->remove_buddy = NULL;
+	ret->remove_buddy = jabber_remove_buddy;
 	ret->add_permit = NULL;
 	ret->add_deny = NULL;
 	ret->rem_permit = NULL;
@@ -695,12 +798,14 @@
 	my_protocol = ret;
 }
 
-char *gaim_plugin_init(GModule *handle) {
+char *gaim_plugin_init(GModule *handle)
+{
 	load_protocol(Jabber_init);
 	return NULL;
 }
 
-void gaim_plugin_remove() {
+void gaim_plugin_remove()
+{
 	struct prpl *p = find_prpl(PROTO_JABBER);
 	if (p == my_protocol)
 		unload_protocol(p);