changeset 26569:bc7fac8e2f79

propagate from branch 'im.pidgin.pidgin' (head f144c6bda9daf701aa891c875fce7a4dedd611ae) to branch 'im.pidgin.cpw.darkrain42.xmpp.bosh' (head 8b60514f2b44295e87ee3587669aec5059556149)
author Paul Aurich <paul@darkrain42.org>
date Sun, 05 Apr 2009 21:13:10 +0000
parents b01e8e76c59d (current diff) 6a6984e95381 (diff)
children 061df5754d20
files libpurple/media.h libpurple/protocols/jabber/auth.c libpurple/protocols/jabber/buddy.c libpurple/protocols/jabber/buddy.h libpurple/protocols/jabber/caps.c libpurple/protocols/jabber/caps.h libpurple/protocols/jabber/data.c libpurple/protocols/jabber/disco.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.h libpurple/protocols/jabber/message.c libpurple/protocols/jabber/message.h libpurple/protocols/jabber/pep.c libpurple/protocols/jabber/pep.h libpurple/protocols/jabber/presence.c libpurple/protocols/jabber/presence.h libpurple/protocols/jabber/roster.c
diffstat 70 files changed, 956 insertions(+), 741 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Sun Apr 05 03:25:00 2009 +0000
+++ b/COPYRIGHT	Sun Apr 05 21:13:10 2009 +0000
@@ -19,6 +19,7 @@
 Christopher Ayoup
 Alex Badea
 John Bailey
+Arunan Balasubramaniam
 R. Tyler Ballance
 Chris Banal
 Luca Barbato
--- a/ChangeLog	Sun Apr 05 03:25:00 2009 +0000
+++ b/ChangeLog	Sun Apr 05 21:13:10 2009 +0000
@@ -15,6 +15,8 @@
 	* Add support for in-band bytestreams for file transfers (XEP-0047).
 	* Add support for sending attentions (equivalent to "buzz" and "nudge")
 	  using the command /buzz (XEP-0224).
+	* A buddy's local time is displayed in the Get Info dialog if the remote
+	  client supports it.
 
 	IRC:
 	* Correctly handle WHOIS for users who are joined to a large number of
@@ -35,6 +37,10 @@
 	* The New Account dialog is now broken into three tabs.  Proxy
 	  configuration has been moved from the Advanced tab to the new tab.
 
+	Finch:
+	* The hardware cursor is updated correctly. This will be useful
+	  especially for users of braille terminals, screen readers etc.
+
 version 2.5.5 (03/01/2009):
 	libpurple:
 	* Fix a crash when removing an account with an unknown protocol id.
--- a/configure.ac	Sun Apr 05 03:25:00 2009 +0000
+++ b/configure.ac	Sun Apr 05 21:13:10 2009 +0000
@@ -788,12 +788,19 @@
 dnl #######################################################################
 AC_ARG_ENABLE(vv,
 	[AC_HELP_STRING([--disable-vv], [compile without voice and video support])],
-	enable_vv="$enableval", enable_vv="yes")
+	[enable_vv="$enableval" force_vv=$enableval], [enable_vv="yes" enable_vv=no])
 if test "x$enable_vv" != "xno"; then
 	if test "x$enable_farsight" != "xno" -a "x$enable_gstprops" != "xno"; then
 		AC_DEFINE(USE_VV, 1, [Use voice and video])
 	else
 		enable_vv="no"
+		if test "x$force_vv" = "xyes"; then
+			AC_MSG_ERROR([
+
+Dependencies for voice/video were not met. Install the necessary gstreamer and farsight packages first.
+
+			])
+		fi
 	fi
 fi
 
--- a/doc/finch.1.in	Sun Apr 05 03:25:00 2009 +0000
+++ b/doc/finch.1.in	Sun Apr 05 21:13:10 2009 +0000
@@ -59,7 +59,7 @@
 Display the version information window.
 
 .SH GNT Shortcuts
-You can use the following shortcuts:
+You can use the following shortcuts (see the "\*QWidget Actions\*U" section for a more complete list):
 .TP
 .B Alt \+ a
 Bring up a list of available actions. You can use this list to access the
@@ -378,6 +378,8 @@
 [GntWidget::binding]
 .br
 f11 = context-menu
+.br
+c-x = context-menu
 
 [GntWindow::binding]
 .br
--- a/finch/gntblist.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/gntblist.c	Sun Apr 05 21:13:10 2009 +0000
@@ -61,7 +61,7 @@
 #include <string.h>
 
 #define PREF_ROOT "/finch/blist"
-#define TYPING_TIMEOUT 4000
+#define TYPING_TIMEOUT_S 4
 
 #define SHOW_EMPTY_GROUP_TIMEOUT  60
 
@@ -2016,7 +2016,7 @@
 	}
 
 	if (ggblist->typing)
-		g_source_remove(ggblist->typing);
+		purple_timeout_remove(ggblist->typing);
 	remove_peripherals(ggblist);
 	if (ggblist->tagged)
 		g_list_free(ggblist->tagged);
@@ -2253,7 +2253,7 @@
 end:
 	g_free(escnewmessage);
 	if (ggblist->typing)
-		g_source_remove(ggblist->typing);
+		purple_timeout_remove(ggblist->typing);
 	ggblist->typing = 0;
 	return FALSE;
 }
@@ -2272,7 +2272,7 @@
 		/* Move the focus to the entry box */
 		/* XXX: Make sure the selected status can have a message */
 		gnt_box_move_focus(GNT_BOX(ggblist->window), 1);
-		ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL);
+		ggblist->typing = purple_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL);
 	}
 	else if (now->type == STATUS_SAVED_ALL)
 	{
@@ -2298,7 +2298,7 @@
 		return FALSE;
 
 	if (ggblist->typing)
-		g_source_remove(ggblist->typing);
+		purple_timeout_remove(ggblist->typing);
 	ggblist->typing = 0;
 
 	if (text[0] == '\r' && text[1] == 0)
@@ -2308,7 +2308,7 @@
 		return TRUE;
 	}
 
-	ggblist->typing = g_timeout_add(TYPING_TIMEOUT, (GSourceFunc)remove_typing_cb, NULL);
+	ggblist->typing = purple_timeout_add_seconds(TYPING_TIMEOUT_S, (GSourceFunc)remove_typing_cb, NULL);
 	return FALSE;
 }
 
--- a/finch/libgnt/gnt.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gnt.h	Sun Apr 05 21:13:10 2009 +0000
@@ -48,6 +48,10 @@
 	#define G_PARAM_STATIC_BLURB  G_PARAM_PRIVATE
 #endif
 
+#if !GLIB_CHECK_VERSION(2,14,0)
+	#define g_timeout_add_seconds(time, callback, data)  g_timeout_add(time * 1000, callback, data)
+#endif
+
 /**
  * Initialize GNT.
  */
--- a/finch/libgnt/gntbox.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gntbox.c	Sun Apr 05 21:13:10 2009 +0000
@@ -78,13 +78,11 @@
 
 	g_list_foreach(box->list, (GFunc)gnt_widget_draw, NULL);
 
-	gnt_box_sync_children(box);
-
 	if (box->title && !GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
 	{
 		int pos, right;
 		char *title = g_strdup(box->title);
-		
+
 		get_title_thingies(box, title, &pos, &right);
 
 		if (gnt_widget_has_focus(widget))
@@ -96,8 +94,8 @@
 		mvwaddch(widget->window, 0, right, ACS_LTEE | gnt_color_pair(GNT_COLOR_NORMAL));
 		g_free(title);
 	}
-	
-	GNTDEBUG;
+
+	gnt_box_sync_children(box);
 }
 
 static void
@@ -723,6 +721,9 @@
 	if (GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_NO_BORDER))
 		pos = 0;
 
+	if (!box->active)
+		find_focusable_widget(box);
+
 	for (iter = box->list; iter; iter = iter->next)
 	{
 		GntWidget *w = GNT_WIDGET(iter->data);
@@ -764,6 +765,9 @@
 		copywin(w->window, widget->window, 0, 0,
 				y, x, y + height - 1, x + width - 1, FALSE);
 		gnt_widget_set_position(w, x + widget->priv.x, y + widget->priv.y);
+		if (w == box->active) {
+			wmove(widget->window, y + getcury(w->window), x + getcurx(w->window));
+		}
 	}
 }
 
--- a/finch/libgnt/gntcheckbox.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gntcheckbox.c	Sun Apr 05 21:13:10 2009 +0000
@@ -42,7 +42,7 @@
 		type = GNT_COLOR_HIGHLIGHT;
 	else
 		type = GNT_COLOR_NORMAL;
-	
+
 	wbkgdset(widget->window, '\0' | gnt_color_pair(type));
 
 	text = g_strdup_printf("[%c]", cb->checked ? 'X' : ' ');
@@ -51,7 +51,8 @@
 
 	wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_NORMAL));
 	mvwaddstr(widget->window, 0, 4, GNT_BUTTON(cb)->priv->text);
-	
+	wmove(widget->window, 0, 1);
+
 	GNTDEBUG;
 }
 
--- a/finch/libgnt/gntcombobox.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gntcombobox.c	Sun Apr 05 21:13:10 2009 +0000
@@ -73,7 +73,7 @@
 	char *text = NULL, *s;
 	GntColorType type;
 	int len;
-	
+
 	if (box->dropdown && box->selected)
 		text = gnt_tree_get_selection_text(GNT_TREE(box->dropdown));
 
@@ -94,6 +94,7 @@
 	whline(widget->window, ' ' | gnt_color_pair(type), widget->priv.width - 4 - len);
 	mvwaddch(widget->window, 1, widget->priv.width - 3, ACS_VLINE | gnt_color_pair(GNT_COLOR_NORMAL));
 	mvwaddch(widget->window, 1, widget->priv.width - 2, ACS_DARROW | gnt_color_pair(GNT_COLOR_NORMAL));
+	wmove(widget->window, 1, 1);
 
 	g_free(text);
 	GNTDEBUG;
--- a/finch/libgnt/gntentry.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gntentry.c	Sun Apr 05 21:13:10 2009 +0000
@@ -271,6 +271,7 @@
 	GntEntry *entry = GNT_ENTRY(widget);
 	int stop;
 	gboolean focus;
+	int curpos;
 
 	if ((focus = gnt_widget_has_focus(widget)))
 		wbkgdset(widget->window, '\0' | gnt_color_pair(GNT_COLOR_TEXT_NORMAL));
@@ -289,9 +290,10 @@
 	if (stop < widget->priv.width)
 		mvwhline(widget->window, 0, stop, ENTRY_CHAR, widget->priv.width - stop);
 
+	curpos = gnt_util_onscreen_width(entry->scroll, entry->cursor);
 	if (focus)
-		mvwchgat(widget->window, 0, gnt_util_onscreen_width(entry->scroll, entry->cursor),
-				1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL);
+		mvwchgat(widget->window, 0, curpos, 1, A_REVERSE, GNT_COLOR_TEXT_NORMAL, NULL);
+	wmove(widget->window, 0, curpos);
 
 	GNTDEBUG;
 }
--- a/finch/libgnt/gnttextview.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gnttextview.c	Sun Apr 05 21:13:10 2009 +0000
@@ -177,7 +177,7 @@
 					gnt_color_pair(GNT_COLOR_HIGHLIGHT_D));
 	}
 
-	GNTDEBUG;
+	wmove(widget->window, 0, 0);
 }
 
 static void
--- a/finch/libgnt/gnttree.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gnttree.c	Sun Apr 05 21:13:10 2009 +0000
@@ -28,7 +28,7 @@
 #include <string.h>
 #include <ctype.h>
 
-#define SEARCH_TIMEOUT 4000   /* 4 secs */
+#define SEARCH_TIMEOUT_S 4   /* 4 secs */
 #define SEARCHING(tree)  (tree->priv->search && tree->priv->search->len > 0)
 
 #define COLUMN_INVISIBLE(tree, index)  (tree->columns[index].flags & GNT_TREE_COLUMN_INVISIBLE)
@@ -420,6 +420,7 @@
 	GntTreeRow *row;
 	int pos, up, down = 0;
 	int rows, scrcol;
+	int current = 0;
 
 	if (!GNT_WIDGET_IS_FLAG_SET(GNT_WIDGET(tree), GNT_WIDGET_MAPPED))
 		return;
@@ -518,6 +519,7 @@
 
 		if (row == tree->current)
 		{
+			current = i;
 			attr |= A_BOLD;
 			if (gnt_widget_has_focus(widget))
 				attr |= gnt_color_pair(GNT_COLOR_HIGHLIGHT);
@@ -606,6 +608,7 @@
 		mvwaddnstr(widget->window, widget->priv.height - pos - 1, pos,
 				tree->priv->search->str, str - tree->priv->search->str);
 	}
+	wmove(widget->window, current, pos);
 
 	gnt_widget_queue_update(widget);
 }
@@ -818,7 +821,7 @@
 			gnt_bindable_perform_action_key(GNT_BINDABLE(tree), text);
 		}
 		g_source_remove(tree->priv->search_timeout);
-		tree->priv->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree);
+		tree->priv->search_timeout = g_timeout_add_seconds(SEARCH_TIMEOUT_S, search_timeout, tree);
 		return TRUE;
 	} else if (text[0] == ' ' && text[1] == 0) {
 		/* Space pressed */
@@ -930,7 +933,7 @@
 		return FALSE;
 	GNT_WIDGET_SET_FLAGS(GNT_WIDGET(tree), GNT_WIDGET_DISABLE_ACTIONS);
 	tree->priv->search = g_string_new(NULL);
-	tree->priv->search_timeout = g_timeout_add(SEARCH_TIMEOUT, search_timeout, tree);
+	tree->priv->search_timeout = g_timeout_add_seconds(SEARCH_TIMEOUT_S, search_timeout, tree);
 	return TRUE;
 }
 
--- a/finch/libgnt/gntwm.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/libgnt/gntwm.c	Sun Apr 05 21:13:10 2009 +0000
@@ -135,6 +135,17 @@
 	src = widget->window;
 	dst = node->window;
 	copywin(src, dst, node->scroll, 0, 0, 0, getmaxy(dst) - 1, getmaxx(dst) - 1, 0);
+
+	/* Update the hardware cursor */
+	if (GNT_IS_WINDOW(widget) || GNT_IS_BOX(widget)) {
+		GntWidget *active = GNT_BOX(widget)->active;
+		if (active) {
+			int curx = active->priv.x + getcurx(active->window);
+			int cury = active->priv.y + getcury(active->window);
+			if (wmove(node->window, cury - widget->priv.y, curx - widget->priv.x) != OK)
+				wmove(node->window, 0, 0);
+		}
+	}
 }
 
 /**
@@ -397,7 +408,7 @@
 	wm->positions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
 	if (gnt_style_get_bool(GNT_STYLE_REMPOS, TRUE))
 		read_window_positions(wm);
-	g_timeout_add(IDLE_CHECK_INTERVAL * 1000, check_idle, NULL);
+	g_timeout_add_seconds(IDLE_CHECK_INTERVAL, check_idle, NULL);
 	time(&last_active_time);
 	gnt_wm_switch_workspace(wm, 0);
 }
@@ -1101,8 +1112,8 @@
 
 	g_hash_table_foreach(wm->nodes, (GHFunc)refresh_node, GINT_TO_POINTER(TRUE));
 	g_signal_emit(wm, signals[SIG_TERMINAL_REFRESH], 0);
+	gnt_ws_draw_taskbar(wm->cws, TRUE);
 	update_screen(wm);
-	gnt_ws_draw_taskbar(wm->cws, TRUE);
 	curs_set(0);   /* endwin resets the cursor to normal */
 
 	return TRUE;
@@ -1872,8 +1883,8 @@
 		}
 	}
 
+	gnt_ws_draw_taskbar(wm->cws, FALSE);
 	update_screen(wm);
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
 }
 
 void gnt_wm_window_decorate(GntWM *wm, GntWidget *widget)
@@ -1885,6 +1896,7 @@
 {
 	GntWS *s;
 	int pos;
+	gboolean transient = !!GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT);
 
 	s = gnt_wm_widget_find_workspace(wm, widget);
 
@@ -1908,10 +1920,12 @@
 			if (s->ordered && wm->cws == s)
 				gnt_wm_raise_window(wm, s->ordered->data);
 		}
+	} else if (transient && wm->cws && wm->cws->ordered) {
+		gnt_wm_update_window(wm, wm->cws->ordered->data);
 	}
 
+	gnt_ws_draw_taskbar(wm->cws, FALSE);
 	update_screen(wm);
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
 }
 
 time_t gnt_wm_get_idle_time()
@@ -2119,7 +2133,7 @@
 	if (write_timeout) {
 		g_source_remove(write_timeout);
 	}
-	write_timeout = g_timeout_add(10000, write_already, wm);
+	write_timeout = g_timeout_add_seconds(10, write_already, wm);
 }
 
 void gnt_wm_move_window(GntWM *wm, GntWidget *widget, int x, int y)
@@ -2181,8 +2195,8 @@
 		GntNode *nd = g_hash_table_lookup(wm->nodes, wm->_list.window);
 		top_panel(nd->panel);
 	}
+	gnt_ws_draw_taskbar(wm->cws, FALSE);
 	update_screen(wm);
-	gnt_ws_draw_taskbar(wm->cws, FALSE);
 }
 
 void gnt_wm_update_window(GntWM *wm, GntWidget *widget)
@@ -2207,8 +2221,8 @@
 
 	if (ws == wm->cws || GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_TRANSIENT)) {
 		gnt_wm_copy_win(widget, node);
+		gnt_ws_draw_taskbar(wm->cws, FALSE);
 		update_screen(wm);
-		gnt_ws_draw_taskbar(wm->cws, FALSE);
 	} else if (ws && ws != wm->cws && GNT_WIDGET_IS_FLAG_SET(widget, GNT_WIDGET_URGENT)) {
 		if (!act || (act && !g_list_find(act, ws)))
 			act = g_list_prepend(act, ws);
--- a/finch/plugins/gntgf.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/finch/plugins/gntgf.c	Sun Apr 05 21:13:10 2009 +0000
@@ -47,6 +47,7 @@
 #include <blist.h>
 #include <conversation.h>
 #include <debug.h>
+#include <eventloop.h>
 #include <util.h>
 
 #include <gnt.h>
@@ -75,7 +76,7 @@
 {
 	toasters = g_list_remove(toasters, toast);
 	gnt_widget_destroy(toast->window);
-	g_source_remove(toast->timer);
+	purple_timeout_remove(toast->timer);
 	g_free(toast);
 }
 
@@ -220,7 +221,7 @@
 	}
 	gnt_widget_draw(window);
 
-	toast->timer = g_timeout_add(4000, (GSourceFunc)remove_toaster, toast);
+	toast->timer = purple_timeout_add_seconds(4, (GSourceFunc)remove_toaster, toast);
 	toasters = g_list_prepend(toasters, toast);
 }
 
--- a/libpurple/media-gst.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/media-gst.h	Sun Apr 05 21:13:10 2009 +0000
@@ -24,8 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#ifndef __MEDIA_GST_H_
-#define __MEDIA_GST_H_
+#ifndef _PURPLE_MEDIA_GST_H_
+#define _PURPLE_MEDIA_GST_H_
 
 #include "media.h"
 #include "mediamanager.h"
@@ -170,4 +170,4 @@
 
 G_END_DECLS
 
-#endif  /* __MEDIA_GST_H_ */
+#endif  /* _PURPLE_MEDIA_GST_H_ */
--- a/libpurple/media.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/media.h	Sun Apr 05 21:13:10 2009 +0000
@@ -24,11 +24,8 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#ifndef __MEDIA_H_
-#define __MEDIA_H_
-
-#include "signals.h"
-#include "util.h"
+#ifndef _PURPLE_MEDIA_H_
+#define _PURPLE_MEDIA_H_
 
 #include <glib.h>
 #include <glib-object.h>
@@ -129,6 +126,9 @@
 	PURPLE_MEDIA_NETWORK_PROTOCOL_TCP,
 } PurpleMediaNetworkProtocol;
 
+#include "signals.h"
+#include "util.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -694,4 +694,4 @@
 
 G_END_DECLS
 
-#endif  /* __MEDIA_H_ */
+#endif  /* _PURPLE_MEDIA_H_ */
--- a/libpurple/mediamanager.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/mediamanager.h	Sun Apr 05 21:13:10 2009 +0000
@@ -24,12 +24,17 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#ifndef __MEDIA_MANAGER_H_
-#define __MEDIA_MANAGER_H_
+#ifndef _PURPLE_MEDIA_MANAGER_H_
+#define _PURPLE_MEDIA_MANAGER_H_
 
 #include <glib.h>
 #include <glib-object.h>
 
+/** @copydoc _PurpleMediaManager */
+typedef struct _PurpleMediaManager PurpleMediaManager;
+/** @copydoc _PurpleMediaManagerClass */
+typedef struct _PurpleMediaManagerClass PurpleMediaManagerClass;
+
 #include "connection.h"
 #include "media.h"
 
@@ -42,11 +47,6 @@
 #define PURPLE_IS_MEDIA_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_MEDIA_MANAGER))
 #define PURPLE_MEDIA_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_MEDIA_MANAGER, PurpleMediaManagerClass))
 
-/** @copydoc _PurpleMediaManager */
-typedef struct _PurpleMediaManager PurpleMediaManager;
-/** @copydoc _PurpleMediaManagerClass */
-typedef struct _PurpleMediaManagerClass PurpleMediaManagerClass;
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -220,4 +220,4 @@
 
 G_END_DECLS
 
-#endif  /* __MEDIA_MANAGER_H_ */
+#endif  /* _PURPLE_MEDIA_MANAGER_H_ */
--- a/libpurple/protocols/jabber/adhoccommands.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.c	Sun Apr 05 21:13:10 2009 +0000
@@ -39,16 +39,17 @@
 	GList *actionslist;
 } JabberAdHocActionInfo;
 
-void jabber_adhoc_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data) {
-	const char *from = xmlnode_get_attrib(packet, "from");
-	const char *type = xmlnode_get_attrib(packet, "type");
+void jabber_adhoc_disco_result_cb(JabberStream *js, const char *from,
+                                  JabberIqType type, const char *id,
+                                  xmlnode *packet, gpointer data)
+{
 	const char *node;
 	xmlnode *query, *item;
 	JabberID *jabberid;
 	JabberBuddy *jb;
 	JabberBuddyResource *jbr = NULL;
 
-	if(strcmp(type, "result"))
+	if (type == JABBER_IQ_ERROR)
 		return;
 
 	query = xmlnode_get_child_with_namespace(packet,"query","http://jabber.org/protocol/disco#items");
@@ -95,7 +96,10 @@
 	}
 }
 
-static void jabber_adhoc_parse(JabberStream *js, xmlnode *packet, gpointer data);
+static void jabber_adhoc_parse(JabberStream *js, const char *from,
+                               JabberIqType type, const char *id,
+                               xmlnode *packet, gpointer data);
+
 
 static void do_adhoc_action_cb(JabberStream *js, xmlnode *result, const char *actionhandle, gpointer user_data) {
 	xmlnode *command;
@@ -131,13 +135,16 @@
 	jabber_iq_send(iq);
 }
 
-static void jabber_adhoc_parse(JabberStream *js, xmlnode *packet, gpointer data) {
+static void
+jabber_adhoc_parse(JabberStream *js, const char *from,
+                   JabberIqType type, const char *id,
+                   xmlnode *packet, gpointer data)
+{
 	xmlnode *command = xmlnode_get_child_with_namespace(packet, "command", "http://jabber.org/protocol/commands");
 	const char *status = xmlnode_get_attrib(command,"status");
 	xmlnode *xdata = xmlnode_get_child_with_namespace(command,"x","jabber:x:data");
-	const char *type = xmlnode_get_attrib(packet,"type");
 
-	if(type && !strcmp(type,"error")) {
+	if (type == JABBER_IQ_ERROR) {
 		char *msg = jabber_parse_error(js, packet, NULL);
 		if(!msg)
 			msg = g_strdup(_("Unknown Error"));
@@ -147,8 +154,6 @@
 		g_free(msg);
 		return;
 	}
-	if(!type || strcmp(type,"result"))
-		return;
 
 	if(!status)
 		return;
@@ -159,7 +164,7 @@
 
 		if(note) {
 			char *data = xmlnode_get_data(note);
-			purple_notify_info(NULL, xmlnode_get_attrib(packet, "from"), data, NULL);
+			purple_notify_info(NULL, from, data, NULL);
 			g_free(data);
 		}
 
@@ -199,7 +204,7 @@
 
 		actionInfo = g_new0(JabberAdHocActionInfo, 1);
 		actionInfo->sessionid = g_strdup(xmlnode_get_attrib(command,"sessionid"));
-		actionInfo->who = g_strdup(xmlnode_get_attrib(packet,"from"));
+		actionInfo->who = g_strdup(from);
 		actionInfo->node = g_strdup(xmlnode_get_attrib(command,"node"));
 		actionInfo->actionslist = actionslist;
 
@@ -218,7 +223,11 @@
 	}
 }
 
-static void jabber_adhoc_server_got_list_cb(JabberStream *js, xmlnode *packet, gpointer data) {
+static void
+jabber_adhoc_server_got_list_cb(JabberStream *js, const char *from,
+                                JabberIqType type, const char *id,
+                                xmlnode *packet, gpointer data)
+{
 	xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", "http://jabber.org/protocol/disco#items");
 	xmlnode *item;
 
--- a/libpurple/protocols/jabber/adhoccommands.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,14 +19,16 @@
  *
  */
 
-#ifndef _PURPLE_JABBER_ADHOCCOMMANDS_H_
-#define _PURPLE_JABBER_ADHOCCOMMANDS_H_
+#ifndef PURPLE_JABBER_ADHOCCOMMANDS_H_
+#define PURPLE_JABBER_ADHOCCOMMANDS_H_
 
 #include "jabber.h"
 
 /* Implementation of XEP-0050 */
 
-void jabber_adhoc_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data);
+void jabber_adhoc_disco_result_cb(JabberStream *js, const char *from,
+                                  JabberIqType type, const char *id,
+                                  xmlnode *packet, gpointer data);
 
 void jabber_adhoc_execute(JabberStream *js, JabberAdHocCommands *cmd);
 
@@ -36,4 +38,4 @@
 
 void jabber_adhoc_init_server_commands(JabberStream *js, GList **m);
 
-#endif /* _PURPLE_JABBER_ADHOCCOMMANDS_H_ */
+#endif /* PURPLE_JABBER_ADHOCCOMMANDS_H_ */
--- a/libpurple/protocols/jabber/auth.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/auth.c	Sun Apr 05 21:13:10 2009 +0000
@@ -37,8 +37,9 @@
 #include "iq.h"
 #include "notify.h"
 
-static void auth_old_result_cb(JabberStream *js, xmlnode *packet,
-		gpointer data);
+static void auth_old_result_cb(JabberStream *js, const char *from,
+                               JabberIqType type, const char *id,
+                               xmlnode *packet, gpointer data);
 
 gboolean
 jabber_process_starttls(JabberStream *js, xmlnode *packet)
@@ -567,11 +568,11 @@
 #endif
 }
 
-static void auth_old_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void auth_old_result_cb(JabberStream *js, const char *from,
+                               JabberIqType type, const char *id,
+                               xmlnode *packet, gpointer data)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
-
-	if(type && !strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		jabber_disco_items_server(js);
 	} else {
 		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
@@ -594,24 +595,20 @@
 	}
 }
 
-static void auth_old_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void auth_old_cb(JabberStream *js, const char *from,
+                        JabberIqType type, const char *id,
+                        xmlnode *packet, gpointer data)
 {
 	JabberIq *iq;
 	xmlnode *query, *x;
-	const char *type = xmlnode_get_attrib(packet, "type");
 	const char *pw = purple_connection_get_password(js->gc);
 
-	if(!type) {
-		purple_connection_error_reason (js->gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Invalid response from server."));
-		return;
-	} else if(!strcmp(type, "error")) {
+	if (type == JABBER_IQ_ERROR) {
 		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
 		char *msg = jabber_parse_error(js, packet, &reason);
 		purple_connection_error_reason (js->gc, reason, msg);
 		g_free(msg);
-	} else if(!strcmp(type, "result")) {
+	} else if (type == JABBER_IQ_RESULT) {
 		query = xmlnode_get_child(packet, "query");
 		if(js->stream_id && xmlnode_get_child(query, "digest")) {
 			char *s, *hash;
--- a/libpurple/protocols/jabber/auth.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/auth.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_AUTH_H_
-#define _PURPLE_JABBER_AUTH_H_
+#ifndef PURPLE_JABBER_AUTH_H_
+#define PURPLE_JABBER_AUTH_H_
 
 #include "jabber.h"
 #include "xmlnode.h"
@@ -32,4 +32,4 @@
 void jabber_auth_handle_success(JabberStream *js, xmlnode *packet);
 void jabber_auth_handle_failure(JabberStream *js, xmlnode *packet);
 
-#endif /* _PURPLE_JABBER_AUTH_H_ */
+#endif /* PURPLE_JABBER_AUTH_H_ */
--- a/libpurple/protocols/jabber/buddy.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/buddy.c	Sun Apr 05 21:13:10 2009 +0000
@@ -155,6 +155,7 @@
 		jbr->jb = jb;
 		jbr->name = g_strdup(resource);
 		jbr->capabilities = JABBER_CAP_XHTML;
+		jbr->tz_off = PURPLE_NO_TZ_OFF;
 		jb->resources = g_list_append(jb->resources, jbr);
 	}
 	jbr->priority = priority;
@@ -794,6 +795,21 @@
 				purple_notify_user_info_prepend_pair(user_info, _("Operating System"), jbr->client.os);
 			}
 		}
+		if (jbr && jbr->tz_off != PURPLE_NO_TZ_OFF) {
+			time_t now_t;
+			struct tm *now;
+			char *timestamp;
+			time(&now_t);
+			now_t += jbr->tz_off;
+			now = gmtime(&now_t);
+
+			timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
+			                            jbr->tz_off < 0 ? '-' : '+',
+			                            abs(jbr->tz_off / (60*60)),
+			                            abs((jbr->tz_off % (60*60)) / 60));
+			purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
+			g_free(timestamp);
+		}
 		if(jbir) {
 			if(jbir->idle_seconds > 0) {
 				char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
@@ -912,7 +928,7 @@
 					feature = _("User Gaming");
 				else if(!strcmp(feature, "http://jabber.org/protocol/viewing"))
 					feature = _("User Viewing");
-				else if(!strcmp(feature, "urn:xmpp:ping") || !strcmp(feature, "http://www.xmpp.org/extensions/xep-0199.html#ns"))
+				else if(!strcmp(feature, "urn:xmpp:ping"))
 					feature = _("Ping");
 				else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns"))
 					feature = _("Stanza Encryption");
@@ -964,6 +980,22 @@
 				}
 			}
 
+			if (jbr->tz_off != PURPLE_NO_TZ_OFF) {
+				time_t now_t;
+				struct tm *now;
+				char *timestamp;
+				time(&now_t);
+				now_t += jbr->tz_off;
+				now = gmtime(&now_t);
+
+				timestamp = g_strdup_printf("%s %c%02d%02d", purple_time_format(now),
+				                            jbr->tz_off < 0 ? '-' : '+',
+				                            abs(jbr->tz_off / (60*60)),
+				                            abs((jbr->tz_off % (60*60)) / 60));
+				purple_notify_user_info_prepend_pair(user_info, _("Local Time"), timestamp);
+				g_free(timestamp);
+			}
+
 			if(jbr->name && (jbir = g_hash_table_lookup(jbi->resources, jbr->name))) {
 				if(jbir->idle_seconds > 0) {
 					char *idle = purple_str_seconds_to_string(jbir->idle_seconds);
@@ -1082,7 +1114,7 @@
 						feature = _("User Gaming");
 					else if(!strcmp(feature, "http://jabber.org/protocol/viewing"))
 						feature = _("User Viewing");
-					else if(!strcmp(feature, "urn:xmpp:ping") || !strcmp(feature, "http://www.xmpp.org/extensions/xep-0199.html#ns"))
+					else if(!strcmp(feature, "urn:xmpp:ping"))
 						feature = _("Ping");
 					else if(!strcmp(feature, "http://www.xmpp.org/extensions/xep-0200.html#ns"))
 						feature = _("Stanza Encryption");
@@ -1148,12 +1180,19 @@
 	}
 }
 
-static void jabber_vcard_save_mine(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_vcard_save_mine(JabberStream *js, const char *from,
+                                   JabberIqType type, const char *id,
+                                   xmlnode *packet, gpointer data)
 {
 	xmlnode *vcard;
 	char *txt;
 	PurpleStoredImage *img;
 
+	if (type == JABBER_IQ_ERROR) {
+		purple_debug_warning("jabber", "Server returned error while retrieving vCard");
+		return;
+	}
+
 	if((vcard = xmlnode_get_child(packet, "vCard")) ||
 			(vcard = xmlnode_get_child_with_namespace(packet, "query", "vcard-temp")))
 	{
@@ -1184,9 +1223,10 @@
 	jabber_iq_send(iq);
 }
 
-static void jabber_vcard_parse(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_vcard_parse(JabberStream *js, const char *from,
+                               JabberIqType type, const char *id,
+                               xmlnode *packet, gpointer data)
 {
-	const char *id, *from;
 	char *bare_jid;
 	char *text;
 	char *serverside_alias = NULL;
@@ -1195,9 +1235,6 @@
 	JabberBuddyInfo *jbi = data;
 	PurpleNotifyUserInfo *user_info;
 
-	from = xmlnode_get_attrib(packet, "from");
-	id = xmlnode_get_attrib(packet, "id");
-
 	if(!jbi)
 		return;
 
@@ -1547,19 +1584,16 @@
 	g_free(jbri);
 }
 
-static void jabber_version_parse(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_version_parse(JabberStream *js, const char *from,
+                                 JabberIqType type, const char *id,
+                                 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)
@@ -1568,7 +1602,7 @@
 	resource_name = jabber_get_resource(from);
 
 	if(resource_name) {
-		if(type && !strcmp(type, "result")) {
+		if (type == JABBER_IQ_RESULT) {
 			if((query = xmlnode_get_child(packet, "query"))) {
 				JabberBuddyResource *jbr = jabber_buddy_find_resource(jbi->jb, resource_name);
 				if(jbr) {
@@ -1591,19 +1625,17 @@
 	jabber_buddy_info_show_if_ready(jbi);
 }
 
-static void jabber_last_parse(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_last_parse(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id,
+                              xmlnode *packet, gpointer data)
 {
 	JabberBuddyInfo *jbi = data;
 	xmlnode *query;
 	char *resource_name;
-	const char *type, *id, *from, *seconds;
+	const char *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)
@@ -1612,7 +1644,7 @@
 	resource_name = jabber_get_resource(from);
 
 	if(resource_name) {
-		if(type && !strcmp(type, "result")) {
+		if (type == JABBER_IQ_RESULT) {
 			if((query = xmlnode_get_child(packet, "query"))) {
 				seconds = xmlnode_get_attrib(query, "seconds");
 				if(seconds) {
@@ -1633,6 +1665,56 @@
 	jabber_buddy_info_show_if_ready(jbi);
 }
 
+static void jabber_time_parse(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id,
+                              xmlnode *packet, gpointer data)
+{
+	JabberBuddyInfo *jbi = data;
+	JabberBuddyResource *jbr;
+	char *resource_name;
+
+	g_return_if_fail(jbi != NULL);
+
+	jabber_buddy_info_remove_id(jbi, id);
+
+	if (!from)
+		return;
+
+	resource_name = jabber_get_resource(from);
+	jbr = resource_name ? jabber_buddy_find_resource(jbi->jb, resource_name) : NULL;
+	g_free(resource_name);
+	if (jbr) {
+		if (type == JABBER_IQ_RESULT) {
+			xmlnode *time = xmlnode_get_child(packet, "time");
+			xmlnode *tzo = time ? xmlnode_get_child(time, "tzo") : NULL;
+			char *tzo_data = tzo ? xmlnode_get_data(tzo) : NULL;
+			if (tzo_data) {
+				char *c = tzo_data;
+				int hours, minutes;
+				if (tzo_data[0] == 'Z' && tzo_data[1] == '\0') {
+					jbr->tz_off = 0;
+				} else {
+					gboolean offset_positive = (tzo_data[0] == '+');
+					/* [+-]HH:MM */
+					if (((*c == '+' || *c == '-') && (c = c + 1)) &&
+							sscanf(c, "%02d:%02d", &hours, &minutes) == 2) {
+						jbr->tz_off = 60*60*hours + 60*minutes;
+						if (!offset_positive)
+							jbr->tz_off *= -1;
+					} else {
+						purple_debug_info("jabber", "Ignoring malformed timezone %s",
+						                  tzo_data);
+					}
+				}
+
+				g_free(tzo_data);
+			}
+		}
+	}
+
+	jabber_buddy_info_show_if_ready(jbi);
+}
+
 void jabber_buddy_remove_all_pending_buddy_info_requests(JabberStream *js)
 {
 	if (js->pending_buddy_info_requests)
@@ -1764,6 +1846,19 @@
 			jabber_iq_send(iq);
 		}
 
+		if (jbr->tz_off == PURPLE_NO_TZ_OFF &&
+				(!jbr->caps ||
+				 	jabber_resource_has_capability(jbr, "urn:xmpp:time"))) {
+			xmlnode *child;
+			iq = jabber_iq_new(js, JABBER_IQ_GET);
+			xmlnode_set_attrib(iq->node, "to", full_jid);
+			child = xmlnode_new_child(iq->node, "time");
+			xmlnode_set_namespace(child, "urn:xmpp:time");
+			jabber_iq_set_callback(iq, jabber_time_parse, jbi);
+			jbi->ids = g_slist_prepend(jbi->ids, g_strdup(iq->id));
+			jabber_iq_send(iq);
+		}
+
 		g_free(full_jid);
 	}
 
@@ -2160,7 +2255,9 @@
 			g_list_nth_data(row, 0), NULL, NULL);
 }
 
-static void user_search_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void user_search_result_cb(JabberStream *js, const char *from,
+                                  JabberIqType type, const char *id,
+                                  xmlnode *packet, gpointer data)
 {
 	PurpleNotifySearchResults *results;
 	PurpleNotifySearchColumn *column;
@@ -2356,15 +2453,16 @@
 };
 #endif
 
-static void user_search_fields_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void user_search_fields_result_cb(JabberStream *js, const char *from,
+                                         JabberIqType type, const char *id,
+                                         xmlnode *packet, gpointer data)
 {
 	xmlnode *query, *x;
-	const char *from, *type;
 
-	if(!(from = xmlnode_get_attrib(packet, "from")))
+	if (!from)
 		return;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || !strcmp(type, "error")) {
+	if (type == JABBER_IQ_ERROR) {
 		char *msg = jabber_parse_error(js, packet, NULL);
 
 		if(!msg)
--- a/libpurple/protocols/jabber/buddy.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/buddy.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_BUDDY_H_
-#define _PURPLE_JABBER_BUDDY_H_
+#ifndef PURPLE_JABBER_BUDDY_H_
+#define PURPLE_JABBER_BUDDY_H_
 
 typedef enum {
 	JABBER_BUDDY_STATE_UNKNOWN = -2,
@@ -81,6 +81,8 @@
 		char *name;
 		char *os;
 	} client;
+	/* tz_off == PURPLE_NO_TZ_OFF when unset */
+	long tz_off;
 	struct {
 		JabberCapsClientInfo *info;
 		GList *exts;
@@ -124,4 +126,4 @@
 										const gchar *cap);
 gboolean jabber_buddy_has_capability(const JabberBuddy *jb, const gchar *cap);
 
-#endif /* _PURPLE_JABBER_BUDDY_H_ */
+#endif /* PURPLE_JABBER_BUDDY_H_ */
--- a/libpurple/protocols/jabber/caps.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/caps.c	Sun Apr 05 21:13:10 2009 +0000
@@ -247,7 +247,7 @@
 		xmlnode_free(capsdata);
 		return;
 	}
-	
+
 	for(client = capsdata->child; client; client = client->next) {
 		if(client->type != XMLNODE_TYPE_TAG)
 			continue;
--- a/libpurple/protocols/jabber/caps.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/caps.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef _PURPLE_JABBER_CAPS_H_
-#define _PURPLE_JABBER_CAPS_H_
+#ifndef PURPLE_JABBER_CAPS_H_
+#define PURPLE_JABBER_CAPS_H_
 
 typedef struct _JabberCapsClientInfo JabberCapsClientInfo;
 
@@ -99,4 +99,4 @@
  */
 void jabber_caps_broadcast_change(void);
 
-#endif /* _PURPLE_JABBER_CAPS_H_ */
+#endif /* PURPLE_JABBER_CAPS_H_ */
--- a/libpurple/protocols/jabber/chat.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/chat.c	Sun Apr 05 21:13:10 2009 +0000
@@ -376,21 +376,19 @@
 	jabber_iq_send(iq);
 }
 
-static void jabber_chat_room_configure_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_chat_room_configure_cb(JabberStream *js, const char *from,
+                                          JabberIqType type, const char *id,
+                                          xmlnode *packet, gpointer data)
 {
 	xmlnode *query, *x;
-	const char *type = xmlnode_get_attrib(packet, "type");
-	const char *from = xmlnode_get_attrib(packet, "from");
 	char *msg;
 	JabberChat *chat;
 	JabberID *jid;
 
-	if(!type || !from)
+	if (!from)
 		return;
 
-
-
-	if(!strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		jid = jabber_id_new(from);
 
 		if(!jid)
@@ -416,7 +414,7 @@
 				return;
 			}
 		}
-	} else if(!strcmp(type, "error")) {
+	} else if (type == JABBER_IQ_ERROR) {
 		char *msg = jabber_parse_error(js, packet, NULL);
 
 		purple_notify_error(js->gc, _("Configuration error"), _("Configuration error"), msg);
@@ -486,11 +484,12 @@
 	g_free(room_jid);
 }
 
-static void jabber_chat_register_x_data_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void
+jabber_chat_register_x_data_result_cb(JabberStream *js, const char *from,
+                                      JabberIqType type, const char *id,
+                                      xmlnode *packet, gpointer data)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
-
-	if(type && !strcmp(type, "error")) {
+	if (type == JABBER_IQ_ERROR) {
 		char *msg = jabber_parse_error(js, packet, NULL);
 
 		purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg);
@@ -521,19 +520,19 @@
 	jabber_iq_send(iq);
 }
 
-static void jabber_chat_register_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_chat_register_cb(JabberStream *js, const char *from,
+                                    JabberIqType type, const char *id,
+                                    xmlnode *packet, gpointer data)
 {
 	xmlnode *query, *x;
-	const char *type = xmlnode_get_attrib(packet, "type");
-	const char *from = xmlnode_get_attrib(packet, "from");
 	char *msg;
 	JabberChat *chat;
 	JabberID *jid;
 
-	if(!type || !from)
+	if (!from)
 		return;
 
-	if(!strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		jid = jabber_id_new(from);
 
 		if(!jid)
@@ -559,7 +558,7 @@
 				return;
 			}
 		}
-	} else if(!strcmp(type, "error")) {
+	} else if (type == JABBER_IQ_ERROR) {
 		char *msg = jabber_parse_error(js, packet, NULL);
 
 		purple_notify_error(js->gc, _("Registration error"), _("Registration error"), msg);
@@ -690,16 +689,17 @@
 	g_free(room_jid);
 }
 
-static void roomlist_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void roomlist_disco_result_cb(JabberStream *js, const char *from,
+                                     JabberIqType type, const char *id,
+                                     xmlnode *packet, gpointer data)
 {
 	xmlnode *query;
 	xmlnode *item;
-	const char *type;
 
 	if(!js->roomlist)
 		return;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) {
+	if (type == JABBER_IQ_ERROR) {
 		char *err = jabber_parse_error(js, packet, NULL);
 		purple_notify_error(js->gc, _("Error"),
 				_("Error retrieving room list"), err);
@@ -988,13 +988,17 @@
 	return TRUE;
 }
 
-static void jabber_chat_disco_traffic_cb(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_chat_disco_traffic_cb(JabberStream *js, const char *from,
+                                         JabberIqType type, const char *id,
+                                         xmlnode *packet, gpointer data)
 {
 	JabberChat *chat;
-	/*xmlnode *query;*/
-	int id = GPOINTER_TO_INT(data);
+#if 0
+	xmlnode *query, *x;
+#endif
+	int chat_id = GPOINTER_TO_INT(data);
 
-	if(!(chat = jabber_chat_find_by_id(js, id)))
+	if(!(chat = jabber_chat_find_by_id(js, chat_id)))
 		return;
 
 	/* defaults, in case the conference server doesn't
@@ -1002,8 +1006,9 @@
 	chat->xhtml = TRUE;
 
 	/* disabling this until more MUC servers support
-	 * announcing this
-	if(xmlnode_get_child(packet, "error")) {
+	 * announcing this */
+#if 0
+	if (type == JABBER_IQ_ERROR) {
 		return;
 	}
 
@@ -1019,7 +1024,7 @@
 			chat->xhtml = TRUE;
 		}
 	}
-	*/
+#endif
 }
 
 void jabber_chat_disco_traffic(JabberChat *chat)
--- a/libpurple/protocols/jabber/chat.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/chat.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_CHAT_H_
-#define _PURPLE_JABBER_CHAT_H_
+#ifndef PURPLE_JABBER_CHAT_H_
+#define PURPLE_JABBER_CHAT_H_
 
 #include "internal.h"
 #include "connection.h"
@@ -94,4 +94,4 @@
 char *jabber_roomlist_room_serialize(PurpleRoomlistRoom *room);
 
 
-#endif /* _PURPLE_JABBER_CHAT_H_ */
+#endif /* PURPLE_JABBER_CHAT_H_ */
--- a/libpurple/protocols/jabber/data.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/data.c	Sun Apr 05 21:13:10 2009 +0000
@@ -200,25 +200,26 @@
 }
 
 void
-jabber_data_parse(JabberStream *js, xmlnode *packet)
+jabber_data_parse(JabberStream *js, const char *who, JabberIqType type,
+                  const char *id, xmlnode *data_node)
 {
 	JabberIq *result = NULL;
-	const char *who = xmlnode_get_attrib(packet, "from");
-	xmlnode *data_node = xmlnode_get_child(packet, "data");
-	const JabberData *data =
-		jabber_data_find_local_by_cid(xmlnode_get_attrib(data_node, "cid"));
+	const char *cid = xmlnode_get_attrib(data_node, "cid");
+	const JabberData *data = cid ? jabber_data_find_local_by_cid(cid) : NULL;
 
 	if (!data) {
 		xmlnode *item_not_found = xmlnode_new("item-not-found");
 
 		result = jabber_iq_new(js, JABBER_IQ_ERROR);
-		xmlnode_set_attrib(result->node, "to", who);
-		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		if (who)
+			xmlnode_set_attrib(result->node, "to", who);
+		xmlnode_set_attrib(result->node, "id", id);
 		xmlnode_insert_child(result->node, item_not_found);
 	} else {
 		result = jabber_iq_new(js, JABBER_IQ_RESULT);
-		xmlnode_set_attrib(result->node, "to", who);
-		xmlnode_set_attrib(result->node, "id", xmlnode_get_attrib(packet, "id"));
+		if (who)
+			xmlnode_set_attrib(result->node, "to", who);
+		xmlnode_set_attrib(result->node, "id", id);
 		xmlnode_insert_child(result->node,
 							 jabber_data_get_xml_definition(data));
 	}
@@ -235,6 +236,8 @@
 		g_free, jabber_data_delete);
 	remote_data_by_cid = g_hash_table_new_full(g_str_hash, g_str_equal,
 		g_free, jabber_data_delete);
+
+	jabber_iq_register_handler("data", XEP_0231_NAMESPACE, jabber_data_parse);	
 }
 
 void
--- a/libpurple/protocols/jabber/data.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/data.h	Sun Apr 05 21:13:10 2009 +0000
@@ -14,8 +14,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
  */
 
-#ifndef JABBER_DATA_H
-#define JABBER_DATA_H
+#ifndef PURPLE_JABBER_DATA_H
+#define PURPLE_JABBER_DATA_H
 
 #include "xmlnode.h"
 #include "jabber.h"
@@ -65,9 +65,10 @@
 void jabber_data_associate_remote(JabberData *data);
 
 /* handles iq requests */
-void jabber_data_parse(JabberStream *js, xmlnode *packet);
+void jabber_data_parse(JabberStream *js, const char *who, JabberIqType type,
+                       const char *id, xmlnode *data_node);
 
 void jabber_data_init(void);
 void jabber_data_uninit(void);
 
-#endif /* JABBER_DATA_H */
+#endif /* PURPLE_JABBER_DATA_H */
--- a/libpurple/protocols/jabber/disco.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/disco.c	Sun Apr 05 21:13:10 2009 +0000
@@ -46,9 +46,11 @@
 }
 
 static void
-jabber_disco_bytestream_server_cb(JabberStream *js, xmlnode *packet, gpointer data) {
+jabber_disco_bytestream_server_cb(JabberStream *js, const char *from,
+                                  JabberIqType type, const char *id,
+                                  xmlnode *packet, gpointer data)
+{
 	JabberBytestreamsStreamhost *sh = data;
-	const char *from = xmlnode_get_attrib(packet, "from");
 	xmlnode *query = xmlnode_get_child_with_namespace(packet, "query",
 		"http://jabber.org/protocol/bytestreams");
 
@@ -86,33 +88,27 @@
 }
 
 
-void jabber_disco_info_parse(JabberStream *js, xmlnode *packet) {
-	const char *from = xmlnode_get_attrib(packet, "from");
-	const char *type = xmlnode_get_attrib(packet, "type");
+void jabber_disco_info_parse(JabberStream *js, const char *from,
+                             JabberIqType type, const char *id,
+                             xmlnode *in_query)
+{
 
-	if(!from || !type)
+	if(!from)
 		return;
 
-	if(!strcmp(type, "get")) {
+	if(type == JABBER_IQ_GET) {
 		xmlnode *query, *identity, *feature;
 		JabberIq *iq;
+		const char *node = xmlnode_get_attrib(in_query, "node");
+		char *node_uri = NULL;
 
-		xmlnode *in_query;
-		const char *node = NULL;
-		char *node_uri = NULL;
-		
 		/* create custom caps node URI */
 		node_uri = g_strconcat(CAPS0115_NODE, "#", jabber_caps_get_own_hash(js), NULL);
 
-		if((in_query = xmlnode_get_child(packet, "query"))) {
-			node = xmlnode_get_attrib(in_query, "node");
-		}
-
-
 		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT,
 				"http://jabber.org/protocol/disco#info");
 
-		jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id"));
+		jabber_iq_set_id(iq, id);
 
 		xmlnode_set_attrib(iq->node, "to", from);
 		query = xmlnode_get_child(iq->node, "query");
@@ -146,7 +142,7 @@
 				if (!feat->is_enabled || feat->is_enabled(js, feat->namespace)) {
 					feature = xmlnode_new_child(query, "feature");
 					xmlnode_set_attrib(feature, "var", feat->namespace);
-				}	
+				}
 			}
 #ifdef USE_VV
 		} else if (g_str_equal(node, CAPS0115_NODE "#" "voice-v1")) {
@@ -177,8 +173,7 @@
 		}
 		g_free(node_uri);
 		jabber_iq_send(iq);
-	} else if(!strcmp(type, "result")) {
-		xmlnode *query = xmlnode_get_child(packet, "query");
+	} else if(type == JABBER_IQ_RESULT) {
 		xmlnode *child;
 		JabberID *jid;
 		JabberBuddy *jb;
@@ -195,7 +190,7 @@
 		if(jbr)
 			capabilities = jbr->capabilities;
 
-		for(child = query->child; child; child = child->next) {
+		for(child = in_query->child; child; child = child->next) {
 			if(child->type != XMLNODE_TYPE_TAG)
 				continue;
 
@@ -245,7 +240,7 @@
 					capabilities |= JABBER_CAP_IQ_SEARCH;
 				else if(!strcmp(var, "jabber:iq:register"))
 					capabilities |= JABBER_CAP_IQ_REGISTER;
-				else if(!strcmp(var, "http://www.xmpp.org/extensions/xep-0199.html#ns"))
+				else if(!strcmp(var, "urn:xmpp:ping"))
 					capabilities |= JABBER_CAP_PING;
 				else if(!strcmp(var, "http://jabber.org/protocol/commands")) {
 					capabilities |= JABBER_CAP_ADHOC;
@@ -266,7 +261,7 @@
 			jdicd->callback(js, from, capabilities, jdicd->data);
 			g_hash_table_remove(js->disco_callbacks, from);
 		}
-	} else if(!strcmp(type, "error")) {
+	} else if(type == JABBER_IQ_ERROR) {
 		JabberID *jid;
 		JabberBuddy *jb;
 		JabberBuddyResource *jbr = NULL;
@@ -290,28 +285,24 @@
 	}
 }
 
-void jabber_disco_items_parse(JabberStream *js, xmlnode *packet) {
-	const char *from = xmlnode_get_attrib(packet, "from");
-	const char *type = xmlnode_get_attrib(packet, "type");
-
-	if(type && !strcmp(type, "get")) {
+void jabber_disco_items_parse(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id,
+                              xmlnode *query)
+{
+	if(type == JABBER_IQ_GET) {
 		JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_RESULT,
 				"http://jabber.org/protocol/disco#items");
 
 		/* preserve node */
-		xmlnode *iq_query = xmlnode_get_child_with_namespace(iq->node,"query","http://jabber.org/protocol/disco#items");
-		if(iq_query) {
-			xmlnode *query = xmlnode_get_child_with_namespace(packet,"query","http://jabber.org/protocol/disco#items");
-			if(query) {
-				const char *node = xmlnode_get_attrib(query,"node");
-				if(node)
-					xmlnode_set_attrib(iq_query,"node",node);
-			}
-		}
+		xmlnode *iq_query = xmlnode_get_child(iq->node, "query");
+		const char *node = xmlnode_get_attrib(query, "node");
+		if(node)
+			xmlnode_set_attrib(iq_query,"node",node);
 
-		jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id"));
+		jabber_iq_set_id(iq, id);
 
-		xmlnode_set_attrib(iq->node, "to", from);
+		if (from)
+			xmlnode_set_attrib(iq->node, "to", from);
 		jabber_iq_send(iq);
 	}
 }
@@ -373,19 +364,18 @@
 }
 
 static void
-jabber_disco_server_info_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_disco_server_info_result_cb(JabberStream *js, const char *from,
+                                   JabberIqType type, const char *id,
+                                   xmlnode *packet, gpointer data)
 {
 	xmlnode *query, *child;
-	const char *from = xmlnode_get_attrib(packet, "from");
-	const char *type = xmlnode_get_attrib(packet, "type");
 
-	if((!from || !type) ||
-	   (strcmp(from, js->user->domain))) {
+	if (!from || strcmp(from, js->user->domain)) {
 		jabber_disco_finish_server_info_result_cb(js);
 		return;
 	}
 
-	if(strcmp(type, "result")) {
+	if (type == JABBER_IQ_ERROR) {
 		/* A common way to get here is for the server not to support xmlns http://jabber.org/protocol/disco#info */
 		jabber_disco_finish_server_info_result_cb(js);
 		return;
@@ -451,19 +441,16 @@
 }
 
 static void
-jabber_disco_server_items_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_disco_server_items_result_cb(JabberStream *js, const char *from,
+                                    JabberIqType type, const char *id,
+                                    xmlnode *packet, gpointer data)
 {
 	xmlnode *query, *child;
-	const char *from = xmlnode_get_attrib(packet, "from");
-	const char *type = xmlnode_get_attrib(packet, "type");
 
-	if(!from || !type)
+	if (!from || strcmp(from, js->user->domain) != 0)
 		return;
 
-	if(strcmp(from, js->user->domain))
-		return;
-
-	if(strcmp(type, "result"))
+	if (type == JABBER_IQ_ERROR)
 		return;
 
 	while(js->chat_servers) {
@@ -538,5 +525,3 @@
 
 	jabber_iq_send(iq);
 }
-
-
--- a/libpurple/protocols/jabber/disco.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/disco.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,20 +19,22 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_DISCO_H_
-#define _PURPLE_JABBER_DISCO_H_
+#ifndef PURPLE_JABBER_DISCO_H_
+#define PURPLE_JABBER_DISCO_H_
 
 #include "jabber.h"
 
 typedef void (JabberDiscoInfoCallback)(JabberStream *js, const char *who,
 		JabberCapabilities capabilities, gpointer data);
 
-void jabber_disco_info_parse(JabberStream *js, xmlnode *packet);
-void jabber_disco_items_parse(JabberStream *js, xmlnode *packet);
+void jabber_disco_info_parse(JabberStream *js, const char *from,
+                             JabberIqType type, const char *id, xmlnode *in_query);
+void jabber_disco_items_parse(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id, xmlnode *query);
 
 void jabber_disco_items_server(JabberStream *js);
 
 void jabber_disco_info_do(JabberStream *js, const char *who,
 		JabberDiscoInfoCallback *callback, gpointer data);
 
-#endif /* _PURPLE_JABBER_DISCO_H_ */
+#endif /* PURPLE_JABBER_DISCO_H_ */
--- a/libpurple/protocols/jabber/google.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/google.c	Sun Apr 05 21:13:10 2009 +0000
@@ -374,7 +374,7 @@
 }
 
 static void
-google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+google_session_handle_initiate(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
 {
 	JabberIq *result;
 	GList *codecs = NULL;
@@ -440,13 +440,13 @@
 	purple_media_codec_list_free(codecs);
 
 	result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+	jabber_iq_set_id(result, iq_id);
 	xmlnode_set_attrib(result->node, "to", session->remote_jid);
 	jabber_iq_send(result);
 }
 
 static void 
-google_session_handle_candidates(JabberStream  *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+google_session_handle_candidates(JabberStream  *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
 {
 	JabberIq *result;
 	GList *list = NULL;
@@ -480,13 +480,13 @@
 	purple_media_candidate_list_free(list);
 
 	result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+	jabber_iq_set_id(result, iq_id);
 	xmlnode_set_attrib(result->node, "to", session->remote_jid);
 	jabber_iq_send(result);
 }
 
 static void
-google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+google_session_handle_accept(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
 {
 	xmlnode *desc_element = xmlnode_get_child(sess, "description");
 	xmlnode *codec_element = xmlnode_get_child(desc_element, "payload-type");
@@ -514,58 +514,54 @@
 			NULL, NULL, FALSE);
 
 	result = jabber_iq_new(js, JABBER_IQ_RESULT);
-	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+	jabber_iq_set_id(result, iq_id);
 	xmlnode_set_attrib(result->node, "to", session->remote_jid);
 	jabber_iq_send(result);
 }
 
 static void
-google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+google_session_handle_reject(JabberStream *js, GoogleSession *session, xmlnode *sess)
 {
 	purple_media_end(session->media, NULL, NULL);
 }
 
 static void
-google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *packet, xmlnode *sess)
+google_session_handle_terminate(JabberStream *js, GoogleSession *session, xmlnode *sess)
 {
 	purple_media_end(session->media, NULL, NULL);
 }
 
 static void
-google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *packet)
+google_session_parse_iq(JabberStream *js, GoogleSession *session, xmlnode *sess, const char *iq_id)
 {
-	xmlnode *sess = xmlnode_get_child(packet, "session");	
 	const char *type = xmlnode_get_attrib(sess, "type");
 
 	if (!strcmp(type, "initiate")) {
-		google_session_handle_initiate(js, session, packet, sess);
+		google_session_handle_initiate(js, session, sess, iq_id);
 	} else if (!strcmp(type, "accept")) {
-		google_session_handle_accept(js, session, packet, sess);
+		google_session_handle_accept(js, session, sess, iq_id);
 	} else if (!strcmp(type, "reject")) {
-		google_session_handle_reject(js, session, packet, sess);
+		google_session_handle_reject(js, session, sess);
 	} else if (!strcmp(type, "terminate")) {
-		google_session_handle_terminate(js, session, packet, sess);
+		google_session_handle_terminate(js, session, sess);
 	} else if (!strcmp(type, "candidates")) {
-		google_session_handle_candidates(js, session, packet, sess);
+		google_session_handle_candidates(js, session, sess, iq_id);
 	}
 }
 
 void
-jabber_google_session_parse(JabberStream *js, xmlnode *packet)
+jabber_google_session_parse(JabberStream *js, const char *from,
+                            JabberIqType type, const char *iq_id,
+                            xmlnode *session_node)
 {
 	GoogleSession *session = NULL;
 	GoogleSessionId id;
 
-	xmlnode *session_node;
 	xmlnode *desc_node;
 
 	GList *iter = NULL;
 
-	if (strcmp(xmlnode_get_attrib(packet, "type"), "set"))
-		return;
-
-	session_node = xmlnode_get_child(packet, "session");
-	if (!session_node)
+	if (type != JABBER_IQ_SET)
 		return;
 
 	id.id = (gchar*)xmlnode_get_attrib(session_node, "id");
@@ -591,7 +587,7 @@
 	}
 
 	if (session) {
-		google_session_parse_iq(js, session, packet);
+		google_session_parse_iq(js, session, session_node, iq_id);
 		return;
 	}
 
@@ -608,18 +604,18 @@
 	session->js = js;
 	session->remote_jid = g_strdup(session->id.initiator);
 
-	google_session_parse_iq(js, session, packet);
+	google_session_parse_iq(js, session, session_node, iq_id);
 }
 #endif /* USE_VV */
 
 static void
-jabber_gmail_parse(JabberStream *js, xmlnode *packet, gpointer nul)
+jabber_gmail_parse(JabberStream *js, const char *from,
+                   JabberIqType type, const char *id,
+                   xmlnode *packet, gpointer nul)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
 	xmlnode *child;
-	xmlnode *message, *sender_node, *subject_node;
-	const char *from, *to, *url, *tid;
-	char *subject;
+	xmlnode *message;
+	const char *to, *url;
 	const char *in_str;
 	char *to_name;
 	char *default_tos[1];
@@ -629,7 +625,7 @@
 	const char **tos, **froms, **urls;
 	char **subjects;
 
-	if (strcmp(type, "result"))
+	if (type == JABBER_IQ_ERROR)
 		return;
 
 	child = xmlnode_get_child(packet, "mailbox");
@@ -670,6 +666,10 @@
 
 	message= xmlnode_get_child(child, "mail-thread-info");
 	for (i=0; message; message = xmlnode_get_next_twin(message), i++) {
+		xmlnode *sender_node, *subject_node;
+		const char *from, *tid;
+		char *subject;
+
 		subject_node = xmlnode_get_child(message, "subject");
 		sender_node  = xmlnode_get_child(message, "senders");
 		sender_node  = xmlnode_get_child(sender_node, "sender");
@@ -727,9 +727,9 @@
 }
 
 void
-jabber_gmail_poke(JabberStream *js, xmlnode *packet)
+jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
+                  const char *id, xmlnode *new_mail)
 {
-	const char *type;
 	xmlnode *query;
 	JabberIq *iq;
 
@@ -737,11 +737,8 @@
 	if (!purple_account_get_check_mail(js->gc->account))
 		return;
 
-	type = xmlnode_get_attrib(packet, "type");
-
-
 	/* Is this an initial incoming mail notification? If so, send a request for more info */
-	if (strcmp(type, "set") || !xmlnode_get_child(packet, "new-mail"))
+	if (type != JABBER_IQ_SET)
 		return;
 
 	purple_debug(PURPLE_DEBUG_MISC, "jabber",
@@ -1159,48 +1156,77 @@
 }
 
 static void
-jabber_google_jingle_info_cb(JabberStream *js, xmlnode *result,
-	gpointer nullus)
-{	
-	if (result) {
-		const xmlnode *query = 
-			xmlnode_get_child_with_namespace(result, "query", 
-				GOOGLE_JINGLE_INFO_NAMESPACE);
+jabber_google_jingle_info_common(JabberStream *js, const char *from,
+                                 JabberIqType type, xmlnode *query)
+{
+	const xmlnode *stun = xmlnode_get_child(query, "stun");
+	gchar *my_bare_jid;
 
-		if (query) {
-			const xmlnode *stun = xmlnode_get_child(query, "stun");
+	/*
+	 * Make sure that random people aren't sending us STUN servers. Per
+	 * http://code.google.com/apis/talk/jep_extensions/jingleinfo.html, these
+	 * stanzas are stamped from our bare JID.
+	 */
+	if (from) {
+		my_bare_jid = g_strdup_printf("%s@%s", js->user->node, js->user->domain);
+		if (!purple_strequal(from, my_bare_jid)) {
+			purple_debug_warning("jabber", "got google:jingleinfo with invalid from (%s)\n",
+			                  from);
+			g_free(my_bare_jid);
+			return;
+		}
 
-			purple_debug_info("jabber", "got google:jingleinfo\n");
-
-			if (stun) {
-				xmlnode *server = xmlnode_get_child(stun, "server");
+		g_free(my_bare_jid);
+	}
 
-				if (server) {
-					const gchar *host = xmlnode_get_attrib(server, "host");
-					const gchar *udp = xmlnode_get_attrib(server, "udp");
+	if (type == JABBER_IQ_ERROR || type == JABBER_IQ_GET)
+		return;
+
+	purple_debug_info("jabber", "got google:jingleinfo\n");
+
+	if (stun) {
+		xmlnode *server = xmlnode_get_child(stun, "server");
 
-					if (host && udp) {
-						int port = atoi(udp);
-						/* if there, would already be an ongoing query, 
-						 cancel it */
-						if (js->stun_query)
-							purple_dnsquery_destroy(js->stun_query);
+		if (server) {
+			const gchar *host = xmlnode_get_attrib(server, "host");
+			const gchar *udp = xmlnode_get_attrib(server, "udp");
 
-						js->stun_query = purple_dnsquery_a(host, port, 
-							jabber_google_stun_lookup_cb, js);
-					}
-				}
+			if (host && udp) {
+				int port = atoi(udp);
+				/* if there, would already be an ongoing query, 
+				 cancel it */
+				if (js->stun_query)
+					purple_dnsquery_destroy(js->stun_query);
+
+				js->stun_query = purple_dnsquery_a(host, port, 
+					jabber_google_stun_lookup_cb, js);
 			}
-			/* should perhaps handle relays later on, or maybe wait until
-			 Google supports a common standard... */
 		}
 	}
+	/* should perhaps handle relays later on, or maybe wait until
+	 Google supports a common standard... */
+}
+
+static void
+jabber_google_jingle_info_cb(JabberStream *js, const char *from,
+                             JabberIqType type, const char *id,
+                             xmlnode *packet, gpointer data)
+{
+	xmlnode *query = xmlnode_get_child_with_namespace(packet, "query",
+			GOOGLE_JINGLE_INFO_NAMESPACE);
+
+	if (query)
+		jabber_google_jingle_info_common(js, from, type, query);
+	else
+		purple_debug_warning("jabber", "Got invalid google:jingleinfo\n");
 }
 
 void
-jabber_google_handle_jingle_info(JabberStream *js, xmlnode *packet)
+jabber_google_handle_jingle_info(JabberStream *js, const char *from,
+                                 JabberIqType type, const char *id,
+                                 xmlnode *child)
 {
-	jabber_google_jingle_info_cb(js, packet, NULL);
+	jabber_google_jingle_info_common(js, from, type, child);
 }
 
 void
--- a/libpurple/protocols/jabber/google.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/google.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef _PURPLE_GOOGLE_H_
-#define _PURPLE_GOOGLE_H_
+#ifndef PURPLE_JABBER_GOOGLE_H_
+#define PURPLE_JABBER_GOOGLE_H_
 
 /* This is a place for Google Talk-specific XMPP extensions to live
  * such that they don't intermingle with code for the XMPP RFCs and XEPs :) */
@@ -31,7 +31,8 @@
 #define GOOGLE_JINGLE_INFO_NAMESPACE "google:jingleinfo"
 
 void jabber_gmail_init(JabberStream *js);
-void jabber_gmail_poke(JabberStream *js, xmlnode *node);
+void jabber_gmail_poke(JabberStream *js, const char *from, JabberIqType type,
+                       const char *id, xmlnode *new_mail);
 
 void jabber_google_roster_init(JabberStream *js);
 void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item);
@@ -50,9 +51,11 @@
 char *jabber_google_format_to_html(const char *text);
 
 gboolean jabber_google_session_initiate(JabberStream *js, const gchar *who, PurpleMediaSessionType type);
-void jabber_google_session_parse(JabberStream *js, xmlnode *node);
+void jabber_google_session_parse(JabberStream *js, const char *from, JabberIqType type, const char *iq, xmlnode *session);
 
-void jabber_google_handle_jingle_info(JabberStream *js, xmlnode *packet);
+void jabber_google_handle_jingle_info(JabberStream *js, const char *from,
+                                      JabberIqType type, const char *id,
+                                      xmlnode *child);
 void jabber_google_send_jingle_info(JabberStream *js);
 
-#endif   /* _PURPLE_GOOGLE_H_ */
+#endif   /* PURPLE_JABBER_GOOGLE_H_ */
--- a/libpurple/protocols/jabber/ibb.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/ibb.c	Sun Apr 05 21:13:10 2009 +0000
@@ -46,12 +46,10 @@
 }
 
 JabberIBBSession *
-jabber_ibb_session_create_from_xmlnode(JabberStream *js, xmlnode *packet,
-	gpointer user_data)
+jabber_ibb_session_create_from_xmlnode(JabberStream *js, const char *from,
+	const char *id, xmlnode *open, gpointer user_data)
 {
 	JabberIBBSession *sess = NULL;
-	xmlnode *open = xmlnode_get_child_with_namespace(packet, "open",
-		XEP_0047_NAMESPACE);
 	const gchar *sid = xmlnode_get_attrib(open, "sid");
 	const gchar *block_size = xmlnode_get_attrib(open, "block-size");
 
@@ -66,9 +64,8 @@
 		return NULL;
 	}
 
-	sess = jabber_ibb_session_create(js, sid,
-			xmlnode_get_attrib(packet, "from"), user_data);
-	sess->id = g_strdup(xmlnode_get_attrib(packet, "id"));
+	sess = jabber_ibb_session_create(js, sid, from, user_data);
+	sess->id = g_strdup(id);
 	sess->block_size = atoi(block_size);
 	/* if we create a session from an incoming <open/> request, it means the
 	  session is immediatly open... */
@@ -198,11 +195,13 @@
 }
 
 static void
-jabber_ibb_session_opened_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_ibb_session_opened_cb(JabberStream *js, const char *from,
+                             JabberIqType type, const char *id,
+                             xmlnode *packet, gpointer data)
 {
 	JabberIBBSession *sess = (JabberIBBSession *) data;
 
-	if (strcmp(xmlnode_get_attrib(packet, "type"), "error") == 0) {
+	if (type == JABBER_IQ_ERROR) {
 		sess->state = JABBER_IBB_SESSION_ERROR;
 	} else {
 		sess->state = JABBER_IBB_SESSION_OPENED;
@@ -274,10 +273,11 @@
 }
 
 static void
-jabber_ibb_session_send_acknowledge_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_ibb_session_send_acknowledge_cb(JabberStream *js, const char *from,
+                                       JabberIqType type, const char *id,
+                                       xmlnode *packet, gpointer data)
 {
 	JabberIBBSession *sess = (JabberIBBSession *) data;
-	xmlnode *error = xmlnode_get_child(packet, "error");
 
 	if (sess) {
 		/* reset callback */
@@ -286,7 +286,7 @@
 			sess->last_iq_id = NULL;
 		}
 
-		if (error) {
+		if (type == JABBER_IQ_ERROR) {
 			jabber_ibb_session_close(sess);
 			sess->state = JABBER_IBB_SESSION_ERROR;
 
@@ -351,7 +351,7 @@
 }
 
 static void
-jabber_ibb_send_error_response(JabberStream *js, xmlnode *packet)
+jabber_ibb_send_error_response(JabberStream *js, const char *to, const char *id)
 {
 	JabberIq *result = jabber_iq_new(js, JABBER_IQ_ERROR);
 	xmlnode *error = xmlnode_new("error");
@@ -361,9 +361,8 @@
 		"urn:ietf:params:xml:ns:xmpp-stanzas");
 	xmlnode_set_attrib(error, "code", "440");
 	xmlnode_set_attrib(error, "type", "cancel");
-	jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
-	xmlnode_set_attrib(result->node, "to",
-		xmlnode_get_attrib(packet, "from"));
+	jabber_iq_set_id(result, id);
+	xmlnode_set_attrib(result->node, "to", to);
 	xmlnode_insert_child(error, item_not_found);
 	xmlnode_insert_child(result->node, error);
 
@@ -371,20 +370,17 @@
 }
 
 void
-jabber_ibb_parse(JabberStream *js, xmlnode *packet)
+jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type,
+                 const char *id, xmlnode *child)
 {
-	xmlnode *data = xmlnode_get_child_with_namespace(packet, "data",
-		XEP_0047_NAMESPACE);
-	xmlnode *close = xmlnode_get_child_with_namespace(packet, "close",
-		XEP_0047_NAMESPACE);
-	xmlnode *open = xmlnode_get_child_with_namespace(packet, "open",
-		XEP_0047_NAMESPACE);
-	const gchar *sid =
-		data ? xmlnode_get_attrib(data, "sid") :
-			close ? xmlnode_get_attrib(close, "sid") : NULL;
+	const char *name = child->name;
+	gboolean data  = g_str_equal(name, "data");
+	gboolean close = g_str_equal(name, "close");
+	gboolean open  = g_str_equal(name, "open");
+	const gchar *sid = (data || close) ?
+		xmlnode_get_attrib(child, "sid") : NULL;
 	JabberIBBSession *sess =
 		sid ? g_hash_table_lookup(jabber_ibb_sessions, sid) : NULL;
-	const gchar *who = xmlnode_get_attrib(packet, "from");
 
 	if (sess) {
 
@@ -394,7 +390,7 @@
 			purple_debug_error("jabber",
 				"Got IBB iq from wrong JID, ignoring\n");
 		} else if (data) {
-			const gchar *seq_attr = xmlnode_get_attrib(data, "seq");
+			const gchar *seq_attr = xmlnode_get_attrib(child, "seq");
 			guint16 seq = (seq_attr ? atoi(seq_attr) : 0);
 
 			/* reject the data, and set the session in error if we get an
@@ -403,12 +399,11 @@
 				/* sequence # is the expected... */
 				JabberIq *result = jabber_iq_new(js, JABBER_IQ_RESULT);
 
-				jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
-				xmlnode_set_attrib(result->node, "to",
-					xmlnode_get_attrib(packet, "from"));
+				jabber_iq_set_id(result, id);
+				xmlnode_set_attrib(result->node, "to", who);
 
 				if (sess->data_received_cb) {
-					gchar *base64 = xmlnode_get_data(data);
+					gchar *base64 = xmlnode_get_data(child);
 					gsize size;
 					gpointer rawdata = purple_base64_decode(base64, &size);
 
@@ -475,20 +470,19 @@
 			 iterator = g_list_next(iterator)) {
 			JabberIBBOpenHandler *handler = iterator->data;
 
-			if (handler(js, packet)) {
+			if (handler(js, who, id, child)) {
 				result = jabber_iq_new(js, JABBER_IQ_RESULT);
-				xmlnode_set_attrib(result->node, "to",
-					xmlnode_get_attrib(packet, "from"));
-				jabber_iq_set_id(result, xmlnode_get_attrib(packet, "id"));
+				xmlnode_set_attrib(result->node, "to", who);
+				jabber_iq_set_id(result, id);
 				jabber_iq_send(result);
 				return;
 			}
 		}
 		/* no open callback returned success, reject */
-		jabber_ibb_send_error_response(js, packet);
+		jabber_ibb_send_error_response(js, who, id);
 	} else {
 		/* send error reply */
-		jabber_ibb_send_error_response(js, packet);
+		jabber_ibb_send_error_response(js, who, id);
 	}
 }
 
@@ -508,6 +502,10 @@
 jabber_ibb_init(void)
 {
 	jabber_ibb_sessions = g_hash_table_new(g_str_hash, g_str_equal);
+
+	jabber_iq_register_handler("close", XEP_0047_NAMESPACE, jabber_ibb_parse);
+	jabber_iq_register_handler("data", XEP_0047_NAMESPACE, jabber_ibb_parse);
+	jabber_iq_register_handler("open", XEP_0047_NAMESPACE, jabber_ibb_parse);
 }
 
 void
--- a/libpurple/protocols/jabber/ibb.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/ibb.h	Sun Apr 05 21:13:10 2009 +0000
@@ -14,8 +14,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
  */
 
-#ifndef _PURPLE_JABBER_IBB_H_
-#define _PURPLE_JABBER_IBB_H_
+#ifndef PURPLE_JABBER_IBB_H_
+#define PURPLE_JABBER_IBB_H_
 
 #include "jabber.h"
 #include "iq.h"
@@ -32,7 +32,8 @@
 typedef void (JabberIBBErrorCallback)(JabberIBBSession *);
 typedef void (JabberIBBSentCallback)(JabberIBBSession *);
 
-typedef gboolean (JabberIBBOpenHandler)(JabberStream *js, xmlnode *packet);
+typedef gboolean (JabberIBBOpenHandler)(JabberStream *js, const char *from,
+                                        const char *id, xmlnode *open);
 
 typedef enum {
 	JABBER_IBB_SESSION_NOT_OPENED,
@@ -71,7 +72,7 @@
 JabberIBBSession *jabber_ibb_session_create(JabberStream *js, const gchar *sid,
 	const gchar *who, gpointer user_data);
 JabberIBBSession *jabber_ibb_session_create_from_xmlnode(JabberStream *js,
-	xmlnode *packet, gpointer user_data);
+	const gchar *from, const gchar *id, xmlnode *open, gpointer user_data);
 
 void jabber_ibb_session_destroy(JabberIBBSession *sess);
 
@@ -107,7 +108,8 @@
 gpointer jabber_ibb_session_get_user_data(JabberIBBSession *sess);
 
 /* handle incoming packet */
-void jabber_ibb_parse(JabberStream *js, xmlnode *packet);
+void jabber_ibb_parse(JabberStream *js, const char *who, JabberIqType type,
+                      const char *id, xmlnode *child);
 
 /* add a handler for open session */
 void jabber_ibb_register_open_handler(JabberIBBOpenHandler *cb);
@@ -116,4 +118,4 @@
 void jabber_ibb_init(void);
 void jabber_ibb_uninit(void);
 
-#endif /* _PURPLE_JABBER_IBB_H_ */
+#endif /* PURPLE_JABBER_IBB_H_ */
--- a/libpurple/protocols/jabber/iq.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/iq.c	Sun Apr 05 21:13:10 2009 +0000
@@ -144,23 +144,19 @@
 	g_free(iq);
 }
 
-static void jabber_iq_last_parse(JabberStream *js, xmlnode *packet)
+static void jabber_iq_last_parse(JabberStream *js, const char *from,
+                                 JabberIqType type, const char *id,
+                                 xmlnode *packet)
 {
 	JabberIq *iq;
-	const char *type;
-	const char *from;
-	const char *id;
 	xmlnode *query;
 	char *idle_time;
 
-	type = xmlnode_get_attrib(packet, "type");
-	from = xmlnode_get_attrib(packet, "from");
-	id = xmlnode_get_attrib(packet, "id");
-
-	if(type && !strcmp(type, "get")) {
+	if(type == JABBER_IQ_GET) {
 		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:last");
 		jabber_iq_set_id(iq, id);
-		xmlnode_set_attrib(iq->node, "to", from);
+		if (from)
+			xmlnode_set_attrib(iq->node, "to", from);
 
 		query = xmlnode_get_child(iq->node, "query");
 
@@ -172,88 +168,67 @@
 	}
 }
 
-static void jabber_iq_time_parse(JabberStream *js, xmlnode *packet)
+static void jabber_iq_time_parse(JabberStream *js, const char *from,
+                                 JabberIqType type, const char *id,
+                                 xmlnode *child)
 {
-	const char *type, *from, *id, *xmlns;
+	const char *xmlns;
 	JabberIq *iq;
-	xmlnode *query;
 	time_t now_t;
+	struct tm now_local;
+	struct tm now_utc;
 	struct tm *now;
 
 	time(&now_t);
 	now = localtime(&now_t);
-
-	type = xmlnode_get_attrib(packet, "type");
-	from = xmlnode_get_attrib(packet, "from");
-	id = xmlnode_get_attrib(packet, "id");
+	memcpy(&now_local, now, sizeof(struct tm));
+	now = gmtime(&now_t);
+	memcpy(&now_utc, now, sizeof(struct tm));
 
-	/* we're gonna throw this away in a moment, but we need it
-	 * to get the xmlns, so we can figure out if this is
-	 * jabber:iq:time or urn:xmpp:time */
-	query = xmlnode_get_child(packet, "query");
-	xmlns = xmlnode_get_namespace(query);
+	xmlns = xmlnode_get_namespace(child);
 
-	if(type && !strcmp(type, "get")) {
+	if(type == JABBER_IQ_GET) {
 		xmlnode *utc;
-		const char *date;
+		const char *date, *tz, *display;
 
-		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, xmlns);
+		iq = jabber_iq_new(js, JABBER_IQ_RESULT);
 		jabber_iq_set_id(iq, id);
-		xmlnode_set_attrib(iq->node, "to", from);
-
-		query = xmlnode_get_child(iq->node, "query");
+		if (from)
+			xmlnode_set_attrib(iq->node, "to", from);
 
-		date = purple_utf8_strftime("%Y%m%dT%T", now);
-		utc = xmlnode_new_child(query, "utc");
-		xmlnode_insert_data(utc, date, -1);
+		child = xmlnode_new_child(iq->node, child->name);
+		xmlnode_set_namespace(child, xmlns);
+		utc = xmlnode_new_child(child, "utc");
 
 		if(!strcmp("urn:xmpp:time", xmlns)) {
-			xmlnode_insert_data(utc, "Z", 1); /* of COURSE the thing that is the same is different */
+			tz = purple_get_tzoff_str(&now_local, TRUE);
+			xmlnode_insert_data(xmlnode_new_child(child, "tzo"), tz, -1);
 
-			date = purple_get_tzoff_str(now, TRUE);
-			xmlnode_insert_data(xmlnode_new_child(query, "tzo"), date, -1);
+			date = purple_utf8_strftime("%FT%TZ", &now_utc);
+			xmlnode_insert_data(utc, date, -1);
 		} else { /* jabber:iq:time */
-			date = purple_utf8_strftime("%Z", now);
-			xmlnode_insert_data(xmlnode_new_child(query, "tz"), date, -1);
+			tz = purple_utf8_strftime("%Z", &now_local);
+			xmlnode_insert_data(xmlnode_new_child(child, "tz"), tz, -1);
 
-			date = purple_utf8_strftime("%d %b %Y %T", now);
-			xmlnode_insert_data(xmlnode_new_child(query, "display"), date, -1);
+			date = purple_utf8_strftime("%Y%m%dT%T", &now_utc);
+			xmlnode_insert_data(utc, date, -1);
+
+			display = purple_utf8_strftime("%d %b %Y %T", &now_local);
+			xmlnode_insert_data(xmlnode_new_child(child, "display"), display, -1);
 		}
 
 		jabber_iq_send(iq);
 	}
 }
 
-static void urn_xmpp_ping_parse(JabberStream *js, xmlnode *packet)
-{
-	const char *type, *id, *from;
-	JabberIq *iq;
-
-	type = xmlnode_get_attrib(packet, "type");
-	from = xmlnode_get_attrib(packet, "from");
-	id = xmlnode_get_attrib(packet, "id");
-
-	if(type && !strcmp(type, "get")) {
-		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "urn:xmpp:ping");
-
-		jabber_iq_set_id(iq, id);
-		xmlnode_set_attrib(iq->node, "to", from);
-
-		jabber_iq_send(iq);
-	} else {
-		/* XXX: error */
-	}
-}
-
-static void jabber_iq_version_parse(JabberStream *js, xmlnode *packet)
+static void jabber_iq_version_parse(JabberStream *js, const char *from,
+                                    JabberIqType type, const char *id,
+                                    xmlnode *packet)
 {
 	JabberIq *iq;
-	const char *type, *from, *id;
 	xmlnode *query;
 
-	type = xmlnode_get_attrib(packet, "type");
-
-	if(type && !strcmp(type, "get")) {
+	if(type == JABBER_IQ_GET) {
 		GHashTable *ui_info;
 		const char *ui_name = NULL, *ui_version = NULL;
 #if 0
@@ -266,11 +241,10 @@
 					osinfo.machine);
 		}
 #endif
-		from = xmlnode_get_attrib(packet, "from");
-		id = xmlnode_get_attrib(packet, "id");
 
 		iq = jabber_iq_new_query(js, JABBER_IQ_RESULT, "jabber:iq:version");
-		xmlnode_set_attrib(iq->node, "to", from);
+		if (from)
+			xmlnode_set_attrib(iq->node, "to", from);
 		jabber_iq_set_id(iq, id);
 
 		query = xmlnode_get_child(iq->node, "query");
@@ -311,33 +285,56 @@
 void jabber_iq_parse(JabberStream *js, xmlnode *packet)
 {
 	JabberCallbackData *jcd;
-	xmlnode *query, *error, *x;
+	xmlnode *child, *error, *x;
 	const char *xmlns;
-	const char *type, *id, *from;
-	JabberIqHandler *jih;
+	const char *iq_type, *id, *from;
+	JabberIqType type = JABBER_IQ_NONE;
 
-	query = xmlnode_get_child(packet, "query");
-	type = xmlnode_get_attrib(packet, "type");
+	/*
+	 * child will be either the first tag child or NULL if there is no child.
+	 * Historically, we used just the 'query' subchild, but newer XEPs use
+	 * differently named children. Grabbing the first child is (for the time
+	 * being) sufficient.
+	 */
+	for (child = packet->child; child; child = child->next) {
+		if (child->type == XMLNODE_TYPE_TAG)
+			break;
+	}
+
+	iq_type = xmlnode_get_attrib(packet, "type");
 	from = xmlnode_get_attrib(packet, "from");
 	id = xmlnode_get_attrib(packet, "id");
 
-	if(type == NULL || !(!strcmp(type, "get") || !strcmp(type, "set")
-			|| !strcmp(type, "result") || !strcmp(type, "error"))) {
+	if (iq_type) {
+		if (!strcmp(iq_type, "get"))
+			type = JABBER_IQ_GET;
+		else if (!strcmp(iq_type, "set"))
+			type = JABBER_IQ_SET;
+		else if (!strcmp(iq_type, "result"))
+			type = JABBER_IQ_RESULT;
+		else if (!strcmp(iq_type, "error"))
+			type = JABBER_IQ_ERROR;
+	}
+
+	if (type == JABBER_IQ_NONE) {
 		purple_debug_error("jabber", "IQ with invalid type ('%s') - ignoring.\n",
-						   type ? type : "(null)");
+						   iq_type ? iq_type : "(null)");
 		return;
 	}
 
 	/* All IQs must have an ID, so send an error for a set/get that doesn't */
 	if(!id || !*id) {
 
-		if(!strcmp(type, "set") || !strcmp(type, "get")) {
+		if(type == JABBER_IQ_SET || type == JABBER_IQ_GET) {
 			JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR);
 
 			xmlnode_free(iq->node);
 			iq->node = xmlnode_copy(packet);
-			xmlnode_set_attrib(iq->node, "to", from);
-			xmlnode_remove_attrib(iq->node, "from");
+			if (from) {
+				xmlnode_set_attrib(iq->node, "to", from);
+				xmlnode_remove_attrib(iq->node, "from");
+			}
+
 			xmlnode_set_attrib(iq->node, "type", "error");
 			/* This id is clearly not useful, but we must put something there for a valid stanza */
 			iq->id = jabber_get_next_id(js);
@@ -349,79 +346,46 @@
 
 			jabber_iq_send(iq);
 		} else
-			purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n", type);
+			purple_debug_error("jabber", "IQ of type '%s' missing id - ignoring.\n",
+			                   iq_type);
 
 		return;
 	}
 
 	/* First, lets see if a special callback got registered */
-
-	if(!strcmp(type, "result") || !strcmp(type, "error")) {
-		if(id && *id && (jcd = g_hash_table_lookup(js->iq_callbacks, id))) {
-			jcd->callback(js, packet, jcd->data);
+	if(type == JABBER_IQ_RESULT || type == JABBER_IQ_ERROR) {
+		if((jcd = g_hash_table_lookup(js->iq_callbacks, id))) {
+			jcd->callback(js, from, type, id, packet, jcd->data);
 			jabber_iq_remove_callback_by_id(js, id);
 			return;
 		}
 	}
 
 	/* Apparently not, so lets see if we have a pre-defined handler */
+	if(child && (xmlns = xmlnode_get_namespace(child))) {
+		char *key = g_strdup_printf("%s %s", child->name, xmlns);
+		JabberIqHandler *jih = g_hash_table_lookup(iq_handlers, key);
+		g_free(key);
 
-	if(query && (xmlns = xmlnode_get_namespace(query))) {
-		if((jih = g_hash_table_lookup(iq_handlers, xmlns))) {
-			jih(js, packet);
+		if(jih) {
+			jih(js, from, type, id, child);
 			return;
 		}
 	}
 
-#ifdef USE_VV
-	if (xmlnode_get_child_with_namespace(packet, "session", "http://www.google.com/session")) {
-		jabber_google_session_parse(js, packet);
-		return;
-	}
-#endif
-
-	if(xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si")) {
-		jabber_si_parse(js, packet);
-		return;
-	}
-
-	if(xmlnode_get_child_with_namespace(packet, "new-mail", "google:mail:notify")) {
-		jabber_gmail_poke(js, packet);
-		return;
-	}
-
 	purple_debug_info("jabber", "jabber_iq_parse\n");
 
-	if(xmlnode_get_child_with_namespace(packet, "ping", "urn:xmpp:ping")) {
-		jabber_ping_parse(js, packet);
-		return;
-	}
-
-	if (xmlnode_get_child_with_namespace(packet, "data", XEP_0231_NAMESPACE)) {
-		jabber_data_parse(js, packet);
-		return;
-	}
-
-	if (xmlnode_get_child_with_namespace(packet, "data", XEP_0047_NAMESPACE)
-		|| xmlnode_get_child_with_namespace(packet, "close", XEP_0047_NAMESPACE)
-		|| xmlnode_get_child_with_namespace(packet, "open", XEP_0047_NAMESPACE)) {
-		jabber_ibb_parse(js, packet);
-		return;
-	}
-
-	if (xmlnode_get_child_with_namespace(packet, "jingle", JINGLE)) {
-		jingle_parse(js, packet);
-		return;
-	}
-
 	/* If we get here, send the default error reply mandated by XMPP-CORE */
-	if(!strcmp(type, "set") || !strcmp(type, "get")) {
+	if(type == JABBER_IQ_SET || type == JABBER_IQ_GET) {
 		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_ERROR);
 
 		xmlnode_free(iq->node);
 		iq->node = xmlnode_copy(packet);
-		xmlnode_set_attrib(iq->node, "to", from);
-		xmlnode_remove_attrib(iq->node, "from");
+		if (from) {
+			xmlnode_set_attrib(iq->node, "to", from);
+			xmlnode_remove_attrib(iq->node, "from");
+		}
+
 		xmlnode_set_attrib(iq->node, "type", "error");
 		error = xmlnode_new_child(iq->node, "error");
 		xmlnode_set_attrib(error, "type", "cancel");
@@ -433,31 +397,50 @@
 	}
 }
 
-void jabber_iq_register_handler(const char *xmlns, JabberIqHandler *handlerfunc)
+void jabber_iq_register_handler(const char *node, const char *xmlns, JabberIqHandler *handlerfunc)
 {
-	g_hash_table_replace(iq_handlers, g_strdup(xmlns), handlerfunc);
+	/*
+	 * This is valid because nodes nor namespaces cannot have spaces in them
+	 * (see http://www.w3.org/TR/2006/REC-xml-20060816/ and
+	 * http://www.w3.org/TR/REC-xml-names/)
+	 */
+	char *key = g_strdup_printf("%s %s", node, xmlns);
+	g_hash_table_replace(iq_handlers, key, handlerfunc);
 }
 
 void jabber_iq_init(void)
 {
 	iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 
-	jabber_iq_register_handler("jabber:iq:roster", jabber_roster_parse);
-	jabber_iq_register_handler("jabber:iq:oob", jabber_oob_parse);
-	jabber_iq_register_handler("http://jabber.org/protocol/bytestreams", jabber_bytestreams_parse);
-	jabber_iq_register_handler("jabber:iq:last", jabber_iq_last_parse);
-	jabber_iq_register_handler("jabber:iq:time", jabber_iq_time_parse);
-	jabber_iq_register_handler("urn:xmpp:time", jabber_iq_time_parse);
-	jabber_iq_register_handler("jabber:iq:version", jabber_iq_version_parse);
-	jabber_iq_register_handler("http://jabber.org/protocol/disco#info", jabber_disco_info_parse);
-	jabber_iq_register_handler("http://jabber.org/protocol/disco#items", jabber_disco_items_parse);
-	jabber_iq_register_handler("jabber:iq:register", jabber_register_parse);
-	jabber_iq_register_handler("urn:xmpp:ping", urn_xmpp_ping_parse);
-	jabber_iq_register_handler(JINGLE, jingle_parse);
+	jabber_iq_register_handler("jingle", JINGLE, jingle_parse);
+	jabber_iq_register_handler("mailbox", "google:mail:notify",
+			jabber_gmail_poke);
+	jabber_iq_register_handler("new-mail", "google:mail:notify",
+			jabber_gmail_poke);
+	jabber_iq_register_handler("ping", "urn:xmpp:ping", jabber_ping_parse);
+	jabber_iq_register_handler("query", GOOGLE_JINGLE_INFO_NAMESPACE,
+			jabber_google_handle_jingle_info);
+	jabber_iq_register_handler("query", "http://jabber.org/protocol/bytestreams",
+			jabber_bytestreams_parse);
+	jabber_iq_register_handler("query", "http://jabber.org/protocol/disco#info",
+			jabber_disco_info_parse);
+	jabber_iq_register_handler("query", "http://jabber.org/protocol/disco#items",
+			jabber_disco_items_parse);
+	jabber_iq_register_handler("query", "jabber:iq:last", jabber_iq_last_parse);
+	jabber_iq_register_handler("query", "jabber:iq:oob", jabber_oob_parse);
+	jabber_iq_register_handler("query", "jabber:iq:register",
+			jabber_register_parse);
+	jabber_iq_register_handler("query", "jabber:iq:roster",
+			jabber_roster_parse);
+	jabber_iq_register_handler("query", "jabber:iq:time", jabber_iq_time_parse);
+	jabber_iq_register_handler("query", "jabber:iq:version",
+			jabber_iq_version_parse);
+#ifdef USE_VV
+	jabber_iq_register_handler("session", "http://www.google.com/session",
+		jabber_google_session_parse);
+#endif
+	jabber_iq_register_handler("time", "urn:xmpp:time", jabber_iq_time_parse);
 
-	/* handle Google jingleinfo */
-	jabber_iq_register_handler(GOOGLE_JINGLE_INFO_NAMESPACE, 
-		jabber_google_handle_jingle_info);
 }
 
 void jabber_iq_uninit(void)
@@ -465,4 +448,3 @@
 	g_hash_table_destroy(iq_handlers);
 	iq_handlers = NULL;
 }
-
--- a/libpurple/protocols/jabber/iq.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/iq.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,12 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_IQ_H_
-#define _PURPLE_JABBER_IQ_H_
-
-#include "jabber.h"
-
-typedef struct _JabberIq JabberIq;
+#ifndef PURPLE_JABBER_IQ_H_
+#define PURPLE_JABBER_IQ_H_
 
 typedef enum {
 	JABBER_IQ_SET,
@@ -34,9 +30,51 @@
 	JABBER_IQ_NONE
 } JabberIqType;
 
-typedef void (JabberIqHandler)(JabberStream *js, xmlnode *packet);
+#include "jabber.h"
+
+typedef struct _JabberIq JabberIq;
 
-typedef void (JabberIqCallback)(JabberStream *js, xmlnode *packet, gpointer data);
+/**
+ * A JabberIqHandler is called to process an incoming IQ stanza.
+ * Handlers typically process unsolicited incoming GETs or SETs for their
+ * registered namespace, but may be called to handle the results of a
+ * GET or SET that we generated if no JabberIqCallback was generated
+ * The handler may be called for the results of a GET or SET (RESULT or ERROR)
+ * that we generated
+ * if the generating function did not register a JabberIqCallback.
+ *
+ * @param js    The JabberStream object.
+ * @param from  The remote entity (the from attribute on the <iq/> stanza)
+ * @param type  The IQ type.
+ * @param id    The IQ id (the id attribute on the <iq/> stanza)
+ * @param child The child element of the <iq/> stanza that matches the name
+ *              and namespace registered with jabber_iq_register_handler.
+ *
+ * @see jabber_iq_register_handler()
+ * @see JabberIqCallback
+ */
+typedef void (JabberIqHandler)(JabberStream *js, const char *from,
+                               JabberIqType type, const char *id,
+                               xmlnode *child);
+
+/**
+ * A JabberIqCallback is called to process the results of a GET or SET that
+ * we send to a remote entity. The callback is matched based on the id
+ * of the incoming stanza (which matches the one on the initial stanza).
+ *
+ * @param js     The JabberStream object.
+ * @param from   The remote entity (the from attribute on the <iq/> stanza)
+ * @param type   The IQ type. The only possible values are JABBER_IQ_RESULT
+ *               and JABBER_IQ_ERROR.
+ * @param id     The IQ id (the id attribute on the <iq/> stanza)
+ * @param packet The <iq/> stanza
+ * @param data   The callback data passed to jabber_iq_set_callback()
+ *
+ * @see jabber_iq_set_callback()
+ */
+typedef void (JabberIqCallback)(JabberStream *js, const char *from,
+                                JabberIqType type, const char *id,
+                                xmlnode *packet, gpointer data);
 
 struct _JabberIq {
 	JabberIqType type;
@@ -65,6 +103,7 @@
 void jabber_iq_init(void);
 void jabber_iq_uninit(void);
 
-void jabber_iq_register_handler(const char *xmlns, JabberIqHandler *func);
+void jabber_iq_register_handler(const char *node, const char *xmlns,
+                                JabberIqHandler *func);
 
-#endif /* _PURPLE_JABBER_IQ_H_ */
+#endif /* PURPLE_JABBER_IQ_H_ */
--- a/libpurple/protocols/jabber/jabber.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Sun Apr 05 21:13:10 2009 +0000
@@ -89,10 +89,11 @@
 }
 
 static void
-jabber_session_initialized_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_session_initialized_cb(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id,
+                              xmlnode *packet, gpointer data)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
-	if(type && !strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		jabber_disco_items_server(js);
 		if(js->unregistration)
 			jabber_unregister_account_cb(js);
@@ -116,13 +117,13 @@
 	jabber_iq_send(iq);
 }
 
-static void jabber_bind_result_cb(JabberStream *js, xmlnode *packet,
-		gpointer data)
+static void jabber_bind_result_cb(JabberStream *js, const char *from,
+                                  JabberIqType type, const char *id,
+                                  xmlnode *packet, gpointer data)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
 	xmlnode *bind;
 
-	if(type && !strcmp(type, "result") &&
+	if (type == JABBER_IQ_RESULT &&
 			(bind = xmlnode_get_child_with_namespace(packet, "bind", "urn:ietf:params:xml:ns:xmpp-bind"))) {
 		xmlnode *jid;
 		char *full_jid;
@@ -456,13 +457,7 @@
 	g_free(txt);
 }
 
-static void jabber_pong_cb(JabberStream *js, xmlnode *packet, gpointer unused)
-{
-	purple_timeout_remove(js->keepalive_timeout);
-	js->keepalive_timeout = -1;
-}
-
-static gboolean jabber_pong_timeout(PurpleConnection *gc)
+static gboolean jabber_keepalive_timeout(PurpleConnection *gc)
 {
 	JabberStream *js = gc->proto_data;
 	purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
@@ -476,14 +471,9 @@
 	JabberStream *js = gc->proto_data;
 
 	if (js->keepalive_timeout == -1) {
-		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_GET);
-
-		xmlnode *ping = xmlnode_new_child(iq->node, "ping");
-		xmlnode_set_namespace(ping, "urn:xmpp:ping");
-
-		js->keepalive_timeout = purple_timeout_add_seconds(120, (GSourceFunc)(jabber_pong_timeout), gc);
-		jabber_iq_set_callback(iq, jabber_pong_cb, NULL);
-		jabber_iq_send(iq);
+		jabber_ping_jid(js, NULL);
+		js->keepalive_timeout = purple_timeout_add_seconds(120,
+				(GSourceFunc)(jabber_keepalive_timeout), gc);
 	}
 }
 
@@ -863,14 +853,15 @@
 }
 
 static void
-jabber_registration_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_registration_result_cb(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id,
+                              xmlnode *packet, gpointer data)
 {
 	PurpleAccount *account = purple_connection_get_account(js->gc);
-	const char *type = xmlnode_get_attrib(packet, "type");
 	char *buf;
 	char *to = data;
 
-	if(!strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		if(js->registration) {
 		buf = g_strdup_printf(_("Registration of %s@%s successful"),
 				js->user->node, js->user->domain);
@@ -898,13 +889,14 @@
 	}
 	g_free(to);
 	if(js->registration)
-	jabber_connection_schedule_close(js);
+		jabber_connection_schedule_close(js);
 }
 
 static void
-jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_unregistration_result_cb(JabberStream *js, const char *from,
+                                JabberIqType type, const char *id,
+                                xmlnode *packet, gpointer data)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
 	char *buf;
 	char *to = data;
 
@@ -912,7 +904,7 @@
 	 * the server, so there should always be a 'to' address. */
 	g_return_if_fail(to != NULL);
 
-	if(!strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		buf = g_strdup_printf(_("Registration from %s successfully removed"),
 							  to);
 		purple_notify_info(NULL, _("Unregistration Successful"),
@@ -1061,31 +1053,30 @@
 	jabber_iq_send(iq);
 }
 
-void jabber_register_parse(JabberStream *js, xmlnode *packet)
+void jabber_register_parse(JabberStream *js, const char *from, JabberIqType type,
+                           const char *id, xmlnode *query)
 {
 	PurpleAccount *account = purple_connection_get_account(js->gc);
-	const char *type;
-	const char *from;
 	PurpleRequestFields *fields;
 	PurpleRequestFieldGroup *group;
 	PurpleRequestField *field;
-	xmlnode *query, *x, *y;
+	xmlnode *x, *y;
 	char *instructions;
 	JabberRegisterCBData *cbdata;
 	gboolean registered = FALSE;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result"))
+	if (type != JABBER_IQ_RESULT)
 		return;
 
-	from = xmlnode_get_attrib(packet, "from");
+	if (!from)
+		from = js->serverFQDN;
+	g_return_if_fail(from != NULL);
 
 	if(js->registration) {
 		/* get rid of the login thingy */
 		purple_connection_set_state(js->gc, PURPLE_CONNECTED);
 	}
 
-	query = xmlnode_get_child(packet, "query");
-
 	if(xmlnode_get_child(query, "registered")) {
 		registered = TRUE;
 
@@ -1323,10 +1314,14 @@
 	}
 }
 
-static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) {
+static void
+jabber_unregister_account_iq_cb(JabberStream *js, const char *from,
+                                JabberIqType type, const char *id,
+                                xmlnode *packet, gpointer data)
+{
 	PurpleAccount *account = purple_connection_get_account(js->gc);
-	const char *type = xmlnode_get_attrib(packet,"type");
-	if(!strcmp(type,"error")) {
+
+	if (type == JABBER_IQ_ERROR) {
 		char *msg = jabber_parse_error(js, packet, NULL);
 
 		purple_notify_error(js->gc, _("Error unregistering account"),
@@ -1334,7 +1329,7 @@
 		g_free(msg);
 		if(js->unregistration_cb)
 			js->unregistration_cb(account, FALSE, js->unregistration_user_data);
-	} else if(!strcmp(type,"result")) {
+	} else {
 		purple_notify_info(js->gc, _("Account successfully unregistered"),
 						   _("Account successfully unregistered"), NULL);
 		if(js->unregistration_cb)
@@ -1582,7 +1577,9 @@
 	js->idle = idle ? time(NULL) - idle : idle;
 }
 
-static void jabber_blocklist_parse(JabberStream *js, xmlnode *packet, gpointer data)
+static void jabber_blocklist_parse(JabberStream *js, const char *from,
+                                   JabberIqType type, const char *id,
+                                   xmlnode *packet, gpointer data)
 {
 	xmlnode *blocklist, *item;
 	PurpleAccount *account;
@@ -2055,14 +2052,11 @@
 }
 
 static void
-jabber_password_change_result_cb(JabberStream *js, xmlnode *packet,
-		gpointer data)
+jabber_password_change_result_cb(JabberStream *js, const char *from,
+                                 JabberIqType type, const char *id,
+                                 xmlnode *packet, gpointer data)
 {
-	const char *type;
-
-	type = xmlnode_get_attrib(packet, "type");
-
-	if(type && !strcmp(type, "result")) {
+	if (type == JABBER_IQ_RESULT) {
 		purple_notify_info(js->gc, _("Password Changed"), _("Password Changed"),
 				_("Your password has been changed."));
 
@@ -2594,10 +2588,16 @@
 static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv,
 		const char *cmd, char **args, char **error, void *data)
 {
+	PurpleAccount *account;
+	PurpleConnection *pc;
+
 	if(!args || !args[0])
 		return PURPLE_CMD_RET_FAILED;
 
-	if(!jabber_ping_jid(conv, args[0])) {
+	account = purple_conversation_get_account(conv);
+	pc = purple_account_get_connection(account);
+
+	if(!jabber_ping_jid(purple_connection_get_protocol_data(pc), args[0])) {
 		*error = g_strdup_printf(_("Unable to ping user %s"), args[0]);
 		return PURPLE_CMD_RET_FAILED;
 	}
--- a/libpurple/protocols/jabber/jabber.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_H_
-#define _PURPLE_JABBER_H_
+#ifndef PURPLE_JABBER_H_
+#define PURPLE_JABBER_H_
 
 typedef enum {
 	JABBER_CAP_NONE           = 0,
@@ -60,6 +60,7 @@
 #include "sslconn.h"
 #include "dnsquery.h"
 
+#include "iq.h"
 #include "jutil.h"
 #include "xmlnode.h"
 #include "buddy.h"
@@ -299,7 +300,8 @@
 
 void jabber_stream_set_state(JabberStream *js, JabberStreamState state);
 
-void jabber_register_parse(JabberStream *js, xmlnode *packet);
+void jabber_register_parse(JabberStream *js, const char *from,
+                           JabberIqType type, const char *id, xmlnode *query);
 void jabber_register_start(JabberStream *js);
 
 char *jabber_get_next_id(JabberStream *js);
@@ -366,4 +368,4 @@
 void jabber_init_plugin(PurplePlugin *plugin);
 void jabber_uninit_plugin(void);
 
-#endif /* _PURPLE_JABBER_H_ */
+#endif /* PURPLE_JABBER_H_ */
--- a/libpurple/protocols/jabber/jingle/content.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/content.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef JINGLE_CONTENT_H
-#define JINGLE_CONTENT_H
+#ifndef PURPLE_JABBER_JINGLE_CONTENT_H
+#define PURPLE_JABBER_JINGLE_CONTENT_H
 
 
 #include "jabber.h"
@@ -113,5 +113,5 @@
 
 G_END_DECLS
 
-#endif /* JINGLE_CONTENT_H */
+#endif /* PURPLE_JABBER_JINGLE_CONTENT_H */
 
--- a/libpurple/protocols/jabber/jingle/iceudp.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/iceudp.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef JINGLE_ICEUDP_H
-#define JINGLE_ICEUDP_H
+#ifndef PURPLE_JABBER_JINGLE_ICEUDP_H
+#define PURPLE_JABBER_JINGLE_ICEUDP_H
 
 #include <glib.h>
 #include <glib-object.h>
@@ -110,5 +110,5 @@
 
 G_END_DECLS
 
-#endif /* JINGLE_ICEUDP_H */
+#endif /* PURPLE_JABBER_JINGLE_ICEUDP_H */
 
--- a/libpurple/protocols/jabber/jingle/jingle.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.c	Sun Apr 05 21:13:10 2009 +0000
@@ -359,28 +359,21 @@
 }
 
 void
-jingle_parse(JabberStream *js, xmlnode *packet)
+jingle_parse(JabberStream *js, const char *from, JabberIqType type,
+             const char *id, xmlnode *jingle)
 {
-	const gchar *type = xmlnode_get_attrib(packet, "type");
-	xmlnode *jingle;
 	const gchar *action;
 	const gchar *sid;
 	JingleActionType action_type;
 	JingleSession *session;
 
-	if (!type || strcmp(type, "set")) {
-		/* send iq error here */
-		return;
-	}
-
-	/* is this a Jingle package? */
-	if (!(jingle = xmlnode_get_child(packet, "jingle"))) {
-		/* send iq error here */
+	if (type != JABBER_IQ_SET) {
+		/* TODO: send iq error here */
 		return;
 	}
 
 	if (!(action = xmlnode_get_attrib(jingle, "action"))) {
-		/* send iq error here */
+		/* TODO: send iq error here */
 		return;
 	}
 
@@ -409,9 +402,10 @@
 			/* send iq error */
 			return;
 		} else {
-			session = jingle_session_create(js, sid,
-					xmlnode_get_attrib(packet, "to"),
-					xmlnode_get_attrib(packet, "from"), FALSE);
+			char *own_jid = g_strdup_printf("%s@%s/%s", js->user->node,
+					js->user->domain, js->user->resource);
+			session = jingle_session_create(js, sid, own_jid, from, FALSE);
+			g_free(own_jid);
 		}
 	}
 
--- a/libpurple/protocols/jabber/jingle/jingle.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/jingle.h	Sun Apr 05 21:13:10 2009 +0000
@@ -16,8 +16,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
  */
  
-#ifndef JINGLE_H
-#define JINGLE_H
+#ifndef PURPLE_JABBER_JINGLE_H
+#define PURPLE_JABBER_JINGLE_H
 
 #include "jabber.h"
 
@@ -69,7 +69,8 @@
 
 GType jingle_get_type(const gchar *type);
 
-void jingle_parse(JabberStream *js, xmlnode *packet);
+void jingle_parse(JabberStream *js, const char *from, JabberIqType type,
+                  const char *id, xmlnode *child);
 
 void jingle_terminate_sessions(JabberStream *js);
 
@@ -83,4 +84,4 @@
 
 G_END_DECLS
 
-#endif /* JINGLE_H */
+#endif /* PURPLE_JABBER_JINGLE_H */
--- a/libpurple/protocols/jabber/jingle/rawudp.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rawudp.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef JINGLE_RAWUDP_H
-#define JINGLE_RAWUDP_H
+#ifndef PURPLE_JABBER_JINGLE_RAWUDP_H
+#define PURPLE_JABBER_JINGLE_RAWUDP_H
 
 #include <glib.h>
 #include <glib-object.h>
@@ -97,5 +97,5 @@
 
 G_END_DECLS
 
-#endif /* JINGLE_RAWUDP_H */
+#endif /* PURPLE_JABBER_JINGLE_RAWUDP_H */
 
--- a/libpurple/protocols/jabber/jingle/rtp.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.c	Sun Apr 05 21:13:10 2009 +0000
@@ -438,12 +438,13 @@
 }
 
 static void
-jingle_rtp_initiate_ack_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jingle_rtp_initiate_ack_cb(JabberStream *js, const char *from,
+                           JabberIqType type, const char *id,
+                           xmlnode *packet, gpointer data)
 {
 	JingleSession *session = data;
 
-	if (!strcmp(xmlnode_get_attrib(packet, "type"), "error") ||
-			xmlnode_get_child(packet, "error")) {
+	if (type == JABBER_IQ_ERROR || xmlnode_get_child(packet, "error")) {
 		purple_media_end(jingle_rtp_get_media(session), NULL, NULL);
 		g_object_unref(session);
 		return;
--- a/libpurple/protocols/jabber/jingle/rtp.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/rtp.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef JINGLE_RTP_H
-#define JINGLE_RTP_H
+#ifndef PURPLE_JABBER_JINGLE_RTP_H
+#define PURPLE_JABBER_JINGLE_RTP_H
 
 #include "config.h"
 
@@ -88,5 +88,5 @@
 
 #endif /* USE_VV */
 
-#endif /* JINGLE_RTP_H */
+#endif /* PURPLE_JABBER_JINGLE_RTP_H */
 
--- a/libpurple/protocols/jabber/jingle/session.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/session.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef JINGLE_SESSION_H
-#define JINGLE_SESSION_H
+#ifndef PURPLE_JABBER_JINGLE_SESSION_H
+#define PURPLE_JABBER_JINGLE_SESSION_H
 
 #include "iq.h"
 #include "jabber.h"
@@ -111,5 +111,5 @@
 
 G_END_DECLS
 
-#endif /* JINGLE_SESSION_H */
+#endif /* PURPLE_JABBER_JINGLE_SESSION_H */
 
--- a/libpurple/protocols/jabber/jingle/transport.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jingle/transport.h	Sun Apr 05 21:13:10 2009 +0000
@@ -18,8 +18,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
 
-#ifndef JINGLE_TRANSPORT_H
-#define JINGLE_TRANSPORT_H
+#ifndef PURPLE_JABBER_JINGLE_TRANSPORT_H
+#define PURPLE_JABBER_JINGLE_TRANSPORT_H
 
 #include <glib.h>
 #include <glib-object.h>
@@ -84,5 +84,5 @@
 
 G_END_DECLS
 
-#endif /* JINGLE_TRANSPORT_H */
+#endif /* PURPLE_JABBER_JINGLE_TRANSPORT_H */
 
--- a/libpurple/protocols/jabber/jutil.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/jutil.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_JUTIL_H_
-#define _PURPLE_JABBER_JUTIL_H_
+#ifndef PURPLE_JABBER_JUTIL_H_
+#define PURPLE_JABBER_JUTIL_H_
 
 typedef struct _JabberID {
 	char *node;
@@ -43,4 +43,4 @@
 PurpleConversation *jabber_find_unnormalized_conv(const char *name, PurpleAccount *account);
 
 char *jabber_calculate_data_sha1sum(gconstpointer data, size_t len);
-#endif /* _PURPLE_JABBER_JUTIL_H_ */
+#endif /* PURPLE_JABBER_JUTIL_H_ */
--- a/libpurple/protocols/jabber/message.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/message.c	Sun Apr 05 21:13:10 2009 +0000
@@ -477,7 +477,9 @@
 } JabberDataRef;
 
 static void
-jabber_message_get_data_cb(JabberStream *js, xmlnode *packet, gpointer data)
+jabber_message_get_data_cb(JabberStream *js, const char *from,
+                           JabberIqType type, const char *id,
+                           xmlnode *packet, gpointer data)
 {
 	JabberDataRef *ref = (JabberDataRef *) data;
 	PurpleConversation *conv = ref->conv;
--- a/libpurple/protocols/jabber/message.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/message.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_MESSAGE_H_
-#define _PURPLE_JABBER_MESSAGE_H_
+#ifndef PURPLE_JABBER_MESSAGE_H_
+#define PURPLE_JABBER_MESSAGE_H_
 
 #include "buddy.h"
 #include "jabber.h"
@@ -84,4 +84,4 @@
 
 gboolean jabber_custom_smileys_isenabled(JabberStream *js, const const gchar *namespace);
 
-#endif /* _PURPLE_JABBER_MESSAGE_H_ */
+#endif /* PURPLE_JABBER_MESSAGE_H_ */
--- a/libpurple/protocols/jabber/oob.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/oob.c	Sun Apr 05 21:13:10 2009 +0000
@@ -187,18 +187,18 @@
 	jabber_oob_xfer_recv_error(xfer, "404");
 }
 
-void jabber_oob_parse(JabberStream *js, xmlnode *packet) {
+void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type,
+                      const char *id, xmlnode *querynode) {
 	JabberOOBXfer *jox;
 	PurpleXfer *xfer;
 	char *filename;
 	char *url;
-	const char *type;
-	xmlnode *querynode, *urlnode;
+	xmlnode *urlnode;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "set"))
+	if(type != JABBER_IQ_SET)
 		return;
 
-	if(!(querynode = xmlnode_get_child(packet, "query")))
+	if(!from)
 		return;
 
 	if(!(urlnode = xmlnode_get_child(querynode, "url")))
@@ -211,10 +211,9 @@
 	g_free(url);
 	jox->js = js;
 	jox->headers = g_string_new("");
-	jox->iq_id = g_strdup(xmlnode_get_attrib(packet, "id"));
+	jox->iq_id = g_strdup(id);
 
-	xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE,
-			xmlnode_get_attrib(packet, "from"));
+	xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, from);
 	if (xfer)
 	{
 		xfer->data = jox;
--- a/libpurple/protocols/jabber/oob.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/oob.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,9 +19,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_OOB_H_
-#define _PURPLE_JABBER_OOB_H_
+#ifndef PURPLE_JABBER_OOB_H_
+#define PURPLE_JABBER_OOB_H_
+
+#include "jabber.h"
 
-void jabber_oob_parse(JabberStream *js, xmlnode *packet);
+void jabber_oob_parse(JabberStream *js, const char *from, JabberIqType type,
+                      const char *id, xmlnode *querynode);
 
-#endif /* _PURPLE_JABBER_OOB_H_ */
+#endif /* PURPLE_JABBER_OOB_H_ */
--- a/libpurple/protocols/jabber/parser.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/parser.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_PARSER_H_
-#define _PURPLE_JABBER_PARSER_H_
+#ifndef PURPLE_JABBER_PARSER_H_
+#define PURPLE_JABBER_PARSER_H_
 
 #include "jabber.h"
 
@@ -28,4 +28,4 @@
 void jabber_parser_free(JabberStream *js);
 void jabber_parser_process(JabberStream *js, const char *buf, int len);
 
-#endif /* _PURPLE_JABBER_PARSER_H_ */
+#endif /* PURPLE_JABBER_PARSER_H_ */
--- a/libpurple/protocols/jabber/pep.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/pep.c	Sun Apr 05 21:13:10 2009 +0000
@@ -60,8 +60,11 @@
 	g_hash_table_replace(pep_handlers, g_strdup(xmlns), handlerfunc);
 }
 
-static void do_pep_iq_request_item_callback(JabberStream *js, xmlnode *packet, gpointer data) {
-	const char *from = xmlnode_get_attrib(packet,"from");
+static void
+do_pep_iq_request_item_callback(JabberStream *js, const char *from,
+                                JabberIqType type, const char *id,
+                                xmlnode *packet, gpointer data)
+{
 	xmlnode *pubsub = xmlnode_get_child_with_namespace(packet,"pubsub","http://jabber.org/protocol/pubsub");
 	xmlnode *items = NULL;
 	JabberPEPHandler *cb = data;
--- a/libpurple/protocols/jabber/pep.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/pep.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef _PURPLE_JABBER_PEP_H_
-#define _PURPLE_JABBER_PEP_H_
+#ifndef PURPLE_JABBER_PEP_H_
+#define PURPLE_JABBER_PEP_H_
 
 #include "jabber.h"
 #include "message.h"
@@ -81,4 +81,4 @@
  */
 void jabber_pep_publish(JabberStream *js, xmlnode *publish);
 
-#endif /* _PURPLE_JABBER_PEP_H_ */
+#endif /* PURPLE_JABBER_PEP_H_ */
--- a/libpurple/protocols/jabber/ping.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/ping.c	Sun Apr 05 21:13:10 2009 +0000
@@ -23,50 +23,63 @@
 #include "internal.h"
 
 #include "debug.h"
-#include "xmlnode.h"
 
 #include "jabber.h"
 #include "ping.h"
 #include "iq.h"
 
-void
-jabber_ping_parse(JabberStream *js, xmlnode *packet)
+static void jabber_keepalive_pong_cb(JabberStream *js)
 {
-	JabberIq *iq;
-
-	purple_debug_info("jabber", "jabber_ping_parse\n");
-
-	iq = jabber_iq_new(js, JABBER_IQ_RESULT);
-
-	xmlnode_set_attrib(iq->node, "to", xmlnode_get_attrib(packet, "from") );
-
-	jabber_iq_set_id(iq, xmlnode_get_attrib(packet, "id"));
-
-	jabber_iq_send(iq);
+	purple_timeout_remove(js->keepalive_timeout);
+	js->keepalive_timeout = -1;
 }
 
-static void jabber_ping_result_cb(JabberStream *js, xmlnode *packet,
-		gpointer data)
+void
+jabber_ping_parse(JabberStream *js, const char *from,
+                  JabberIqType type, const char *id, xmlnode *ping)
 {
-	const char *type = xmlnode_get_attrib(packet, "type");
+	if (type == JABBER_IQ_GET) {
+		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_RESULT);
+
+		if (from)
+			xmlnode_set_attrib(iq->node, "to", from);
+		xmlnode_set_attrib(iq->node, "id", id);
+
+		jabber_iq_send(iq);
+	} else if (type == JABBER_IQ_SET) {
+		/* XXX: error */
+	}
+}
 
-	purple_debug_info("jabber", "jabber_ping_result_cb\n");
-	if(type && !strcmp(type, "result")) {
+static void jabber_ping_result_cb(JabberStream *js, const char *from,
+                                  JabberIqType type, const char *id,
+                                  xmlnode *packet, gpointer data)
+{
+	char *own_bare_jid = g_strdup_printf("%s@%s", js->user->node,
+	                                     js->user->domain);
+
+	if (!from || !strcmp(from, own_bare_jid)) {
+		/* If the pong is from our bare JID, treat it as a return from the
+		 * keepalive functions */
+		jabber_keepalive_pong_cb(js);
+	}
+	g_free(own_bare_jid);
+
+	if (type == JABBER_IQ_RESULT) {
 		purple_debug_info("jabber", "PONG!\n");
 	} else {
 		purple_debug_info("jabber", "(not supported)\n");
 	}
 }
 
-gboolean jabber_ping_jid(PurpleConversation *conv, const char *jid)
+gboolean jabber_ping_jid(JabberStream *js, const char *jid)
 {
 	JabberIq *iq;
 	xmlnode *ping;
 
-	purple_debug_info("jabber", "jabber_ping_jid\n");
-
-	iq = jabber_iq_new(conv->account->gc->proto_data, JABBER_IQ_GET);
-	xmlnode_set_attrib(iq->node, "to", jid);
+	iq = jabber_iq_new(js, JABBER_IQ_GET);
+	if (jid)
+		xmlnode_set_attrib(iq->node, "to", jid);
 
 	ping = xmlnode_new_child(iq->node, "ping");
 	xmlnode_set_namespace(ping, "urn:xmpp:ping");
@@ -74,7 +87,5 @@
 	jabber_iq_set_callback(iq, jabber_ping_result_cb, NULL);
 	jabber_iq_send(iq);
 
-
-
 	return TRUE;
 }
--- a/libpurple/protocols/jabber/ping.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/ping.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,17 +19,15 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#ifndef _PURPLE_JABBER_PING_H_
-#define _PURPLE_JABBER_PING_H_
+#ifndef PURPLE_JABBER_PING_H_
+#define PURPLE_JABBER_PING_H_
 
 #include "jabber.h"
-#include "conversation.h"
-
-void jabber_ping_parse(JabberStream *js,
-						xmlnode *packet);
+#include "iq.h"
+#include "xmlnode.h"
 
-
-gboolean jabber_ping_jid(PurpleConversation *conv, const char *jid);
+void jabber_ping_parse(JabberStream *js, const char *from,
+                       JabberIqType, const char *id, xmlnode *child);
+gboolean jabber_ping_jid(JabberStream *js, const char *jid);
 
-
-#endif /* _PURPLE_JABBER_PING_H_ */
+#endif /* PURPLE_JABBER_PING_H_ */
--- a/libpurple/protocols/jabber/presence.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/presence.c	Sun Apr 05 21:13:10 2009 +0000
@@ -315,14 +315,16 @@
 	g_free(jap);
 }
 
-static void jabber_vcard_parse_avatar(JabberStream *js, xmlnode *packet, gpointer blah)
+static void
+jabber_vcard_parse_avatar(JabberStream *js, const char *from,
+                          JabberIqType type, const char *id,
+                          xmlnode *packet, gpointer blah)
 {
 	JabberBuddy *jb = NULL;
 	xmlnode *vcard, *photo, *binval;
 	char *text;
 	guchar *data;
 	gsize size;
-	const char *from = xmlnode_get_attrib(packet, "from");
 
 	if(!from)
 		return;
--- a/libpurple/protocols/jabber/presence.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/presence.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_PRESENCE_H_
-#define _PURPLE_JABBER_PRESENCE_H_
+#ifndef PURPLE_JABBER_PRESENCE_H_
+#define PURPLE_JABBER_PRESENCE_H_
 
 #include "buddy.h"
 #include "jabber.h"
@@ -45,4 +45,4 @@
 void jabber_presence_fake_to_self(JabberStream *js, const PurpleStatus *status);
 void purple_status_to_jabber(const PurpleStatus *status, JabberBuddyState *state, char **msg, int *priority);
 
-#endif /* _PURPLE_JABBER_PRESENCE_H_ */
+#endif /* PURPLE_JABBER_PRESENCE_H_ */
--- a/libpurple/protocols/jabber/roster.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/roster.c	Sun Apr 05 21:13:10 2009 +0000
@@ -145,10 +145,10 @@
 	g_slist_free(buddies);
 }
 
-void jabber_roster_parse(JabberStream *js, xmlnode *packet)
+void jabber_roster_parse(JabberStream *js, const char *from,
+                         JabberIqType type, const char *id, xmlnode *query)
 {
-	xmlnode *query, *item, *group;
-	const char *from = xmlnode_get_attrib(packet, "from");
+	xmlnode *item, *group;
 
 	if(from) {
 		char *from_norm;
@@ -169,10 +169,6 @@
 			return;
 	}
 
-	query = xmlnode_get_child(packet, "query");
-	if(!query)
-		return;
-
 	js->currently_parsing_roster_push = TRUE;
 
 	for(item = xmlnode_get_child(query, "item"); item; item = xmlnode_get_next_twin(item))
--- a/libpurple/protocols/jabber/roster.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/roster.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,14 +19,15 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_ROSTER_H_
-#define _PURPLE_JABBER_ROSTER_H_
+#ifndef PURPLE_JABBER_ROSTER_H_
+#define PURPLE_JABBER_ROSTER_H_
 
 #include "jabber.h"
 
 void jabber_roster_request(JabberStream *js);
 
-void jabber_roster_parse(JabberStream *js, xmlnode *packet);
+void jabber_roster_parse(JabberStream *js, const char *from,
+                         JabberIqType type, const char *id, xmlnode *query);
 
 void jabber_roster_add_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
 		PurpleGroup *group);
@@ -39,4 +40,4 @@
 void jabber_roster_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy,
 		PurpleGroup *group);
 
-#endif /* _PURPLE_JABBER_ROSTER_H_ */
+#endif /* PURPLE_JABBER_ROSTER_H_ */
--- a/libpurple/protocols/jabber/si.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/si.c	Sun Apr 05 21:13:10 2009 +0000
@@ -311,20 +311,18 @@
 	}
 }
 
-void jabber_bytestreams_parse(JabberStream *js, xmlnode *packet)
+void jabber_bytestreams_parse(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id, xmlnode *query)
 {
 	PurpleXfer *xfer;
 	JabberSIXfer *jsx;
-	xmlnode *query, *streamhost;
-	const char *sid, *from, *type;
+	xmlnode *streamhost;
+	const char *sid;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "set"))
+	if(type != JABBER_IQ_SET)
 		return;
 
-	if(!(from = xmlnode_get_attrib(packet, "from")))
-		return;
-
-	if(!(query = xmlnode_get_child(packet, "query")))
+	if(!from)
 		return;
 
 	if(!(sid = xmlnode_get_attrib(query, "sid")))
@@ -340,7 +338,7 @@
 
 	if(jsx->iq_id)
 		g_free(jsx->iq_id);
-	jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id"));
+	jsx->iq_id = g_strdup(id);
 
 	for(streamhost = xmlnode_get_child(query, "streamhost"); streamhost;
 			streamhost = xmlnode_get_next_twin(streamhost)) {
@@ -685,13 +683,14 @@
 }
 
 static void
-jabber_si_connect_proxy_cb(JabberStream *js, xmlnode *packet,
-		gpointer data)
+jabber_si_connect_proxy_cb(JabberStream *js, const char *from,
+                           JabberIqType type, const char *id,
+                           xmlnode *packet, gpointer data)
 {
 	PurpleXfer *xfer = data;
 	JabberSIXfer *jsx;
 	xmlnode *query, *streamhost_used;
-	const char *from, *type, *jid;
+	const char *jid;
 	GList *matched;
 
 	/* TODO: This need to send errors if we don't see what we're looking for */
@@ -708,37 +707,34 @@
 
 	jsx = xfer->data;
 
-	if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) {
-	  purple_debug_info("jabber",
-			    "jabber_si_xfer_connect_proxy_cb: type = %s\n",
-			    type);
-		if (type && !strcmp(type, "error")) {
-			/* if IBB is available, open IBB session */
-			purple_debug_info("jabber",
-				"jabber_si_xfer_connect_proxy_cb: got error, method: %d\n",
-				jsx->stream_method);
-			if (jsx->stream_method & STREAM_METHOD_IBB) {
-				purple_debug_info("jabber", "IBB is possible, try it\n");
-				/* if we are the sender and haven't already opened an IBB
-				  session, do so now (we might already have failed to open
-				  the bytestream proxy ourselves when receiving this <iq/> */
-				if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND
-					&& !jsx->ibb_session) {
-					jabber_si_xfer_ibb_send_init(js, xfer);
-				} else {
-					jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
-						jabber_si_bytestreams_ibb_timeout_cb, xfer);
-				}
-				/* if we are receiver, just wait for IBB open stanza, callback
-				  is already set up */
+	if(type != JABBER_IQ_RESULT) {
+		purple_debug_info("jabber",
+			    "jabber_si_xfer_connect_proxy_cb: type = error\n");
+		/* if IBB is available, open IBB session */
+		purple_debug_info("jabber",
+			"jabber_si_xfer_connect_proxy_cb: got error, method: %d\n",
+			jsx->stream_method);
+		if (jsx->stream_method & STREAM_METHOD_IBB) {
+			purple_debug_info("jabber", "IBB is possible, try it\n");
+			/* if we are the sender and haven't already opened an IBB
+			  session, do so now (we might already have failed to open
+			  the bytestream proxy ourselves when receiving this <iq/> */
+			if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND
+				&& !jsx->ibb_session) {
+				jabber_si_xfer_ibb_send_init(js, xfer);
 			} else {
-				purple_xfer_cancel_remote(xfer);
+				jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
+					jabber_si_bytestreams_ibb_timeout_cb, xfer);
 			}
+			/* if we are receiver, just wait for IBB open stanza, callback
+			  is already set up */
+		} else {
+			purple_xfer_cancel_remote(xfer);
 		}
 		return;
 	}
 
-	if(!(from = xmlnode_get_attrib(packet, "from")))
+	if (!from)
 		return;
 
 	if(!(query = xmlnode_get_child(packet, "query")))
@@ -1019,16 +1015,15 @@
 }
 
 static gboolean
-jabber_si_xfer_ibb_open_cb(JabberStream *js, xmlnode *packet)
+jabber_si_xfer_ibb_open_cb(JabberStream *js, const char *who, const char *id,
+                           xmlnode *open)
 {
-	const gchar *who = xmlnode_get_attrib(packet, "from");
-	xmlnode *open = xmlnode_get_child(packet, "open");
 	const gchar *sid = xmlnode_get_attrib(open, "sid");
 	PurpleXfer *xfer = jabber_si_xfer_find(js, sid, who);
 	if (xfer) {
 		JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
 		JabberIBBSession *sess =
-			jabber_ibb_session_create_from_xmlnode(js, packet, xfer);
+			jabber_ibb_session_create_from_xmlnode(js, who, id, open, xfer);
 		const char *filename;
 
 		jabber_si_bytestreams_ibb_timeout_remove(jsx);
@@ -1183,8 +1178,9 @@
 	}
 }
 
-static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet,
-		gpointer data)
+static void jabber_si_xfer_send_method_cb(JabberStream *js, const char *from,
+                                          JabberIqType type, const char *id,
+                                          xmlnode *packet, gpointer data)
 {
 	PurpleXfer *xfer = data;
 	xmlnode *si, *feature, *x, *field, *value;
@@ -1585,17 +1581,15 @@
 		purple_xfer_request(xfer);
 }
 
-void jabber_si_parse(JabberStream *js, xmlnode *packet)
+void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type,
+                     const char *id, xmlnode *si)
 {
 	JabberSIXfer *jsx;
 	PurpleXfer *xfer;
-	xmlnode *si, *file, *feature, *x, *field, *option, *value;
-	const char *stream_id, *filename, *filesize_c, *profile, *from;
+	xmlnode *file, *feature, *x, *field, *option, *value;
+	const char *stream_id, *filename, *filesize_c, *profile;
 	size_t filesize = 0;
 
-	if(!(si = xmlnode_get_child(packet, "si")))
-		return;
-
 	if(!(profile = xmlnode_get_attrib(si, "profile")) ||
 			strcmp(profile, "http://jabber.org/protocol/si/profile/file-transfer"))
 		return;
@@ -1618,7 +1612,7 @@
 	if(!(x = xmlnode_get_child_with_namespace(feature, "x", "jabber:x:data")))
 		return;
 
-	if(!(from = xmlnode_get_attrib(packet, "from")))
+	if(!from)
 		return;
 
 	/* if they've already sent us this file transfer with the same damn id
@@ -1659,7 +1653,7 @@
 
 	jsx->js = js;
 	jsx->stream_id = g_strdup(stream_id);
-	jsx->iq_id = g_strdup(xmlnode_get_attrib(packet, "id"));
+	jsx->iq_id = g_strdup(id);
 
 	xfer = purple_xfer_new(js->gc->account, PURPLE_XFER_RECEIVE, from);
 	g_return_if_fail(xfer != NULL);
@@ -1683,6 +1677,8 @@
 void
 jabber_si_init(void)
 {
+	jabber_iq_register_handler("si", "http://jabber.org/protocol/si", jabber_si_parse);	
+	
 	jabber_ibb_register_open_handler(jabber_si_xfer_ibb_open_cb);
 }
 
--- a/libpurple/protocols/jabber/si.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/si.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,18 +19,20 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_SI_H_
-#define _PURPLE_JABBER_SI_H_
+#ifndef PURPLE_JABBER_SI_H_
+#define PURPLE_JABBER_SI_H_
 
 #include "ft.h"
 
 #include "jabber.h"
 
-void jabber_bytestreams_parse(JabberStream *js, xmlnode *packet);
-void jabber_si_parse(JabberStream *js, xmlnode *packet);
+void jabber_bytestreams_parse(JabberStream *js, const char *from,
+                              JabberIqType type, const char *id, xmlnode *query);
+void jabber_si_parse(JabberStream *js, const char *from, JabberIqType type,
+                     const char *id, xmlnode *si);
 PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who);
 void jabber_si_xfer_send(PurpleConnection *gc, const char *who, const char *file);
 void jabber_si_init(void);
 void jabber_si_uninit(void);
 
-#endif /* _PURPLE_JABBER_SI_H_ */
+#endif /* PURPLE_JABBER_SI_H_ */
--- a/libpurple/protocols/jabber/usermood.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/usermood.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef _PURPLE_JABBER_USERMOOD_H_
-#define _PURPLE_JABBER_USERMOOD_H_
+#ifndef PURPLE_JABBER_USERMOOD_H_
+#define PURPLE_JABBER_USERMOOD_H_
 
 #include "jabber.h"
 
@@ -34,4 +34,4 @@
 		     const char *mood, /* must be one of the valid strings defined in the XEP */
 		     const char *text /* might be NULL */);
 
-#endif /* _PURPLE_JABBER_USERMOOD_H_ */
+#endif /* PURPLE_JABBER_USERMOOD_H_ */
--- a/libpurple/protocols/jabber/usernick.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/usernick.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef _PURPLE_JABBER_USERNICK_H_
-#define _PURPLE_JABBER_USERNICK_H_
+#ifndef PURPLE_JABBER_USERNICK_H_
+#define PURPLE_JABBER_USERNICK_H_
 
 #include "jabber.h"
 
@@ -29,4 +29,4 @@
 void jabber_nick_init(void);
 void jabber_nick_init_action(GList **m);
 
-#endif /* _PURPLE_JABBER_USERNICK_H_ */
+#endif /* PURPLE_JABBER_USERNICK_H_ */
--- a/libpurple/protocols/jabber/usertune.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/usertune.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  *
  */
 
-#ifndef _PURPLE_JABBER_USERTUNE_H_
-#define _PURPLE_JABBER_USERTUNE_H_
+#ifndef PURPLE_JABBER_USERTUNE_H_
+#define PURPLE_JABBER_USERTUNE_H_
 
 #include "jabber.h"
 
@@ -40,4 +40,4 @@
 
 void jabber_tune_set(PurpleConnection *gc, const PurpleJabberTuneInfo *tuneinfo);
 
-#endif /* _PURPLE_JABBER_USERTUNE_H_ */
+#endif /* PURPLE_JABBER_USERTUNE_H_ */
--- a/libpurple/protocols/jabber/xdata.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/protocols/jabber/xdata.h	Sun Apr 05 21:13:10 2009 +0000
@@ -19,8 +19,8 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
-#ifndef _PURPLE_JABBER_XDATA_H_
-#define _PURPLE_JABBER_XDATA_H_
+#ifndef PURPLE_JABBER_XDATA_H_
+#define PURPLE_JABBER_XDATA_H_
 
 #include "jabber.h"
 #include "xmlnode.h"
@@ -35,4 +35,4 @@
 void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data);
 void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data);
 
-#endif /* _PURPLE_JABBER_XDATA_H_ */
+#endif /* PURPLE_JABBER_XDATA_H_ */
--- a/libpurple/util.h	Sun Apr 05 03:25:00 2009 +0000
+++ b/libpurple/util.h	Sun Apr 05 21:13:10 2009 +0000
@@ -31,23 +31,26 @@
 
 #include <stdio.h>
 
+typedef struct _PurpleUtilFetchUrlData PurpleUtilFetchUrlData;
+typedef struct _PurpleMenuAction PurpleMenuAction;
+typedef struct _PurpleKeyValuePair PurpleKeyValuePair;
+
 #include "account.h"
 #include "xmlnode.h"
 #include "notify.h"
 
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef struct _PurpleUtilFetchUrlData PurpleUtilFetchUrlData;
-
-typedef struct _PurpleMenuAction
+struct _PurpleMenuAction
 {
 	char *label;
 	PurpleCallback callback;
 	gpointer data;
 	GList *children;
-} PurpleMenuAction;
+};
 
 typedef char *(*PurpleInfoFieldFormatCallback)(const char *field, size_t len);
 
@@ -57,12 +60,12 @@
  * This is used by, among other things, purple_gtk_combo* functions to pass in a
  * list of key-value pairs so it can display a user-friendly value.
  */
-typedef struct _PurpleKeyValuePair
+struct _PurpleKeyValuePair
 {
 	gchar *key;
 	void *value;
 
-} PurpleKeyValuePair;
+};
 
 /**
  * Creates a new PurpleMenuAction.
--- a/pidgin/gtkimhtml.c	Sun Apr 05 03:25:00 2009 +0000
+++ b/pidgin/gtkimhtml.c	Sun Apr 05 21:13:10 2009 +0000
@@ -3320,7 +3320,8 @@
 			pos++;
 		} else if ((pos == 0 || wpos == 0 || isspace(*(c - 1))) &&
 		           (len_protocol = gtk_imhtml_is_protocol(c)) > 0 &&
-				   c[len_protocol] && !isspace(c[len_protocol])) {
+				   c[len_protocol] && !isspace(c[len_protocol]) &&
+				   (c[len_protocol] != '<' || !gtk_imhtml_is_tag(c + 1, NULL, NULL, NULL))) {
 			br = FALSE;
 			if (wpos > 0) {
 				gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos);