changeset 22760:5c65b5df9bcc

merge of '5f1a220f63d8e85758a94a2ed57381dc91b07eda' and '9698269bb39cad1afe98da492d53fc909fe8d958'
author Richard Laager <rlaager@wiktel.com>
date Mon, 28 Apr 2008 19:24:18 +0000
parents 8c3f6126759c (diff) d5fe9bd3c963 (current diff)
children 99cd68788bc0
files finch/libgnt/pygnt/Files.txt finch/libgnt/pygnt/Makefile.am finch/libgnt/pygnt/Makefile.make finch/libgnt/pygnt/README.txt finch/libgnt/pygnt/common.c finch/libgnt/pygnt/common.h finch/libgnt/pygnt/dbus-gnt finch/libgnt/pygnt/example/rss/gnthtml.py finch/libgnt/pygnt/example/rss/gntrss-ui.py finch/libgnt/pygnt/example/rss/gntrss.py finch/libgnt/pygnt/file.py finch/libgnt/pygnt/gendef.sh finch/libgnt/pygnt/gnt.override finch/libgnt/pygnt/gntbox.override finch/libgnt/pygnt/gntfilesel.override finch/libgnt/pygnt/gntmodule.c finch/libgnt/pygnt/gnttree.override finch/libgnt/pygnt/gntwidget.override finch/libgnt/pygnt/test.py
diffstat 88 files changed, 1494 insertions(+), 2829 deletions(-) [+]
line wrap: on
line diff
--- a/COPYRIGHT	Sat Apr 19 21:57:17 2008 +0000
+++ b/COPYRIGHT	Mon Apr 28 19:24:18 2008 +0000
@@ -360,6 +360,7 @@
 Dossy Shiobara
 Michael Shkutkov
 Shreevatsa R
+Dylan Simon <dylan@dylex.net>
 Ettore Simone
 John Silvestri
 Craig Slusher
--- a/ChangeLog	Sat Apr 19 21:57:17 2008 +0000
+++ b/ChangeLog	Mon Apr 28 19:24:18 2008 +0000
@@ -5,13 +5,17 @@
 	* In MySpaceIM, messages from spambots are discarded (Justin Williams)
 	* Strip mIRC formatting codes from quit and part messages.
 	* IRC now displays ban lists in-channel for joined channels.
-	
+	* Fixed a bug where the list of loaded plugins would get removed when
+	  switching between different operating systems.
+
 	Pidgin:
 	* The typing notification in the conversation history can be disabled or
 	  customized (font, color etc.) in .gtkrc-2.0.
 	* Added a plugin (not built by default) which adds a Send button back
 	  to the conversation window. People without physical keyboards have a
 	  hard time with the lack of the button.
+	* Clicking on the buddyicon in the conversation window toggles the size of
+	  the icon between small and large.
 
 	General:
 	* The configure script now dies on more absent dependencies.  The
--- a/ChangeLog.API	Sat Apr 19 21:57:17 2008 +0000
+++ b/ChangeLog.API	Mon Apr 28 19:24:18 2008 +0000
@@ -1,5 +1,17 @@
 Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
 
+version 2.x.x:
+	perl:
+		Added:
+		* Purple::Prefs::get_children_names.
+		* Purple::timeout_remove.
+		Changed:
+		* Purple::timeout_add now returns a handle which can be used
+		  to remove the timeout.
+		* Callbacks to Purple::Util::fetch_url and the
+		  Purple::Request::* functions can now be specified as both
+		  strings (the name of the callback function) and as coderefs.
+
 version 2.4.0 (02/29/2008):
 	libpurple:
 		Added:
--- a/autogen.sh	Sat Apr 19 21:57:17 2008 +0000
+++ b/autogen.sh	Mon Apr 28 19:24:18 2008 +0000
@@ -49,13 +49,21 @@
 PACKAGE="Pidgin"
 ARGS_FILE="autogen.args"
 
+libtoolize="libtoolize"
+case $(uname -s) in
+	Darwin*)
+		libtoolize="glibtoolize"
+		;;
+	*)
+esac
+
 ###############################################################################
 # Some helper functions
 ###############################################################################
 check () {
 	CMD=$1
 
-	echo -n "checking for ${CMD}... "
+	printf "%s" "checking for ${CMD}... "
 	BIN=`which ${CMD} 2> /dev/null`
 
 	if [ x"${BIN}" = x"" ] ; then
@@ -71,7 +79,7 @@
 	CMD=$1
 	shift
 
-	echo -n "running ${CMD} ${@}... "
+	printf "%s" "running ${CMD} ${@}... "
 	OUTPUT=`${CMD} ${@} 2>&1`
 	if [ $? != 0 ] ; then
 		echo "failed."
@@ -99,11 +107,11 @@
 ###############################################################################
 # Look for our args file
 ###############################################################################
-echo -n "checking for ${ARGS_FILE}: "
+printf "%s" "checking for ${ARGS_FILE}: "
 if [ -f ${ARGS_FILE} ] ; then
 	echo "found."
-	echo -n "sourcing ${ARGS_FILE}: "
-	. autogen.args
+	printf "%s" "sourcing ${ARGS_FILE}: "
+	. ${ARGS_FILE}
 	echo "done."
 else
 	echo "not found."
@@ -112,7 +120,7 @@
 ###############################################################################
 # Check for our required helpers
 ###############################################################################
-check "libtoolize";		LIBTOOLIZE=${BIN};
+check "$libtoolize";		LIBTOOLIZE=${BIN};
 check "glib-gettextize"; GLIB_GETTEXTIZE=${BIN};
 check "intltoolize";	INTLTOOLIZE=${BIN};
 check "aclocal";		ACLOCAL=${BIN};
--- a/finch/gntconv.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/finch/gntconv.c	Mon Apr 28 19:24:18 2008 +0000
@@ -682,7 +682,7 @@
 	ggc->active_conv = conv;
 	FINCH_SET_DATA(conv, ggc);
 
-	if (cc && FINCH_GET_DATA(cc)) {
+	if (cc && FINCH_GET_DATA(cc) && cc != conv) {
 		finch_conversation_set_active(conv);
 		return;
 	}
--- a/finch/libgnt/Makefile.am	Sat Apr 19 21:57:17 2008 +0000
+++ b/finch/libgnt/Makefile.am	Mon Apr 28 19:24:18 2008 +0000
@@ -1,4 +1,4 @@
-EXTRA_DIST=genmarshal pygnt
+EXTRA_DIST=genmarshal
 
 SUBDIRS = . wms
 pkgconfigdir = $(libdir)/pkgconfig
--- a/finch/libgnt/gntentry.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/finch/libgnt/gntentry.c	Mon Apr 28 19:24:18 2008 +0000
@@ -238,8 +238,15 @@
 		destroy_suggest(entry);
 		return FALSE;
 	} else if (count == 1) {
+		char *store = g_strndup(entry->start, entry->end - entry->start);
+		gboolean ret;
+
 		destroy_suggest(entry);
-		return complete_suggest(entry, sgst);
+		complete_suggest(entry, sgst);
+
+		ret = (strncmp(store, entry->start, entry->end - entry->start) != 0);
+		g_free(store);
+		return ret;
 	} else {
 		if (max > 0) {
 			GntWidget *ddown = entry->ddown;
--- a/finch/libgnt/gntmain.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/finch/libgnt/gntmain.c	Mon Apr 28 19:24:18 2008 +0000
@@ -245,8 +245,11 @@
 	}
 
 	rd += HOLDING_ESCAPE;
-	if (HOLDING_ESCAPE)
+	if (HOLDING_ESCAPE) {
 		keys[0] = '\033';
+		g_source_remove(escape_stuff.timer);
+		escape_stuff.timer = 0;
+	}
 	keys[rd] = 0;
 	gnt_wm_set_event_stack(wm, TRUE);
 
@@ -271,12 +274,6 @@
 		int p;
 
 		if (k[0] == '\033' && rd == 1) {
-			if (escape_stuff.timer) {
-				gnt_wm_process_input(wm, "\033\033");
-				g_source_remove(escape_stuff.timer);
-				escape_stuff.timer = 0;
-				break;
-			}
 			escape_stuff.timer = g_timeout_add(250, escape_timeout, NULL);
 			break;
 		}
--- a/finch/libgnt/pygnt/Files.txt	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-gendef.sh
-gnt.override
-Makefile
-test.py
-dbus-gnt
-gntmodule.c
--- a/finch/libgnt/pygnt/Makefile.am	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-EXTRA_DIST = gendef.sh
-
-pg_LTLIBRARIES = gnt.la
-
-pgdir = $(libdir)
-
-sources = \
-	gnt.def \
-	gnt.override \
-	gntbox.override \
-	gntfilesel.override \
-	gnttree.override \
-	gntwidget.override
-
-gnt_la_SOURCES = gnt.c common.c common.h gntmodule.c
-
-gnt_la_LDFLAGS = -module -avoid-version \
-	`pkg-config --libs pygobject-2.0`
-
-gnt_la_LIBADD = \
-	$(GLIB_LIBS) \
-	../libgnt.la
-
-AM_CPPFLAGS = \
-	-I../ \
-	$(GLIB_CFLAGS) \
-	$(GNT_CFLAGS)  \
-	-I/usr/include/python2.4 \
-	`pkg-config --cflags pygobject-2.0`
-
-CLEANFILES = gnt.def gnt.c gnt.defe
-
-gnt.def: $(srcdir)/../*.h
-	$(srcdir)/gendef.sh
-
-gnt.c: $(sources)
-	pygtk-codegen-2.0 --prefix gnt \
-	--override gnt.override \
-	gnt.def > $@
-
--- a/finch/libgnt/pygnt/Makefile.make	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-CC = gcc
-CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -I/usr/include/python2.4/ -I.. -g -O0
-LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0 gnt`
- 
-gnt.so: gnt.o gntmodule.o common.o
-	$(CC) $(LDFLAGS) -shared $^ -o $@
-
-gnt.c: gnt.def *.override common.c common.h
-	pygtk-codegen-2.0 --prefix gnt \
-	--override gnt.override \
-	gnt.def > $@
-
-#python codegen/codegen.py --prefix gnt \
-
-clean:
-	@rm *.so *.o gnt.c
--- a/finch/libgnt/pygnt/README.txt	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-Run these in sequence:
-
-./gendef.sh
-make -f Makefile.make gnt.so
--- a/finch/libgnt/pygnt/common.c	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#include "common.h"
-
-PyObject *
-create_pyobject_from_string_list(GList *list)
-{
-	PyObject *py_list;
-	if (list == NULL) {
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
-	if ((py_list = PyList_New(0)) == NULL) {
-		g_list_foreach(list, (GFunc)g_free, NULL);
-		g_list_free(list);
-		return NULL;
-	}
-	while (list) {
-		PyObject *obj = PyString_FromString(list->data);
-		PyList_Append(py_list, obj);
-		Py_DECREF(obj);
-		g_free(list->data);
-		list = g_list_delete_link(list, list);
-	}
-	return py_list;
-}
--- a/finch/libgnt/pygnt/common.h	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-#include "Python.h"
-#include "gnt.h"
-
-PyObject *create_pyobject_from_string_list(GList *list);
-
--- a/finch/libgnt/pygnt/dbus-gnt	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-#!/usr/bin/env python
-
-# This script requires Python 2.4 and pygnt bindings
-#
-# Note that all function names are resolved dynamically, no
-# purple-specific library is needed.
-
-import dbus
-import dbus.glib
-import dbus.decorators
-import gobject
-import os
-import gnt
-import sys
-
-import time
-
-convwins = {}
-
-def buddysignedon(buddy):
-    pass
-
-def conv_closed(conv):
-    key = get_dict_key(conv)
-    stuff = convwins[key]
-    stuff[0].destroy()
-    # if a conv window is closed, then reopened, this thing crashes
-    convwins[key] = None
-
-def add_message(conv, who, msg, flags, timestamp):
-    stuff = show_conversation(conv, False)
-    tv = stuff[1]
-    tv.append_text_with_flags("\n", 0)
-    if timestamp:
-        tv.append_text_with_flags(time.strftime("(%X) ", time.localtime(timestamp)), 8)
-    else:
-        tv.append_text_with_flags(time.strftime("(%X) "), 8)
-    if flags & 3:
-        tv.append_text_with_flags(who + ": ", 1)
-        msg = purple.PurpleMarkupStripHtml(msg)
-        tv.append_text_with_flags(msg, 0)
-        stuff[0].set_urgent()
-    else:
-        tv.append_text_with_flags(msg, 8)
-    tv.scroll(0)
-
-def wrote_msg(account, who, msg, conv, flags):
-    add_message(conv, who, msg, flags, None)
-
-bus = dbus.SessionBus()
-obj = bus.get_object("im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
-purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
-
-bus.add_signal_receiver(buddysignedon,
-                        dbus_interface = "im.pidgin.purple.PurpleInterface",
-                        signal_name = "BuddySignedOn")
-
-bus.add_signal_receiver(wrote_msg,
-                        dbus_interface = "im.pidgin.purple.PurpleInterface",
-                        signal_name = "WroteImMsg")
-
-bus.add_signal_receiver(wrote_msg,
-                        dbus_interface = "im.pidgin.purple.PurpleInterface",
-                        signal_name = "WroteChatMsg")
-
-bus.add_signal_receiver(conv_closed,
-                        dbus_interface = "im.pidgin.purple.PurpleInterface",
-                        signal_name = "DeletingConversation")
-
-def get_dict_key(conv):
-    val = purple.PurpleConversationGetName(conv)
-    return val
-
-def send_im_cb(entry, key, conv):
-    if key[0] == '\r':
-        # XXX: do something about the / commands
-        type = purple.PurpleConversationGetType(conv)
-        if type == 1:
-            imdata = purple.PurpleConversationGetImData(conv)
-            purple.PurpleConvImSend(imdata, entry.get_text())
-        else:
-            chatdata = purple.PurpleConversationGetChatData(conv)
-            purple.PurpleConvChatSend(chatdata, entry.get_text())
-        entry.clear()
-
-def conv_window_destroyed(win, key):
-    del convwins[key]
-
-def show_conversation(conv, history):
-    key = get_dict_key(conv)
-    if key in convwins:
-        return convwins[key]
-    win = gnt.Window()
-    vbox = gnt.Box(0, 1)
-    win.add_widget(vbox)
-    win.set_title(purple.PurpleConversationGetName(conv))
-    win.set_pad(0)
-    vbox.set_pad(0)
-    tv = gnt.TextView()
-    entry = gnt.Entry("")
-    vbox.add_widget(tv)
-    entry.set_size(40, 1)
-    vbox.add_widget(entry)
-    entry.connect("key_pressed", send_im_cb, conv)
-    tv.clear()
-    tv.attach_scroll_widget(entry)
-    win.show()
-    convwins[key] = [win, tv, entry]
-    win.connect("destroy", conv_window_destroyed, key)
-    
-    if history:
-        msgs = purple.PurpleConversationGetMessageHistory(conv)
-        msgs.reverse()
-        for msg in msgs:
-            who = purple.PurpleConversationMessageGetSender(msg)
-            what = purple.PurpleConversationMessageGetMessage(msg)
-            flags = purple.PurpleConversationMessageGetFlags(msg)
-            when = purple.PurpleConversationMessageGetTimestamp(msg)
-            add_message(conv, who, what, flags, when)
-
-    return convwins[key]
-
-def show_buddylist():
-    win = gnt.Window()
-    tree = gnt.Tree()
-    tree.set_property("columns", 1)
-    win.add_widget(tree)
-    node = purple.PurpleBlistGetRoot()
-    while node:
-        if purple.PurpleBlistNodeIsGroup(node):
-            sys.stderr.write(str(node) + "\n")
-            tree.add_row_after(str(node), ["asd", ""], None, None)
-            #tree.add_row_after(node, [str(purple.PurpleGroupGetName(node)), ""], None, None)
-            #tree.add_row_after(node, ["aasd", ""], None, None)
-        elif purple.PurpleBlistNodeIsContact(node):
-            buddy = purple.PurpleContactGetPriorityBuddy(node)
-            group = purple.PurpleBuddyGetGroup(buddy)
-            #tree.add_row_after(node, [str(purple.PurpleBuddyGetName(buddy)), ""], group, None)
-
-        node = purple.PurpleBlistNodeNext(node, False)
-    win.show()
-
-gnt.gnt_init()
-
-# show_buddylist()
-
-convs = purple.PurpleGetConversations()
-for conv in convs:
-    show_conversation(conv, True)
-
-gnt.gnt_main()
-
-gnt.gnt_quit()
-
--- a/finch/libgnt/pygnt/example/rss/gnthtml.py	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-#!/usr/bin/env python
-
-"""
-gr - An RSS-reader built using libgnt and feedparser.
-
-Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
-
-This application is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This application is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this application; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
-USA
-"""
-
-"""
-This file defines GParser, which is a simple HTML parser to display HTML
-in a GntTextView nicely.
-"""
-
-import sgmllib
-import gnt
-
-class GParser(sgmllib.SGMLParser):
-    def __init__(self, view):
-        sgmllib.SGMLParser.__init__(self, False)
-        self.link = None
-        self.view = view
-        self.flag = gnt.TEXT_FLAG_NORMAL
-
-    def parse(self, s):
-        self.feed(s)
-        self.close()
-
-    def unknown_starttag(self, tag, attrs):
-        if tag in ["b", "i", "blockquote", "strong"]:
-            self.flag = self.flag | gnt.TEXT_FLAG_BOLD
-        elif tag in ["p", "hr", "br"]:
-            self.view.append_text_with_flags("\n", self.flag)
-        else:
-            print tag
-
-    def unknown_endtag(self, tag):
-        if tag in ["b", "i", "blockquote", "strong"]:
-            self.flag = self.flag & ~gnt.TEXT_FLAG_BOLD
-        elif tag in ["p", "hr", "br"]:
-            self.view.append_text_with_flags("\n", self.flag)
-        else:
-            print tag
-
-    def start_u(self, attrs):
-        self.flag = self.flag | gnt.TEXT_FLAG_UNDERLINE
-
-    def end_u(self):
-        self.flag = self.flag & ~gnt.TEXT_FLAG_UNDERLINE
-
-    def start_a(self, attributes):
-        for name, value in attributes:
-            if name == "href":
-                self.link = value
-
-    def do_img(self, attrs):
-        for name, value in attrs:
-            if name == 'src':
-                self.view.append_text_with_flags("[img:" + value + "]", self.flag)
-
-    def end_a(self):
-        if not self.link:
-            return
-        self.view.append_text_with_flags(" (", self.flag)
-        self.view.append_text_with_flags(self.link, self.flag | gnt.TEXT_FLAG_UNDERLINE)
-        self.view.append_text_with_flags(")", self.flag)
-        self.link = None
-
-    def handle_data(self, data):
-        if len(data.strip()) == 0:
-            return
-        self.view.append_text_with_flags(data, self.flag)
-
--- a/finch/libgnt/pygnt/example/rss/gntrss-ui.py	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,400 +0,0 @@
-#!/usr/bin/env python
-
-"""
-gr - An RSS-reader built using libgnt and feedparser.
-
-Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
-
-This application is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This application is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this application; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
-USA
-"""
-
-"""
-This file deals with the UI part (gnt) of the application
-
-TODO:
-    - Allow showing feeds of only selected 'category' and/or 'priority'. A different
-      window should be used to change such filtering.
-    - Display details of each item in its own window.
-    - Add search capability, and allow searching only in title/body. Also allow
-      filtering in the search results.
-    - Show the data and time for feed items (probably in a separate column .. perhaps not)
-    - Have a simple way to add a feed.
-    - Allow renaming a feed.
-"""
-
-import gntrss
-import gnthtml
-import gnt
-import gobject
-import sys
-
-__version__ = "0.0.1alpha"
-__author__ = "Sadrul Habib Chowdhury (sadrul@pidgin.im)"
-__copyright__ = "Copyright 2007, Sadrul Habib Chowdhury"
-__license__ = "GPL" # see full license statement above
-
-gnt.gnt_init()
-
-class RssTree(gnt.Tree):
-    __gsignals__ = {
-        'active_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,))
-    }
-
-    __gntbindings__ = {
-        'jump-next-unread' : ('jump_next_unread', 'n')
-    }
-
-    def jump_next_unread(self, null):
-        first = None
-        next = None
-        all = self.get_rows()
-        for item in all:
-            if item.unread:
-                if next:
-                    first = item
-                    break
-                elif not first and self.active != item:
-                    first = item
-            if self.active == item:
-                next = item
-        if first:
-            self.set_active(first)
-            self.set_selected(first)
-        return True
-
-    def __init__(self):
-        self.active = None
-        gnt.Tree.__init__(self)
-        gnt.set_flag(self, 8)    # remove borders
-        self.connect('key_pressed', self.do_key_pressed)
-
-    def set_active(self, active):
-        if self.active == active:
-            return
-        if self.active:
-            flag = gnt.TEXT_FLAG_NORMAL
-            if self.active.unread:
-                flag = flag | gnt.TEXT_FLAG_BOLD
-            self.set_row_flags(self.active, flag)
-        old = self.active
-        self.active = active
-        flag = gnt.TEXT_FLAG_UNDERLINE
-        if self.active.unread:
-            flag = flag | gnt.TEXT_FLAG_BOLD
-        self.set_row_flags(self.active, flag)
-        self.emit('active_changed', old)
-
-    def do_key_pressed(self, null, text):
-        if text == '\r':
-            now = self.get_selection_data()
-            self.set_active(now)
-            return True
-        return False
-
-gobject.type_register(RssTree)
-gnt.register_bindings(RssTree)
-
-win = gnt.Box(homo = False, vert = True)
-win.set_toplevel(True)
-win.set_title("GntRss")
-win.set_pad(0)
-
-#
-# [[[ Generic feed/item callbacks
-#
-def feed_item_added(feed, item):
-    add_feed_item(item)
-
-def add_feed(feed):
-    if not feed.get_data('gntrss-connected'):
-        feed.connect('added', feed_item_added)
-        feed.connect('notify', update_feed_title)
-        feed.set_data('gntrss-connected', True)
-    feeds.add_row_after(feed, [feed.title, str(feed.unread)], None, None)
-
-def remove_item(item, feed):
-    items.remove(item)
-
-def update_feed_item(item, property):
-    if property.name == 'unread':
-        if feeds.active == item.parent:
-            flag = 0
-            if item == items.active:
-                flag = gnt.TEXT_FLAG_UNDERLINE
-            if item.unread:
-                flag = flag | gnt.TEXT_FLAG_BOLD
-            else:
-                flag = flag | gnt.TEXT_FLAG_NORMAL
-            items.set_row_flags(item, flag)
-
-        unread = item.parent.unread
-        if item.unread:
-            unread = unread + 1
-        else:
-            unread = unread - 1
-        item.parent.set_property('unread', unread)
-
-def add_feed_item(item):
-    currentfeed = feeds.active
-    if item.parent != currentfeed:
-        return
-    months = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
-    dt = str(item.date_parsed[2]) + "." + months[item.date_parsed[1]] + "." + str(item.date_parsed[0])
-    items.add_row_after(item, [str(item.title), dt], None, None)
-    if item.unread:
-        items.set_row_flags(item, gnt.TEXT_FLAG_BOLD)
-    if not item.get_data('gntrss-connected'):
-        item.set_data('gntrss-connected', True)
-        # this needs to happen *without* having to add the item in the tree
-        item.connect('notify', update_feed_item)
-        item.connect('delete', remove_item)
-
-#
-# ]]] Generic feed/item callbacks
-#
-
-
-####
-# [[[ The list of feeds
-###
-
-# 'Add Feed' dialog
-add_feed_win = None
-def add_feed_win_closed(win):
-    global add_feed_win
-    add_feed_win = None
-
-def add_new_feed():
-    global add_feed_win
-
-    if add_feed_win:
-        gnt.gnt_window_present(add_feed_win)
-        return
-    win = gnt.Window()
-    win.set_title("New Feed")
-
-    box = gnt.Box(False, False)
-    label = gnt.Label("Link")
-    box.add_widget(label)
-    entry = gnt.Entry("")
-    entry.set_size(40, 1)
-    box.add_widget(entry)
-
-    win.add_widget(box)
-    win.show()
-    add_feed_win = win
-    add_feed_win.connect("destroy", add_feed_win_closed)
-
-#
-# The active row in the feed-list has changed. Update the feed-item table.
-def feed_active_changed(tree, old):
-    items.remove_all()
-    if not tree.active:
-        return
-    update_items_title()
-    for item in tree.active.items:
-        add_feed_item(item)
-    win.give_focus_to_child(items)
-
-#
-# Check for the action keys and decide how to deal with them.
-def feed_key_pressed(tree, text):
-    if tree.is_searching():
-        return
-    if text == 'r':
-        feed = tree.get_selection_data()
-        tree.perform_action_key('j')
-        #tree.perform_action('move-down')
-        feed.refresh()
-    elif text == 'R':
-        feeds = tree.get_rows()
-        for feed in feeds:
-            feed.refresh()
-    elif text == 'm':
-        feed = tree.get_selection_data()
-        if feed:
-            feed.mark_read()
-            feed.set_property('unread', 0)
-    elif text == 'a':
-        add_new_feed()
-    else:
-        return False
-    return True
-
-feeds = RssTree()
-feeds.set_property('columns', 2)
-feeds.set_col_width(0, 20)
-feeds.set_col_width(1, 6)
-feeds.set_column_resizable(0, False)
-feeds.set_column_resizable(1, False)
-feeds.set_column_is_right_aligned(1, True)
-feeds.set_show_separator(False)
-feeds.set_column_title(0, "Feeds")
-feeds.set_show_title(True)
-
-feeds.connect('active_changed', feed_active_changed)
-feeds.connect('key_pressed', feed_key_pressed)
-gnt.unset_flag(feeds, 256)   # Fix the width
-
-####
-# ]]] The list of feeds
-###
-
-####
-# [[[ The list of items in the feed
-####
-
-#
-# The active item in the feed-item list has changed. Update the
-# summary content.
-def item_active_changed(tree, old):
-    details.clear()
-    if not tree.active:
-        return
-    item = tree.active
-    details.append_text_with_flags(str(item.title) + "\n", gnt.TEXT_FLAG_BOLD)
-    details.append_text_with_flags("Link: ", gnt.TEXT_FLAG_BOLD)
-    details.append_text_with_flags(str(item.link) + "\n", gnt.TEXT_FLAG_UNDERLINE)
-    details.append_text_with_flags("Date: ", gnt.TEXT_FLAG_BOLD)
-    details.append_text_with_flags(str(item.date) + "\n", gnt.TEXT_FLAG_NORMAL)
-    details.append_text_with_flags("\n", gnt.TEXT_FLAG_NORMAL)
-    parser = gnthtml.GParser(details)
-    parser.parse(str(item.summary))
-    item.mark_unread(False)
-
-    if old and old.unread:   # If the last selected item is marked 'unread', then make sure it's bold
-        items.set_row_flags(old, gnt.TEXT_FLAG_BOLD)
-
-#
-# Look for action keys in the feed-item list.
-def item_key_pressed(tree, text):
-    if tree.is_searching():
-        return
-    current = tree.get_selection_data()
-    if text == 'M':     # Mark all of the items 'read'
-        feed = feeds.active
-        if feed:
-            feed.mark_read()
-    elif text == 'm':     # Mark the current item 'read'
-        current.mark_unread(False)
-        tree.perform_action_key('j')
-    elif text == 'U':     # Mark the current item 'unread'
-        current.mark_unread(True)
-    elif text == 'd':
-        current.remove()
-        tree.perform_action_key('j')
-    else:
-        return False
-    return True
-
-items = RssTree()
-items.set_property('columns', 2)
-items.set_col_width(0, 40)
-items.set_col_width(1, 11)
-items.set_column_resizable(1, False)
-items.set_column_title(0, "Items")
-items.set_column_title(1, "Date")
-items.set_show_title(True)
-items.connect('key_pressed', item_key_pressed)
-items.connect('active_changed', item_active_changed)
-
-####
-# ]]] The list of items in the feed
-####
-
-#
-# Update the title of the items list depending on the selection in the feed list
-def update_items_title():
-    feed = feeds.active
-    if feed:
-        items.set_column_title(0, str(feed.title) + ": " + str(feed.unread) + "(" + str(len(feed.items)) + ")")
-    else:
-        items.set_column_title(0, "Items")
-    items.draw()
-
-# The container on the top
-line = gnt.Line(vertical = False)
-
-# The textview to show the details of a feed
-details = gnt.TextView()
-details.set_take_focus(True)
-details.set_flag(gnt.TEXT_VIEW_TOP_ALIGN)
-details.attach_scroll_widget(details)
-
-# Make it look nice
-s = feeds.get_size()
-size = gnt.screen_size()
-size[0] = size[0] - s[0]
-items.set_size(size[0], size[1] / 2)
-details.set_size(size[0], size[1] / 2)
-
-# Category tree
-cat = gnt.Tree()
-cat.set_property('columns', 1)
-cat.set_column_title(0, 'Category')
-cat.set_show_title(True)
-gnt.set_flag(cat, 8)    # remove borders
-
-box = gnt.Box(homo = False, vert = False)
-box.set_pad(0)
-
-vbox = gnt.Box(homo = False, vert = True)
-vbox.set_pad(0)
-vbox.add_widget(feeds)
-vbox.add_widget(gnt.Line(False))
-vbox.add_widget(cat)
-box.add_widget(vbox)
-
-box.add_widget(gnt.Line(True))
-
-vbox = gnt.Box(homo = False, vert = True)
-vbox.set_pad(0)
-vbox.add_widget(items)
-vbox.add_widget(gnt.Line(False))
-vbox.add_widget(details)
-box.add_widget(vbox)
-
-win.add_widget(box)
-win.show()
-
-def update_feed_title(feed, property):
-    if property.name == 'title':
-        if feed.customtitle:
-            title = feed.customtitle
-        else:
-            title = feed.title
-        feeds.change_text(feed, 0, title)
-    elif property.name == 'unread':
-        feeds.change_text(feed, 1, str(feed.unread) + "(" + str(len(feed.items)) + ")")
-        flag = 0
-        if feeds.active == feed:
-            flag = gnt.TEXT_FLAG_UNDERLINE
-            update_items_title()
-        if feed.unread > 0:
-            flag = flag | gnt.TEXT_FLAG_BOLD
-        feeds.set_row_flags(feed, flag)
-
-# populate everything
-for feed in gntrss.feeds:
-    feed.refresh()
-    feed.set_auto_refresh(True)
-    add_feed(feed)
-
-gnt.gnt_register_action("Stuff", add_new_feed)
-gnt.gnt_main()
-
-gnt.gnt_quit()
-
--- a/finch/libgnt/pygnt/example/rss/gntrss.py	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
-#!/usr/bin/env python
-
-"""
-gr - An RSS-reader built using libgnt and feedparser.
-
-Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
-
-This application is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation; either
-version 2.1 of the License, or (at your option) any later version.
-
-This application is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this application; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
-USA
-"""
-
-"""
-This file deals with the rss parsing part (feedparser) of the application
-"""
-
-import os
-import tempfile, urllib2
-import feedparser
-import gobject
-import sys
-import time
-
-##
-# The FeedItem class. It will update emit 'delete' signal when it's
-# destroyed.
-##
-class FeedItem(gobject.GObject):
-    __gproperties__ = {
-        'unread' : (gobject.TYPE_BOOLEAN, 'read',
-            'The unread state of the item.',
-            False, gobject.PARAM_READWRITE)
-    }
-    __gsignals__ = {
-        'delete' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,))
-    }
-    def __init__(self, item, parent):
-        self.__gobject_init__()
-        try:
-            "Apparently some feed items don't have any dates in them"
-            self.date = item['date']
-            self.date_parsed = item['date_parsed']
-        except:
-            item['date'] = self.date = time.ctime()
-            self.date_parsed = feedparser._parse_date(self.date)
-
-        self.title = item['title'].encode('utf8')
-        self.summary = item['summary'].encode('utf8')
-        self.link = item['link']
-        self.parent = parent
-        self.unread = True
-
-    def __del__(self):
-        pass
-
-    def remove(self):
-        self.emit('delete', self.parent)
-        if self.unread:
-            self.parent.set_property('unread', self.parent.unread - 1)
-
-    def do_set_property(self, property, value):
-        if property.name == 'unread':
-            self.unread = value
-
-    def mark_unread(self, unread):
-        if self.unread == unread:
-            return
-        self.set_property('unread', unread)
-
-gobject.type_register(FeedItem)
-
-def item_hash(item):
-    return str(item['title'])
-
-"""
-The Feed class. It will update the 'link', 'title', 'desc' and 'items'
-attributes if/when they are updated (triggering 'notify::<attr>' signal)
-
-TODO:
-    - Add a 'count' attribute
-    - Each feed will have a 'uidata', which will be its display window
-    - Look into 'category'. Is it something that feed defines, or the user?
-    - Have separate refresh times for each feed.
-    - Have 'priority' for each feed. (somewhat like category, perhaps?)
-"""
-class Feed(gobject.GObject):
-    __gproperties__ = {
-        'link' : (gobject.TYPE_STRING, 'link',
-            'The web page this feed is associated with.',
-            '...', gobject.PARAM_READWRITE),
-        'title' : (gobject.TYPE_STRING, 'title',
-            'The title of the feed.',
-            '...', gobject.PARAM_READWRITE),
-        'desc' : (gobject.TYPE_STRING, 'description',
-            'The description for the feed.',
-            '...', gobject.PARAM_READWRITE),
-        'items' : (gobject.TYPE_POINTER, 'items',
-            'The items in the feed.', gobject.PARAM_READWRITE),
-        'unread' : (gobject.TYPE_INT, 'unread',
-            'Number of unread items in the feed.', 0, 10000, 0, gobject.PARAM_READWRITE)
-    }
-    __gsignals__ = {
-        'added' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,))
-    }
-
-    def __init__(self, feed):
-        self.__gobject_init__()
-        url = feed['link']
-        name = feed['name']
-        self.url = url           # The url of the feed itself
-        self.link = url          # The web page associated with the feed
-        self.desc = url
-        self.title = (name, url)[not name]
-        self.customtitle = name
-        self.unread = 0
-        self.items = []
-        self.hash = {}
-        self.pending = False
-        self._refresh = {'time' : 30, 'id' : 0}
-
-    def __del__(self):
-        pass
-
-    def do_set_property(self, property, value):
-        if property.name == 'link':
-            self.link = value
-        elif property.name == 'desc':
-            self.desc = value
-        elif property.name == 'title':
-            self.title = value
-        elif property.name == 'unread':
-            self.unread = value
-        pass
-
-    def set_result(self, result):
-        # XXX Look at result['bozo'] first, and emit some signal that the UI can use
-        # to indicate (dim the row?) that the feed has invalid XML format or something
-
-        try:
-            channel = result['channel']
-            self.set_property('link', channel['link'])
-            self.set_property('desc', channel['description'])
-            self.set_property('title', channel['title'])
-            items = result['items']
-        except:
-            items = ()
-
-        tmp = {}
-        for item in self.items:
-            tmp[hash(item)] = item
-
-        unread = self.unread
-        for item in items:
-            try:
-                exist = self.hash[item_hash(item)]
-                del tmp[hash(exist)]
-            except:
-                itm = FeedItem(item, self)
-                self.items.append(itm)
-                self.emit('added', itm)
-                self.hash[item_hash(item)] = itm
-                unread = unread + 1
-
-        if unread != self.unread:
-            self.set_property('unread', unread)
-
-        for hv in tmp:
-            self.items.remove(tmp[hv])
-            tmp[hv].remove()
-            "Also notify the UI about the count change"
-
-        self.pending = False
-        return False
-
-    def refresh(self):
-        if self.pending:
-            return
-        self.pending = True
-        FeedReader(self).run()
-        return True
-
-    def mark_read(self):
-        for item in self.items:
-            item.mark_unread(False)
-
-    def set_auto_refresh(self, auto):
-        if auto:
-            if self._refresh['id']:
-                return
-            if self._refresh['time'] < 1:
-                self._refresh['time'] = 1
-            self.id = gobject.timeout_add(self._refresh['time'] * 1000 * 60, self.refresh)
-        else:
-            if not self._refresh['id']:
-                return
-            gobject.source_remove(self._refresh['id'])
-            self._refresh['id'] = 0
-
-gobject.type_register(Feed)
-
-"""
-The FeedReader updates a Feed. It fork()s off a child to avoid blocking.
-"""
-class FeedReader:
-    def __init__(self, feed):
-        self.feed = feed
-
-    def reap_child(self, pid, status):
-        result = feedparser.parse(self.tmpfile.name)
-        self.tmpfile.close()
-        self.feed.set_result(result)
-
-    def run(self):
-        self.tmpfile = tempfile.NamedTemporaryFile()
-        self.pid = os.fork()
-        if self.pid == 0:
-            tmp = urllib2.urlopen(self.feed.url)
-            content = tmp.read()
-            tmp.close()
-            self.tmpfile.write(content)
-            self.tmpfile.flush()
-            # Do NOT close tmpfile here
-            os._exit(os.EX_OK)
-        gobject.child_watch_add(self.pid, self.reap_child)
-
-feeds = []
-urls = (
-    {'name': '/.',
-     'link': "http://rss.slashdot.org/Slashdot/slashdot"},
-    {'name': 'KernelTrap',
-     'link': "http://kerneltrap.org/node/feed"},
-    {'name': None,
-     'link': "http://pidgin.im/rss.php"},
-    {'name': "F1",
-     'link': "http://www.formula1.com/rss/news/latest.rss"},
-    {'name': "Freshmeat",
-     'link': "http://www.pheedo.com/f/freshmeatnet_announcements_unix"},
-    {'name': "Cricinfo",
-     'link': "http://www.cricinfo.com/rss/livescores.xml"}
-)
-
-for url in urls:
-    feed = Feed(url)
-    feeds.append(feed)
-
--- a/finch/libgnt/pygnt/file.py	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-
-import gnt, sys
-
-def file_selected(widget, path, file, null):
-	sys.stderr.write(path + " " + file)
-	list = widget.get_selected_multi_files()
-	for i in list:
-		sys.stderr.write(i)
-
-gnt.gnt_init()
-
-win = gnt.Window()
-
-files = gnt.FileSel()
-files.set_multi_select(True)
-files.set_title("Files")
-files.connect("file_selected", file_selected, None)
-
-files.show()
-
-gnt.gnt_main()
-
-gnt.gnt_quit()
--- a/finch/libgnt/pygnt/gendef.sh	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-#!/bin/sh
-FILES="
-	gntwidget.h
-	gntbindable.h
-	gntbox.h
-	gntbutton.h
-	gntcheckbox.h
-	gntclipboard.h
-	gntcolors.h
-	gntcombobox.h
-	gntentry.h
-	gntfilesel.h
-	gntkeys.h
-	gntlabel.h
-	gntline.h
-	gntmarshal.h
-	gntmenu.h
-	gntmenuitem.h
-	gntmenuitemcheck.h
-	gntslider.h
-	gntstyle.h
-	gnttextview.h
-	gnttree.h
-	gntutils.h
-	gntwindow.h
-	gntwm.h
-	gntws.h
-	gnt.h"
-
-# Generate the def file
-rm -f gnt.def
-for file in $FILES
-do
-	echo -n "Generating definitions for ${file} ... "
-	python /usr/share/pygtk/2.0/codegen/h2def.py ../$file >> gnt.def
-	echo "Done"
-done
-
-# Remove the definitions about the enums
-ENUMS="
-GNT_TYPE_ALIGNMENT
-GNT_TYPE_COLOR_TYPE
-GNT_TYPE_MENU_TYPE
-GNT_TYPE_STYLE
-GNT_TYPE_KEY_PRESS_MODE
-GNT_TYPE_ENTRY_FLAG
-GNT_TYPE_TEXT_FORMAT_FLAGS
-GNT_TYPE_TEXT_VIEW_FLAG
-"
-
-for enum in $ENUMS
-do
-	sed -ie s/^.*gtype-id\ \"$enum\".*$//g gnt.def
-done
-
-
--- a/finch/libgnt/pygnt/gnt.override	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-%%
-headers
-#include <Python.h>
-#include "pygobject.h"
-#include "gnt.h"
-#include "gntbindable.h"
-#include "gntwidget.h"
-#include "gntbox.h"
-#include "gntbutton.h"
-#include "gntcheckbox.h"
-#include "gntcolors.h"
-#include "gntcombobox.h"
-#include "gntentry.h"
-#include "gntfilesel.h"
-#include "gntkeys.h"
-#include "gntlabel.h"
-#include "gntline.h"
-#include "gntmenu.h"
-#include "gntmenuitem.h"
-#include "gntmenuitemcheck.h"
-#include "gntslider.h"
-#include "gntstyle.h"
-#include "gnttextview.h"
-#include "gnttree.h"
-#include "gntutils.h"
-#include "gntwindow.h"
-#include "gntwm.h"
-#include "gntws.h"
-#include "common.h"
-%%
-include
- gntbox.override
- gntfilesel.override
- gnttree.override
- gntwidget.override
-%%
-modulename gnt
-%%
-import gobject.GObject as PyGObject_Type
-%%
-ignore-glob
-	*_get_gtype
-%%
-define set_flag
-static PyObject *
-_wrap_set_flag(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = {"flags", NULL};
-	PyGObject *widget;
-	int flags;
-
-	if (!PyArg_ParseTuple(args, "O!i:gnt.set_flag", &PyGntWidget_Type, &widget,
-				&flags)) {
-		return NULL;
-	}
-
-	GNT_WIDGET_SET_FLAGS(widget->obj, flags);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-define unset_flag
-static PyObject *
-_wrap_unset_flag(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = {"flags", NULL};
-	PyGObject *widget;
-	int flags;
-
-	if (!PyArg_ParseTuple(args, "O!i:gnt.unset_flag", &PyGntWidget_Type, &widget,
-				&flags)) {
-		return NULL;
-	}
-
-	GNT_WIDGET_UNSET_FLAGS(widget->obj, flags);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-define screen_size noargs
-static PyObject *
-_wrap_screen_size(PyObject *self)
-{
-	PyObject *list = PyList_New(0);
-
-	if (list == NULL)
-		return NULL;
-
-	PyList_Append(list, PyInt_FromLong((long)getmaxx(stdscr)));
-	PyList_Append(list, PyInt_FromLong((long)getmaxy(stdscr)));
-
-	return list;
-}
-%%
-override gnt_register_action
-static GHashTable *actions;
-
-
-
-static PyObject *
-_wrap_gnt_register_action(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = {"name", "callback", NULL};
-	PyGObject *callback;
-	GClosure *closure;
-	char *name;
-
-	if (!PyArg_ParseTuple(args, "sO:gnt.gnt_register_action", &name, &callback)) {
-		return NULL;
-	}
-
-	if (!PyCallable_Check(callback)) {
-		PyErr_SetString(PyExc_TypeError, "the callback must be callable ... doh!");
-		return NULL;
-	}
-
-	gnt_register_action(name, callback->obj);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-define register_bindings
-
-static gboolean
-pygnt_binding_callback(GntBindable *bindable, GList *list)
-{
-	PyObject *wrapper = pygobject_new(G_OBJECT(bindable));
-	PyObject_CallMethod(wrapper, list->data, "O", Py_None);
-	Py_DECREF(wrapper);
-	return TRUE;
-}
-
-static PyObject *
-_wrap_register_bindings(PyObject *self, PyObject *args)
-{
-	PyTypeObject *class;
-	int pos = 0;
-	PyObject *key, *value, *gbindings;
-	GntBindableClass *bindable;
-
-	if (!PyArg_ParseTuple(args, "O!:gnt.register_bindings",
-				&PyType_Type, &class)) {
-		/* Make sure it's a GntBindableClass subclass */
-		PyErr_SetString(PyExc_TypeError,
-				"argument must be a GntBindable subclass");
-		return NULL;
-	}
-
-	gbindings = PyDict_GetItemString(class->tp_dict, "__gntbindings__");
-	if (!gbindings)
-		goto end;
-
-	if (!PyDict_Check(gbindings)) {
-		PyErr_SetString(PyExc_TypeError,
-				"__gntbindings__ attribute not a dict!");
-		return NULL;
-	}
-
-	bindable = g_type_class_ref(pyg_type_from_object((PyObject *)class));
-	while (PyDict_Next(gbindings, &pos, &key, &value)) {
-		const char *trigger, *callback, *name;
-		GList *list = NULL;
-
-		if (!PyString_Check(key)) {
-			PyErr_SetString(PyExc_TypeError,
-					"__gntbindings__ keys must be strings");
-			g_type_class_unref(bindable);
-			return NULL;
-		}
-		name = PyString_AsString(key);
-
-		if (!PyTuple_Check(value) ||
-				!PyArg_ParseTuple(value, "ss", &callback, &trigger)) {
-			PyErr_SetString(PyExc_TypeError,
-					"__gntbindings__ values must be (callback, trigger) tupples");
-			g_type_class_unref(bindable);
-			return NULL;
-		}
-
-		gnt_bindable_class_register_action(bindable, name, pygnt_binding_callback,
-				trigger, g_strdup(callback), NULL);
-	}
-	if (gbindings)
-		PyDict_DelItemString(class->tp_dict, "__gntbindings__");
-	g_type_class_unref(bindable);
-
-end:
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-
--- a/finch/libgnt/pygnt/gntbox.override	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/**
- * pygnt- Python bindings for the GNT toolkit.
- * Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
- *
- *   gntbox.override: overrides for the box widget.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
- * USA
- */
-%%
-override gnt_box_add_widget kwargs
-static PyObject *
-_wrap_gnt_box_add_widget(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-    static char *kwlist[] = { "widget", NULL };
-    PyGObject *widget;
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:GntBox.add_widget", kwlist, &PyGntWidget_Type, &widget))
-        return NULL;
-    
-    gnt_box_add_widget(GNT_BOX(self->obj), GNT_WIDGET(widget->obj));
-	Py_INCREF(widget);
-    
-    Py_INCREF(Py_None);
-    return Py_None;
-}
--- a/finch/libgnt/pygnt/gntfilesel.override	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/**
- * pygnt- Python bindings for the GNT toolkit.
- * Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
- *
- *   gntfilesel.override: overrides for the file selector.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
- * USA
- */
-%%
-headrs
-#include "common.h"
-%%
-override gnt_file_sel_get_selected_multi_files noargs
-static PyObject *
-_wrap_gnt_file_sel_get_selected_multi_files(PyGObject *self)
-{
-	GList *list = gnt_file_sel_get_selected_multi_files(GNT_FILE_SEL(self->obj));
-	return create_pyobject_from_string_list(list);
-}
-
--- a/finch/libgnt/pygnt/gntmodule.c	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-#include <pygobject.h>
-#include "gnt.h"
- 
-void gnt_register_classes (PyObject *d); 
-extern PyMethodDef gnt_functions[];
-
-static void
-gnt_add_string_constants(PyObject *module)
-{
-#define define_key(x) if (GNT_KEY_##x && *(GNT_KEY_##x))  PyModule_AddStringConstant(module, "KEY_" #x, GNT_KEY_##x)
-
-	define_key(POPUP);
-
-	define_key(LEFT);
-	define_key(RIGHT);
-	define_key(UP);
-	define_key(DOWN);
-
-	define_key(CTRL_UP);
-	define_key(CTRL_DOWN);
-	define_key(CTRL_RIGHT);
-	define_key(CTRL_LEFT);
-
-	define_key(PGUP);
-	define_key(PGDOWN);
-	define_key(HOME);
-	define_key(END);
-
-	define_key(ENTER);
-
-	define_key(BACKSPACE);
-	define_key(DEL);
-	define_key(INS);
-	define_key(BACK_TAB);
-
-	define_key(CTRL_A);
-	define_key(CTRL_B);
-	define_key(CTRL_D);
-	define_key(CTRL_E);
-	define_key(CTRL_F);
-	define_key(CTRL_G);
-	define_key(CTRL_H);
-	define_key(CTRL_I);
-	define_key(CTRL_J);
-	define_key(CTRL_K);
-	define_key(CTRL_L);
-	define_key(CTRL_M);
-	define_key(CTRL_N);
-	define_key(CTRL_O);
-	define_key(CTRL_P);
-	define_key(CTRL_R);
-	define_key(CTRL_T);
-	define_key(CTRL_U);
-	define_key(CTRL_V);
-	define_key(CTRL_W);
-	define_key(CTRL_X);
-	define_key(CTRL_Y);
-
-	define_key(F1);
-	define_key(F2);
-	define_key(F3);
-	define_key(F4);
-	define_key(F5);
-	define_key(F6);
-	define_key(F7);
-	define_key(F8);
-	define_key(F9);
-	define_key(F10);
-	define_key(F11);
-	define_key(F12);
-}
- 
-DL_EXPORT(void)
-initgnt(void)
-{
-    PyObject *m, *d;
- 
-    init_pygobject ();
-
-    m = Py_InitModule ("gnt", gnt_functions);
-    d = PyModule_GetDict (m);
- 
-    gnt_register_classes (d);
-    gnt_add_constants(m, "GNT_");
- 
-    if (PyErr_Occurred ()) {
-        Py_FatalError ("can't initialise module sad");
-    }
-
-	gnt_init();
-	gnt_add_string_constants(m);
-}
-
--- a/finch/libgnt/pygnt/gnttree.override	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/**
- * pygnt- Python bindings for the GNT toolkit.
- * Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
- *
- *   gnttree.override: overrides for the tree widget.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
- * USA
- */
-%%
-headers
-#include "common.h"
-%%
-ignore 
-gnt_tree_create_row
-gnt_tree_create_row_from_list
-%%
-override gnt_tree_get_selection_text_list noargs
-static PyObject *
-_wrap_gnt_tree_get_selection_text_list(PyGObject *self)
-{
-	GList *list = gnt_tree_get_selection_text_list(GNT_TREE(self->obj));
-	return create_pyobject_from_string_list(list);
-}
-%%
-override gnt_tree_get_rows noargs
-static PyObject *
-_wrap_gnt_tree_get_rows(PyGObject *self)
-{
-	GList *list = gnt_tree_get_rows(GNT_TREE(self->obj));
-	PyObject *py_list;
-	if (list == NULL) {
-		Py_INCREF(Py_None);
-		return Py_None;
-	}
-	if ((py_list = PyList_New(0)) == NULL) {
-		return NULL;
-	}
-	while (list) {
-		PyObject *obj = list->data;
-		PyList_Append(py_list, obj);
-		list = list->next;
-	}
-	return py_list;
-}
-%%
-override gnt_tree_add_row_after
-static PyObject *
-_wrap_gnt_tree_add_row_after(PyGObject *self, PyObject *args)
-{
-	static char *kwlist[] = {"key", "row", "parent", "bigbro", NULL};
-	PyObject *py_list;
-	gpointer key, parent, bigbro = NULL;
-	int len, i;
-	GList *list = NULL;
-	GntTreeRow *row;
-	gboolean insert_last = FALSE;
-
-	if (!PyArg_ParseTuple(args,
-				"OOO|O:GntTree.add_row_after",
-				&key,
-				&py_list,
-				&parent,
-				&bigbro))
-		return NULL;
-
-	len = PySequence_Length(py_list);
-	for (i = 0; i < len; i++) {
-		PyObject *item = PySequence_GetItem(py_list, i);
-		if (!pygobject_check(item, &PyString_Type)) {
-			PyErr_SetString(PyExc_TypeError,
-					"column_list members must be strings");
-			Py_DECREF(item);
-			return NULL;
-		}
-		list = g_list_prepend(list, PyString_AsString(item));
-		Py_DECREF(item);
-	}
-
-	if (parent == Py_None)
-		parent = NULL;
-	if (bigbro == Py_None)
-		bigbro = NULL;
-	else if (bigbro == NULL)
-		insert_last = TRUE;
-
-	Py_INCREF((PyObject*)key);
-
-	list = g_list_reverse(list);
-	row = gnt_tree_create_row_from_list(GNT_TREE(self->obj), list);
-	if (insert_last)
-		gnt_tree_add_row_last(GNT_TREE(self->obj),
-				key, row, parent);
-	else
-		gnt_tree_add_row_after(GNT_TREE(self->obj),
-				key, row,
-				parent, bigbro);
-	g_list_free(list);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-override gnt_tree_get_selection_data noargs
-static PyObject *
-_wrap_gnt_tree_get_selection_data(PyGObject *self)
-{
-	PyObject *ret = gnt_tree_get_selection_data(GNT_TREE(self->obj));
-	if (!ret)
-		ret = Py_None;
-	Py_INCREF(ret);
-	return ret;
-}
-%%
-override gnt_tree_change_text
-static PyObject *
-_wrap_gnt_tree_change_text(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = { "key", "colno", "text", NULL };
-	char *text;
-	int colno;
-	gpointer key;
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs,"Ois:GntTree.change_text", kwlist, &key, &colno, &text))
-		return NULL;
-
-	gnt_tree_change_text(GNT_TREE(self->obj), key, colno, text);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-override gnt_tree_set_row_flags
-static PyObject *
-_wrap_gnt_tree_set_row_flags(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = { "key", "flag", NULL };
-	int flag;
-	gpointer key;
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs,"Oi:GntTree.set_row_flags", kwlist, &key, &flag))
-		return NULL;
-
-	gnt_tree_set_row_flags(GNT_TREE(self->obj), key, flag);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-override gnt_tree_remove
-static PyObject *
-_wrap_gnt_tree_remove(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = { "key", NULL };
-	gpointer key;
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs,"O:GntTree.remove", kwlist, &key))
-		return NULL;
-
-	gnt_tree_remove(GNT_TREE(self->obj), key);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-override gnt_tree_set_selected
-static PyObject *
-_wrap_gnt_tree_set_selected(PyGObject *self, PyObject *args)
-{
-	gpointer key;
-	if (!PyArg_ParseTuple(args, "O:GntTree.set_selected", &key)) {
-		return NULL;
-	}
-	gnt_tree_set_selected(GNT_TREE(self->obj), key);
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-%%
-override gnt_tree_set_compare_func
-static PyObject *
-_wrap_gnt_tree_set_compare_func(PyGObject *self, PyObject *args)
-{
-	static char *kwlist[] = {"compare_func", NULL};
-	PyGObject *compare;
-
-	if (!PyArg_ParseTuple(args, "O:GntTree.set_compare_func", &compare)) {
-		return NULL;
-	}
-
-	if (!PyCallable_Check(compare)) {
-		PyErr_SetString(PyExc_TypeError, "the callback must be callable ... doh!");
-		return NULL;
-	}
-
-	Py_INCREF(compare);
-	gnt_tree_set_compare_func(GNT_TREE(self->obj), (GCompareFunc)compare->obj);
-
-	Py_INCREF(Py_None);
-	return Py_None;
-}
-
--- a/finch/libgnt/pygnt/gntwidget.override	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/**
- * pygnt- Python bindings for the GNT toolkit.
- * Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
- *
- *   gntwidget.override: overrides for generic widgets.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301
- * USA
- */
-%%
-override gnt_widget_get_size args
-static PyObject *
-_wrap_gnt_widget_get_size(PyGObject *self)
-{
-    PyObject *list = PyList_New(0);
-    int x = 0, y = 0;
-
-    gnt_widget_get_size(GNT_WIDGET(self->obj), &x, &y);
-    PyList_Append(list, PyInt_FromLong((long)x));
-    PyList_Append(list, PyInt_FromLong((long)y));
-
-    return list;
-}
-
--- a/finch/libgnt/pygnt/test.py	Sat Apr 19 21:57:17 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-#!/usr/bin/env python
-import gobject
-import gnt
-
-class MyObject(gobject.GObject):
-    __gproperties__ = {
-        'mytype': (gobject.TYPE_INT, 'mytype', 'the type of the object',
-                0, 10000, 0, gobject.PARAM_READWRITE),
-        'string': (gobject.TYPE_STRING, 'string property', 'the string',
-                None, gobject.PARAM_READWRITE),
-        'gobject': (gobject.TYPE_OBJECT, 'object property', 'the object',
-                gobject.PARAM_READWRITE),
-    }
-
-    def __init__(self, type = 'string', value = None):
-        self.__gobject_init__()
-        self.set_property(type, value)
-
-    def __del__(self):
-        pass
-
-    def do_set_property(self, pspec, value):
-        if pspec.name == 'string':
-            self.string = value
-            self.type = gobject.TYPE_STRING
-        elif pspec.name == 'gobject':
-            self.gobject = value
-            self.type = gobject.TYPE_OBJECT
-        else:
-            raise AttributeError, 'unknown property %s' % pspec.name
-    def do_get_property(self, pspec):
-        if pspec.name == 'string':
-            return self.string
-        elif pspec.name == 'gobject':
-            return self.gobject
-        elif pspec.name == 'mytype':
-            return self.type
-        else:
-            raise AttributeError, 'unknown property %s' % pspec.name
-gobject.type_register(MyObject)
-
-def button_activate(button, tree):
-    list = tree.get_selection_text_list()
-    ent = tree.get_selection_data()
-    if ent.type == gobject.TYPE_STRING:
-        str = ""
-        for i in list:
-            str = str + i
-        entry.set_text("clicked!!!" + str)
-    elif ent.type == gobject.TYPE_OBJECT:
-        ent.gobject.set_text("mwhahaha!!!")
-
-gnt.gnt_init()
-
-win = gnt.Window()
-
-entry = gnt.Entry("")
-obj = MyObject()
-obj.set_property('gobject', entry)
-
-win.add_widget(entry)
-win.set_title("Entry")
-
-button = gnt.Button("Click!")
-win.add_widget(button)
-
-tree = gnt.Tree()
-tree.set_property("columns", 1)
-win.add_widget(tree)
-
-# so random non-string values can be used as the key for a row in a GntTree!
-last = None
-for i in range(1, 100):
-    key = MyObject('string', str(i))
-    tree.add_row_after(key, [str(i)], None, last)
-    last = key
-
-tree.add_row_after(MyObject('gobject', entry), ["asd"], None, None)
-tree.add_row_after(MyObject('string', "b"), ["123"], MyObject('gobject', entry), None)
-
-button.connect("activate", button_activate, tree)
-
-tv = gnt.TextView()
-
-win.add_widget(tv)
-tv.append_text_with_flags("What up!!", gnt.TEXT_FLAG_BOLD)
-
-win.show()
-
-gnt.gnt_main()
-
-gnt.gnt_quit()
-
--- a/libpurple/account.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/account.c	Mon Apr 28 19:24:18 2008 +0000
@@ -1359,8 +1359,12 @@
 		return;
 	}
 
-	if (orig_pass == NULL || new_pass_1 == NULL || new_pass_2 == NULL ||
-		*orig_pass == '\0' || *new_pass_1 == '\0' || *new_pass_2 == '\0')
+	if ((purple_request_fields_is_field_required(fields, "password") &&
+			(orig_pass == NULL || *orig_pass == '\0')) ||
+		(purple_request_fields_is_field_required(fields, "new_password_1") &&
+			(new_pass_1 == NULL || *new_pass_1 == '\0')) ||
+		(purple_request_fields_is_field_required(fields, "new_password_2") &&
+			(new_pass_2 == NULL || *new_pass_2 == '\0')))
 	{
 		purple_notify_error(account, NULL,
 						  _("Fill out all fields completely."), NULL);
@@ -1376,11 +1380,20 @@
 	PurpleRequestFields *fields;
 	PurpleRequestFieldGroup *group;
 	PurpleRequestField *field;
+	PurpleConnection *gc;
+	PurplePlugin *prpl = NULL;
+	PurplePluginProtocolInfo *prpl_info = NULL;
 	char primary[256];
 
 	g_return_if_fail(account != NULL);
 	g_return_if_fail(purple_account_is_connected(account));
 
+	gc = purple_account_get_connection(account);
+	if (gc != NULL)
+		prpl = purple_connection_get_prpl(gc);
+	if (prpl != NULL)
+		prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
 	fields = purple_request_fields_new();
 
 	group = purple_request_field_group_new(NULL);
@@ -1389,21 +1402,24 @@
 	field = purple_request_field_string_new("password", _("Original password"),
 										  NULL, FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_set_required(field, TRUE);
+	if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
+		purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	field = purple_request_field_string_new("new_password_1",
 										  _("New password"),
 										  NULL, FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_set_required(field, TRUE);
+	if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
+		purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	field = purple_request_field_string_new("new_password_2",
 										  _("New password (again)"),
 										  NULL, FALSE);
 	purple_request_field_string_set_masked(field, TRUE);
-	purple_request_field_set_required(field, TRUE);
+	if (!(prpl_info && (prpl_info->options | OPT_PROTO_PASSWORD_OPTIONAL)))
+		purple_request_field_set_required(field, TRUE);
 	purple_request_field_group_add_field(group, field);
 
 	g_snprintf(primary, sizeof(primary), _("Change password for %s"),
--- a/libpurple/blist.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/blist.c	Mon Apr 28 19:24:18 2008 +0000
@@ -2238,6 +2238,8 @@
 				pce = parts->data;
 				chat_name = g_hash_table_lookup(chat->components,
 												pce->identifier);
+				g_list_foreach(parts, (GFunc)g_free, NULL);
+				g_list_free(parts);
 
 				if (chat->account == account && chat_name != NULL &&
 					name != NULL && !strcmp(chat_name, name)) {
--- a/libpurple/core.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/core.c	Mon Apr 28 19:24:18 2008 +0000
@@ -323,25 +323,6 @@
 	return remote_user_dir;
 }
 
-static void purple_dbus_owner_show_buddy_list(void)
-{
-	DBusError dbus_error;
-	DBusMessage *msg = NULL, *reply = NULL;
-	DBusConnection *dbus_connection = NULL;
-
-	if ((dbus_connection = purple_dbus_get_connection()) == NULL)
-		return;
-
-	if ((msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleBlistShow")) == NULL)
-		return;
-
-	dbus_error_init(&dbus_error);
-	if ((reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 5000, &dbus_error)) != NULL)
-	{
-		dbus_message_unref(msg);
-	}
-	dbus_error_free(&dbus_error);
-}
 #endif /* HAVE_DBUS */
 
 gboolean
@@ -366,9 +347,6 @@
 			else
 				is_single_instance = strcmp(dbus_owner_user_dir, user_dir);
 
-			if (!is_single_instance)
-				purple_dbus_owner_show_buddy_list();
-
 			g_free(dbus_owner_user_dir);
 		}
 	}
--- a/libpurple/dbus-server.h	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/dbus-server.h	Mon Apr 28 19:24:18 2008 +0000
@@ -28,9 +28,9 @@
 #ifndef _PURPLE_DBUS_SERVER_H_
 #define _PURPLE_DBUS_SERVER_H_
 
+#include "dbus-purple.h"
 #include "value.h"
 
-
 G_BEGIN_DECLS
 
 /**
@@ -51,6 +51,8 @@
     PurpleDBusType *parent;
 };
 
+#include "dbus-bindings.h"
+
 /* By convention, the PurpleDBusType variable representing each structure
    PurpleSomeStructure has the name PURPLE_DBUS_TYPE_PurpleSomeStructure.
    The following macros facilitate defining such variables
--- a/libpurple/log.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/log.c	Mon Apr 28 19:24:18 2008 +0000
@@ -1758,6 +1758,7 @@
 			lastoff = offset;
 
 			g_snprintf(convostart, length, "%s", temp);
+			memset(&tm, 0, sizeof(tm));
 			sscanf(convostart, "%*s %s %d %d:%d:%d %d",
 			       month, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &tm.tm_year);
 			/* Ugly hack, in case current locale is not English */
--- a/libpurple/plugin.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugin.c	Mon Apr 28 19:24:18 2008 +0000
@@ -1212,7 +1212,7 @@
 	if (g_list_find_custom(search_paths, path, (GCompareFunc)strcmp))
 		return;
 
-	search_paths = g_list_append(search_paths, strdup(path));
+	search_paths = g_list_append(search_paths, g_strdup(path));
 }
 
 void
@@ -1294,7 +1294,7 @@
 
 		/* Strip the extension */
 		if (basename)
-			basename = purple_plugin_get_basename(filename);
+			basename = purple_plugin_get_basename(basename);
 
 		if (((plugin = purple_plugins_find_with_filename(filename)) != NULL) ||
 				(basename && (plugin = purple_plugins_find_with_basename(basename)) != NULL) ||
--- a/libpurple/plugins/perl/Makefile.am	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/Makefile.am	Mon Apr 28 19:24:18 2008 +0000
@@ -90,7 +90,9 @@
 common/Makefile: common/Makefile.PL
 	@if test "x${top_srcdir}" != "x${top_builddir}"; then \
 		for f in ${common_sources}; do \
-			${LN_S} -f ../${srcdir}/$$f $$f; \
+			srcloc=${srcdir}; \
+			case $$srcloc in /*) ;; *) srcloc=../${srcdir} ;; esac; \
+			${LN_S} -f $$srcloc/$$f $$f; \
 		done; \
 	fi
 	@cd common && $(perlpath) Makefile.PL $(PERL_MM_PARAMS)
@@ -148,7 +150,9 @@
 
 	@if test "x${top_srcdir}" != "x${top_builddir}"; then \
 		for f in ${common_sources}; do \
-			${LN_S} -f ../${srcdir}/$$f $$f; \
+			srcloc=${srcdir}; \
+			case $$srcloc in /*) ;; *) srcloc=../${srcdir} ;; esac; \
+			${LN_S} -f $$srcloc/$$f $$f; \
 		done; \
 	fi
 
--- a/libpurple/plugins/perl/common/Notify.xs	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/common/Notify.xs	Mon Apr 28 19:24:18 2008 +0000
@@ -172,10 +172,10 @@
 void purple_notify_user_info_remove_last_item(user_info)
 	Purple::NotifyUserInfo user_info
 
-gchar *
+const gchar *
 purple_notify_user_info_entry_get_label(user_info_entry)
 	Purple::NotifyUserInfoEntry user_info_entry
 
-gchar *
+const gchar *
 purple_notify_user_info_entry_get_value(user_info_entry)
 	Purple::NotifyUserInfoEntry user_info_entry
--- a/libpurple/plugins/perl/common/Prefs.xs	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/common/Prefs.xs	Mon Apr 28 19:24:18 2008 +0000
@@ -167,6 +167,17 @@
 	const char *name
 
 void
+purple_prefs_get_children_names(name)
+	const char *name
+PREINIT:
+	GList *l;
+PPCODE:
+	for (l = purple_prefs_get_children_names(name); l != NULL; l = g_list_delete_link(l, l)) {
+		XPUSHs(sv_2mortal(newSVpv(l->data, 0)));
+		g_free(l->data);
+	}
+
+void
 purple_prefs_uninit()
 
 void
--- a/libpurple/plugins/perl/common/Purple.xs	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/common/Purple.xs	Mon Apr 28 19:24:18 2008 +0000
@@ -74,14 +74,24 @@
 	PURPLE_PERL_BOOT(Util);
 	PURPLE_PERL_BOOT(XMLNode);
 
-void
+guint
 timeout_add(plugin, seconds, callback, data = 0)
 	Purple::Plugin plugin
 	int seconds
 	SV *callback
 	SV *data
 CODE:
-	purple_perl_timeout_add(plugin, seconds, callback, data);
+	RETVAL = purple_perl_timeout_add(plugin, seconds, callback, data);
+OUTPUT:
+	RETVAL
+
+gboolean
+timeout_remove(handle)
+	guint handle
+CODE:
+	RETVAL = purple_perl_timeout_remove(handle);
+OUTPUT:
+	RETVAL
 
 void
 deinit()
--- a/libpurple/plugins/perl/common/Request.xs	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/common/Request.xs	Mon Apr 28 19:24:18 2008 +0000
@@ -15,10 +15,20 @@
 
 
 typedef struct {
-	char *cancel_cb;
-	char *ok_cb;
+	SV *ok_fun;
+	SV *cancel_fun;
 } PurplePerlRequestData;
 
+static void
+purple_perl_request_data_free(PurplePerlRequestData *ppr)
+{
+	if (ppr->ok_fun)
+		SvREFCNT_dec(ppr->ok_fun);
+	if (ppr->cancel_fun)
+		SvREFCNT_dec(ppr->cancel_fun);
+	g_free(ppr);
+}
+
 /********************************************************/
 /*                                                      */
 /* Callback function that calls a perl subroutine       */
@@ -39,23 +49,19 @@
 
 	XPUSHs(purple_perl_bless_object(fields, "Purple::Request::Fields"));
 	PUTBACK;
-
-	call_pv(gpr->ok_cb, G_EVAL | G_SCALAR);
+	call_sv(gpr->ok_fun, G_EVAL | G_SCALAR);
 	SPAGAIN;
 
 	PUTBACK;
 	FREETMPS;
 	LEAVE;
 
-	g_free(gpr->ok_cb);
-	g_free(gpr->cancel_cb);
-	g_free(gpr);
+	purple_perl_request_data_free(gpr);
 }
 
 static void
 purple_perl_request_cancel_cb(void * data, PurpleRequestFields *fields)
 {
-
 	PurplePerlRequestData *gpr = (PurplePerlRequestData *)data;
 
 	dSP;
@@ -65,16 +71,14 @@
 
 	XPUSHs(purple_perl_bless_object(fields, "Purple::Request::Fields"));
 	PUTBACK;
-	call_pv(gpr->cancel_cb, G_EVAL | G_SCALAR);
+	call_sv(gpr->cancel_fun, G_EVAL | G_SCALAR);
 	SPAGAIN;
 
 	PUTBACK;
 	FREETMPS;
 	LEAVE;
 
-	g_free(gpr->ok_cb);
-	g_free(gpr->cancel_cb);
-	g_free(gpr);
+	purple_perl_request_data_free(gpr);
 }
 
 MODULE = Purple::Request  PACKAGE = Purple::Request  PREFIX = purple_request_
@@ -131,14 +135,13 @@
 	SV * cancel_cb
 CODE:
 	PurplePerlRequestData *gpr;
-	STRLEN len;
 	char *basename;
 
 	basename = g_path_get_basename(handle->path);
 	purple_perl_normalize_script_name(basename);
 	gpr = g_new(PurplePerlRequestData, 1);
-	gpr->ok_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(ok_cb, len));
-	gpr->cancel_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(cancel_cb, len));
+	gpr->ok_fun = purple_perl_sv_from_fun(handle, ok_cb);
+	gpr->cancel_fun = purple_perl_sv_from_fun(handle, cancel_cb);
 	g_free(basename);
 
 	RETVAL = purple_request_input(handle, title, primary, secondary, default_value, multiline, masked, hint, ok_text, G_CALLBACK(purple_perl_request_ok_cb), cancel_text, G_CALLBACK(purple_perl_request_cancel_cb), NULL, NULL, NULL, gpr);
@@ -155,14 +158,13 @@
 	SV * cancel_cb
 CODE:
 	PurplePerlRequestData *gpr;
-	STRLEN len;
 	char *basename;
 
 	basename = g_path_get_basename(handle->path);
 	purple_perl_normalize_script_name(basename);
 	gpr = g_new(PurplePerlRequestData, 1);
-	gpr->ok_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(ok_cb, len));
-	gpr->cancel_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(cancel_cb, len));
+	gpr->ok_fun = purple_perl_sv_from_fun(handle, ok_cb);
+	gpr->cancel_fun = purple_perl_sv_from_fun(handle, cancel_cb);
 	g_free(basename);
 
 	RETVAL = purple_request_file(handle, title, filename, savedialog, G_CALLBACK(purple_perl_request_ok_cb), G_CALLBACK(purple_perl_request_cancel_cb), NULL, NULL, NULL, gpr);
@@ -182,14 +184,13 @@
 	SV * cancel_cb
 CODE:
 	PurplePerlRequestData *gpr;
-	STRLEN len;
 	char *basename;
 
 	basename = g_path_get_basename(handle->path);
 	purple_perl_normalize_script_name(basename);
 	gpr = g_new(PurplePerlRequestData, 1);
-	gpr->ok_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(ok_cb, len));
-	gpr->cancel_cb = g_strdup_printf("Purple::Script::%s::%s", basename, SvPV(cancel_cb, len));
+	gpr->ok_fun = purple_perl_sv_from_fun(handle, ok_cb);
+	gpr->cancel_fun = purple_perl_sv_from_fun(handle, cancel_cb);
 	g_free(basename);
 
 	RETVAL = purple_request_fields(handle, title, primary, secondary, fields, ok_text, G_CALLBACK(purple_perl_request_ok_cb), cancel_text, G_CALLBACK(purple_perl_request_cancel_cb), NULL, NULL, NULL, gpr);
--- a/libpurple/plugins/perl/common/Util.xs	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/common/Util.xs	Mon Apr 28 19:24:18 2008 +0000
@@ -257,29 +257,13 @@
 	gboolean http11
 	SV * cb
 CODE:
-	SV *sv = NULL;
-
-
-	if (SvTYPE(cb) == SVt_RV) {
-		SV *cbsv = SvRV(cb);
-
-		if (SvTYPE(cbsv) == SVt_PVCV) {
-			sv = newSVsv(cb);
-		} else {
-			purple_debug_warning("perl", "Callback not a valid coderef in purple_util_fetch_url.\n");
-		}
-	} else if (SvTYPE(cb) == SVt_PV) {
-		PurplePerlScript *gps;
-
-		gps = (PurplePerlScript *)PURPLE_PLUGIN_LOADER_INFO(plugin);
-		sv = newSVpvf("%s::%s", gps->package, SvPV_nolen(cb));
-	} else {
-		purple_debug_warning("perl", "Callback not a valid type, only strings and coderefs allowed in purple_util_fetch_url.\n");
-	}
+	SV *sv = purple_perl_sv_from_fun(plugin, cb);
 
 	if (sv != NULL) {
 		purple_util_fetch_url(url, full, user_agent, http11,
 		                      purple_perl_util_url_cb, sv);
+	} else {
+		purple_debug_warning("perl", "Callback not a valid type, only strings and coderefs allowed in purple_util_fetch_url.\n");
 	}
 
 void
--- a/libpurple/plugins/perl/perl-common.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.c	Mon Apr 28 19:24:18 2008 +0000
@@ -616,3 +616,26 @@
 
 	return NULL;
 }
+
+SV *purple_perl_sv_from_fun(PurplePlugin *plugin, SV *callback)
+{
+	SV *sv = NULL;
+
+	if (SvTYPE(callback) == SVt_RV) {
+		SV *cbsv = SvRV(callback);
+
+		if (SvTYPE(cbsv) == SVt_PVCV) {
+			sv = newSVsv(callback);
+		}
+	} else if (SvTYPE(callback) == SVt_PV) {
+		PurplePerlScript *gps;
+
+		gps = (PurplePerlScript *)PURPLE_PLUGIN_LOADER_INFO(plugin);
+		sv = newSVpvf("%s::%s", gps->package, SvPV_nolen(callback));
+	} else {
+		purple_debug_warning("perl", "Callback not a valid type, only strings and coderefs allowed.\n");
+	}
+
+	return sv;
+}
+
--- a/libpurple/plugins/perl/perl-common.h	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/perl-common.h	Mon Apr 28 19:24:18 2008 +0000
@@ -67,5 +67,5 @@
 void *purple_perl_data_from_sv(PurpleValue *value, SV *sv);
 SV *purple_perl_sv_from_vargs(const PurpleValue *value, va_list *args,
                             void ***copy_arg);
-
+SV *purple_perl_sv_from_fun(PurplePlugin *plugin, SV *callback);
 #endif /* _PURPLE_PERL_COMMON_H_ */
--- a/libpurple/plugins/perl/perl-handlers.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/perl-handlers.c	Mon Apr 28 19:24:18 2008 +0000
@@ -207,13 +207,15 @@
 	return ret_frame;
 }
 
-static void
+static gboolean
 destroy_timeout_handler(PurplePerlTimeoutHandler *handler)
 {
+	gboolean ret = FALSE;
+
 	timeout_handlers = g_list_remove(timeout_handlers, handler);
 
 	if (handler->iotag > 0)
-		purple_timeout_remove(handler->iotag);
+		ret = purple_timeout_remove(handler->iotag);
 
 	if (handler->callback != NULL)
 		SvREFCNT_dec(handler->callback);
@@ -222,6 +224,8 @@
 		SvREFCNT_dec(handler->data);
 
 	g_free(handler);
+
+	return ret;
 }
 
 static void
@@ -301,8 +305,8 @@
 
 	for (i = 0; i < value_count; i++) {
 		sv_args[i] = purple_perl_sv_from_vargs(values[i],
-		                                     (va_list*)&args,
-		                                     &copy_args[i]);
+		                                       (va_list*)&args,
+		                                       &copy_args[i]);
 
 		XPUSHs(sv_args[i]);
 	}
@@ -422,14 +426,14 @@
 	return NULL;
 }
 
-void
+guint
 purple_perl_timeout_add(PurplePlugin *plugin, int seconds, SV *callback, SV *data)
 {
 	PurplePerlTimeoutHandler *handler;
 
 	if (plugin == NULL) {
 		croak("Invalid handle in adding perl timeout handler.\n");
-		return;
+		return 0;
 	}
 
 	handler = g_new0(PurplePerlTimeoutHandler, 1);
@@ -443,15 +447,39 @@
 	timeout_handlers = g_list_append(timeout_handlers, handler);
 
 	handler->iotag = purple_timeout_add(seconds * 1000, perl_timeout_cb, handler);
+
+	return handler->iotag;
+}
+
+gboolean
+purple_perl_timeout_remove(guint handle)
+{
+	GList *l, *l_next;
+
+	for (l = timeout_handlers; l != NULL; l = l_next) {
+		PurplePerlTimeoutHandler *handler;
+
+		l_next = l->next;
+
+		handler = (PurplePerlTimeoutHandler *)l->data;
+
+		if (handler->iotag == handle)
+			return destroy_timeout_handler(handler);
+	}
+
+	purple_debug_info("perl", "No timeout handler found with handle %u.\n",
+	                  handle);
+	return FALSE;
 }
 
 void
 purple_perl_timeout_clear_for_plugin(PurplePlugin *plugin)
 {
-	PurplePerlTimeoutHandler *handler;
 	GList *l, *l_next;
 
 	for (l = timeout_handlers; l != NULL; l = l_next) {
+		PurplePerlTimeoutHandler *handler;
+
 		l_next = l->next;
 
 		handler = (PurplePerlTimeoutHandler *)l->data;
--- a/libpurple/plugins/perl/perl-handlers.h	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/perl/perl-handlers.h	Mon Apr 28 19:24:18 2008 +0000
@@ -48,8 +48,9 @@
 GtkWidget *purple_perl_gtk_get_plugin_frame(PurplePlugin *plugin);
 #endif
 
-void purple_perl_timeout_add(PurplePlugin *plugin, int seconds, SV *callback,
-                           SV *data);
+guint purple_perl_timeout_add(PurplePlugin *plugin, int seconds, SV *callback,
+                              SV *data);
+gboolean purple_perl_timeout_remove(guint handle);
 void purple_perl_timeout_clear_for_plugin(PurplePlugin *plugin);
 void purple_perl_timeout_clear(void);
 
--- a/libpurple/plugins/statenotify.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/plugins/statenotify.c	Mon Apr 28 19:24:18 2008 +0000
@@ -42,6 +42,10 @@
 {
 	gboolean available, old_available;
 
+	if (!purple_status_is_exclusive(status) ||
+			!purple_status_is_exclusive(old_status))
+		return;
+
 	available = purple_status_is_available(status);
 	old_available = purple_status_is_available(old_status);
 
--- a/libpurple/protocols/irc/msgs.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/irc/msgs.c	Mon Apr 28 19:24:18 2008 +0000
@@ -706,16 +706,16 @@
 void irc_msg_invite(struct irc_conn *irc, const char *name, const char *from, char **args)
 {
 	PurpleConnection *gc = purple_account_get_connection(irc->account);
-	GHashTable *components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-	char *nick = irc_mask_nick(from);
+	GHashTable *components;
+	gchar *nick;
 
-	if (!args || !args[1] || !gc) {
-		g_free(nick);
-		g_hash_table_destroy(components);
+	if (!args || !args[1] || !gc)
 		return;
-	}
 
-	g_hash_table_insert(components, strdup("channel"), strdup(args[1]));
+	components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	nick = irc_mask_nick(from);
+
+	g_hash_table_insert(components, g_strdup("channel"), g_strdup(args[1]));
 
 	serv_got_chat_invite(gc, args[1], nick, NULL, components);
 	g_free(nick);
@@ -980,7 +980,7 @@
 	if (!args || !args[1])
 		return;
 
-	newnick = strdup(args[1]);
+	newnick = g_strdup(args[1]);
 	end = newnick + strlen(newnick) - 1;
 	/* try fallbacks */
 	if((*end < '9') && (*end >= '1')) {
--- a/libpurple/protocols/jabber/chat.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/jabber/chat.c	Mon Apr 28 19:24:18 2008 +0000
@@ -238,6 +238,8 @@
 		char *buf = g_strdup_printf(_("%s is not a valid room handle"), handle);
 		purple_notify_error(gc, _("Invalid Room Handle"),
 				_("Invalid Room Handle"), buf);
+		g_free(buf);
+		return;
 	}
 
 	if(jabber_chat_find(js, room, server))
--- a/libpurple/protocols/msnp9/nexus.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/msnp9/nexus.c	Mon Apr 28 19:24:18 2008 +0000
@@ -337,7 +337,8 @@
 	username =
 		g_strdup(purple_url_encode(purple_account_get_username(session->account)));
 
-	password = g_strndup(purple_connection_get_password(session->account->gc), 16);
+	password = g_utf8_strncpy(g_strdup(purple_connection_get_password(session->account->gc)),
+							  purple_connection_get_password(session->account->gc), 16);
 	encpass = g_strdup(purple_url_encode(password));
 	g_free(password);
 
--- a/libpurple/protocols/msnp9/slplink.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/msnp9/slplink.c	Mon Apr 28 19:24:18 2008 +0000
@@ -118,6 +118,8 @@
 	while (slplink->slp_calls != NULL)
 		msn_slp_call_destroy(slplink->slp_calls->data);
 
+	g_queue_free(slplink->slp_msg_queue);
+
 	session->slplinks =
 		g_list_remove(session->slplinks, slplink);
 
--- a/libpurple/protocols/msnp9/switchboard.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/msnp9/switchboard.c	Mon Apr 28 19:24:18 2008 +0000
@@ -111,6 +111,9 @@
 	for (l = swboard->users; l != NULL; l = l->next)
 		g_free(l->data);
 
+	if (swboard->users != NULL)
+		g_list_free(swboard->users);
+
 	session = swboard->session;
 	session->switches = g_list_remove(session->switches, swboard);
 
--- a/libpurple/protocols/oscar/bstream.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/bstream.c	Mon Apr 28 19:24:18 2008 +0000
@@ -45,6 +45,11 @@
 	return 0;
 }
 
+void byte_stream_destroy(ByteStream *bs)
+{
+	g_free(bs->data);
+}
+
 int byte_stream_empty(ByteStream *bs)
 {
 	return bs->len - bs->offset;
--- a/libpurple/protocols/oscar/family_admin.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_admin.c	Mon Apr 28 19:24:18 2008 +0000
@@ -40,18 +40,18 @@
 int
 aim_admin_getinfo(OscarData *od, FlapConnection *conn, guint16 info)
 {
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
-	fr = flap_frame_new(od, 0x02, 14);
+	byte_stream_new(&bs, 4);
 
-	snacid = aim_cachesnac(od, 0x0007, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0007, 0x0002, 0x0000, snacid);
+	byte_stream_put16(&bs, info);
+	byte_stream_put16(&bs, 0x0000);
 
-	byte_stream_put16(&fr->data, info);
-	byte_stream_put16(&fr->data, 0x0000);
+	snacid = aim_cachesnac(od, 0x0007, 0x0002, 0x0000, NULL, 0);	
+	flap_connection_send_snac(od, conn, 0x0007, 0x0002, 0x0000, snacid, &bs);	
 
-	flap_connection_send(conn, fr);
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -120,25 +120,28 @@
  * Subtype 0x0004 - Set screenname formatting.
  *
  */
+/*
+ * Subtype 0x0004 - Set screenname formatting.
+ *
+ */
 int
 aim_admin_setnick(OscarData *od, FlapConnection *conn, const char *newnick)
 {
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
-	fr = flap_frame_new(od, 0x02, 10+2+2+strlen(newnick));
-
-	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
+	byte_stream_new(&bs, 2+2+strlen(newnick));
 
 	aim_tlvlist_add_str(&tlvlist, 0x0001, newnick);
 
-	aim_tlvlist_write(&fr->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, fr);
+	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0007, 0x0004, 0x0000, snacid, &bs);
 
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -150,14 +153,11 @@
 int
 aim_admin_changepasswd(OscarData *od, FlapConnection *conn, const char *newpw, const char *curpw)
 {
-	FlapFrame *fr;
+	ByteStream bs;
 	GSList *tlvlist = NULL;
 	aim_snacid_t snacid;
 
-	fr = flap_frame_new(od, 0x02, 10+4+strlen(curpw)+4+strlen(newpw));
-
-	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
+	byte_stream_new(&bs, 4+strlen(curpw)+4+strlen(newpw));
 
 	/* new password TLV t(0002) */
 	aim_tlvlist_add_str(&tlvlist, 0x0002, newpw);
@@ -165,10 +165,11 @@
 	/* current password TLV t(0012) */
 	aim_tlvlist_add_str(&tlvlist, 0x0012, curpw);
 
-	aim_tlvlist_write(&fr->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, fr);
+	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0007, 0x0004, 0x0000, snacid, &bs);
 
 	return 0;
 }
@@ -180,21 +181,21 @@
 int
 aim_admin_setemail(OscarData *od, FlapConnection *conn, const char *newemail)
 {
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
-	fr = flap_frame_new(od, 0x02, 10+2+2+strlen(newemail));
-
-	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0007, 0x0004, 0x0000, snacid);
+	byte_stream_new(&bs, 2+2+strlen(newemail));
 
 	aim_tlvlist_add_str(&tlvlist, 0x0011, newemail);
 
-	aim_tlvlist_write(&fr->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, fr);
+	snacid = aim_cachesnac(od, 0x0007, 0x0004, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0007, 0x0004, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_alert.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_alert.c	Mon Apr 28 19:24:18 2008 +0000
@@ -41,40 +41,41 @@
 aim_email_sendcookies(OscarData *od)
 {
 	FlapConnection *conn;
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ALERT)))
 		return -EINVAL;
 
-	fr = flap_frame_new(od, 0x02, 10+2+16+16);
-	snacid = aim_cachesnac(od, 0x0018, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0018, 0x0006, 0x0000, snacid);
+	byte_stream_new(&bs, 2+16+16);
 
 	/* Number of cookies to follow */
-	byte_stream_put16(&fr->data, 0x0002);
+	byte_stream_put16(&bs, 0x0002);
 
 	/* Cookie */
-	byte_stream_put16(&fr->data, 0x5d5e);
-	byte_stream_put16(&fr->data, 0x1708);
-	byte_stream_put16(&fr->data, 0x55aa);
-	byte_stream_put16(&fr->data, 0x11d3);
-	byte_stream_put16(&fr->data, 0xb143);
-	byte_stream_put16(&fr->data, 0x0060);
-	byte_stream_put16(&fr->data, 0xb0fb);
-	byte_stream_put16(&fr->data, 0x1ecb);
+	byte_stream_put16(&bs, 0x5d5e);
+	byte_stream_put16(&bs, 0x1708);
+	byte_stream_put16(&bs, 0x55aa);
+	byte_stream_put16(&bs, 0x11d3);
+	byte_stream_put16(&bs, 0xb143);
+	byte_stream_put16(&bs, 0x0060);
+	byte_stream_put16(&bs, 0xb0fb);
+	byte_stream_put16(&bs, 0x1ecb);
 
 	/* Cookie */
-	byte_stream_put16(&fr->data, 0xb380);
-	byte_stream_put16(&fr->data, 0x9ad8);
-	byte_stream_put16(&fr->data, 0x0dba);
-	byte_stream_put16(&fr->data, 0x11d5);
-	byte_stream_put16(&fr->data, 0x9f8a);
-	byte_stream_put16(&fr->data, 0x0060);
-	byte_stream_put16(&fr->data, 0xb0ee);
-	byte_stream_put16(&fr->data, 0x0631);
+	byte_stream_put16(&bs, 0xb380);
+	byte_stream_put16(&bs, 0x9ad8);
+	byte_stream_put16(&bs, 0x0dba);
+	byte_stream_put16(&bs, 0x11d5);
+	byte_stream_put16(&bs, 0x9f8a);
+	byte_stream_put16(&bs, 0x0060);
+	byte_stream_put16(&bs, 0xb0ee);
+	byte_stream_put16(&bs, 0x0631);
 
-	flap_connection_send(conn, fr);
+	snacid = aim_cachesnac(od, 0x0018, 0x0006, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0018, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -171,25 +172,26 @@
 aim_email_activate(OscarData *od)
 {
 	FlapConnection *conn;
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_ALERT)))
 		return -EINVAL;
 
-	fr = flap_frame_new(od, 0x02, 10+1+16);
-	snacid = aim_cachesnac(od, 0x0018, 0x0016, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0018, 0x0016, 0x0000, snacid);
+	byte_stream_new(&bs, 1+16);
 
 	/* I would guess this tells AIM that you want updates for your mail accounts */
 	/* ...but I really have no idea */
-	byte_stream_put8(&fr->data, 0x02);
-	byte_stream_put32(&fr->data, 0x04000000);
-	byte_stream_put32(&fr->data, 0x04000000);
-	byte_stream_put32(&fr->data, 0x04000000);
-	byte_stream_put32(&fr->data, 0x00000000);
+	byte_stream_put8(&bs, 0x02);
+	byte_stream_put32(&bs, 0x04000000);
+	byte_stream_put32(&bs, 0x04000000);
+	byte_stream_put32(&bs, 0x04000000);
+	byte_stream_put32(&bs, 0x00000000);
 
-	flap_connection_send(conn, fr);
+	snacid = aim_cachesnac(od, 0x0018, 0x0016, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0018, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_bart.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_bart.c	Mon Apr 28 19:24:18 2008 +0000
@@ -40,25 +40,26 @@
 aim_bart_upload(OscarData *od, const guint8 *icon, guint16 iconlen)
 {
 	FlapConnection *conn;
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0010)) || !icon || !iconlen)
 		return -EINVAL;
 
-	fr = flap_frame_new(od, 0x02, 10 + 2 + 2+iconlen);
-	snacid = aim_cachesnac(od, 0x0010, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0010, 0x0002, 0x0000, snacid);
+	byte_stream_new(&bs, 2 + 2 + iconlen);
 
 	/* The reference number for the icon */
-	byte_stream_put16(&fr->data, 1);
+	byte_stream_put16(&bs, 1);
 
 	/* The icon */
-	byte_stream_put16(&fr->data, iconlen);
-	byte_stream_putraw(&fr->data, icon, iconlen);
+	byte_stream_put16(&bs, iconlen);
+	byte_stream_putraw(&bs, icon, iconlen);
 
-	flap_connection_send(conn, fr);
-
+	snacid = aim_cachesnac(od, 0x0010, 0x0002, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0010, 0x0002, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -98,30 +99,31 @@
 aim_bart_request(OscarData *od, const char *sn, guint8 iconcsumtype, const guint8 *iconcsum, guint16 iconcsumlen)
 {
 	FlapConnection *conn;
-	FlapFrame *fr;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0010)) || !sn || !strlen(sn) || !iconcsum || !iconcsumlen)
 		return -EINVAL;
 
-	fr = flap_frame_new(od, 0x02, 10 + 1+strlen(sn) + 4 + 1+iconcsumlen);
-	snacid = aim_cachesnac(od, 0x0010, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&fr->data, 0x0010, 0x0004, 0x0000, snacid);
+	byte_stream_new(&bs, 1+strlen(sn) + 4 + 1+iconcsumlen);
 
 	/* Screen name */
-	byte_stream_put8(&fr->data, strlen(sn));
-	byte_stream_putstr(&fr->data, sn);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	/* Some numbers.  You like numbers, right? */
-	byte_stream_put8(&fr->data, 0x01);
-	byte_stream_put16(&fr->data, 0x0001);
-	byte_stream_put8(&fr->data, iconcsumtype);
+	byte_stream_put8(&bs, 0x01);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put8(&bs, iconcsumtype);
 
 	/* Icon string */
-	byte_stream_put8(&fr->data, iconcsumlen);
-	byte_stream_putraw(&fr->data, iconcsum, iconcsumlen);
+	byte_stream_put8(&bs, iconcsumlen);
+	byte_stream_putraw(&bs, iconcsum, iconcsumlen);
 
-	flap_connection_send(conn, fr);
+	snacid = aim_cachesnac(od, 0x0010, 0x0004, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0010, 0x0004, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_bos.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_bos.c	Mon Apr 28 19:24:18 2008 +0000
@@ -114,7 +114,7 @@
  */
 int aim_bos_changevisibility(OscarData *od, FlapConnection *conn, int changetype, const char *denylist)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	int packlen = 0;
 	guint16 subtype;
 	char *localcpy = NULL, *tmpptr = NULL;
@@ -139,24 +139,24 @@
 	localcpy = g_strdup(denylist);
 
 	listcount = aimutil_itemcnt(localcpy, '&');
-	packlen = aimutil_tokslen(localcpy, 99, '&') + listcount + 9;
+	packlen = aimutil_tokslen(localcpy, 99, '&') + listcount-1;
 
-	frame = flap_frame_new(od, 0x02, packlen);
-
-	snacid = aim_cachesnac(od, 0x0009, subtype, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0009, subtype, 0x00, snacid);
+	byte_stream_new(&bs, packlen);
 
 	for (i = 0; (i < (listcount - 1)) && (i < 99); i++) {
 		tmpptr = aimutil_itemindex(localcpy, i, '&');
 
-		byte_stream_put8(&frame->data, strlen(tmpptr));
-		byte_stream_putstr(&frame->data, tmpptr);
+		byte_stream_put8(&bs, strlen(tmpptr));
+		byte_stream_putstr(&bs, tmpptr);
 
 		g_free(tmpptr);
 	}
 	g_free(localcpy);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0009, subtype, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0009, subtype, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_buddy.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_buddy.c	Mon Apr 28 19:24:18 2008 +0000
@@ -97,21 +97,21 @@
 int
 aim_buddylist_addbuddy(OscarData *od, FlapConnection *conn, const char *sn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!sn || !strlen(sn))
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));
+	byte_stream_new(&bs, 1+strlen(sn));
+
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&frame->data, 0x0003, 0x0004, 0x0000, snacid);
+	flap_connection_send_snac(od, conn, 0x0003, 0x0004, 0x0000, snacid, &bs);
 
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
-
-	flap_connection_send(conn, frame);
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -129,7 +129,7 @@
 int
 aim_buddylist_set(OscarData *od, FlapConnection *conn, const char *buddy_list)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int len = 0;
 	char *localcpy = NULL;
@@ -145,10 +145,7 @@
 		tmpptr = strtok(NULL, "&");
 	}
 
-	frame = flap_frame_new(od, 0x02, 10+len);
-
-	snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0003, 0x0004, 0x0000, snacid);
+	byte_stream_new(&bs, len);
 
 	strncpy(localcpy, buddy_list, strlen(buddy_list) + 1);
 
@@ -157,12 +154,15 @@
 		purple_debug_misc("oscar", "---adding: %s (%" G_GSIZE_FORMAT
 				")\n", tmpptr, strlen(tmpptr));
 
-		byte_stream_put8(&frame->data, strlen(tmpptr));
-		byte_stream_putstr(&frame->data, tmpptr);
+		byte_stream_put8(&bs, strlen(tmpptr));
+		byte_stream_putstr(&bs, tmpptr);
 		tmpptr = strtok(NULL, "&");
 	}
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0003, 0x0004, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0003, 0x0004, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	g_free(localcpy);
 
@@ -179,21 +179,21 @@
 int
 aim_buddylist_removebuddy(OscarData *od, FlapConnection *conn, const char *sn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!sn || !strlen(sn))
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));
+	byte_stream_new(&bs, 1 + strlen(sn));
+
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	snacid = aim_cachesnac(od, 0x0003, 0x0005, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&frame->data, 0x0003, 0x0005, 0x0000, snacid);
+	flap_connection_send_snac(od, conn, 0x0003, 0x0005, 0x0000, snacid, &bs);
 
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
-
-	flap_connection_send(conn, frame);
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_chat.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_chat.c	Mon Apr 28 19:24:18 2008 +0000
@@ -353,7 +353,7 @@
 aim_chat_send_im(OscarData *od, FlapConnection *conn, guint16 flags, const gchar *msg, int msglen, const char *encoding, const char *language)
 {
 	int i;
-	FlapFrame *frame;
+	ByteStream bs;
 	IcbmCookie *cookie;
 	aim_snacid_t snacid;
 	guint8 ckstr[8];
@@ -362,10 +362,9 @@
 	if (!od || !conn || !msg || (msglen <= 0))
 		return 0;
 
-	frame = flap_frame_new(od, 0x02, 1152);
+	byte_stream_new(&bs, 1142);
 
 	snacid = aim_cachesnac(od, 0x000e, 0x0005, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x000e, 0x0005, 0x0000, snacid);
 
 	/*
 	 * Cookie
@@ -382,8 +381,8 @@
 	aim_cachecookie(od, cookie);
 
 	/* ICBM Header */
-	byte_stream_putraw(&frame->data, ckstr, 8); /* Cookie */
-	byte_stream_put16(&frame->data, 0x0003); /* Channel */
+	byte_stream_putraw(&bs, ckstr, 8); /* Cookie */
+	byte_stream_put16(&bs, 0x0003); /* Channel */
 
 	/*
 	 * Type 1: Flag meaning this message is destined to the room.
@@ -428,13 +427,15 @@
 	 */
 	aim_tlvlist_add_frozentlvlist(&tlvlist, 0x0005, &inner_tlvlist);
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x000e, 0x0005, 0x0000, snacid, &bs);
 
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
--- a/libpurple/protocols/oscar/family_chatnav.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_chatnav.c	Mon Apr 28 19:24:18 2008 +0000
@@ -91,17 +91,16 @@
 	static const char ck[] = {"create"};
 	static const char lang[] = {"en"};
 	static const char charset[] = {"us-ascii"};
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
-	frame = flap_frame_new(od, 0x02, 1152);
+	byte_stream_new(&bs, 1142);
 
 	snacid = aim_cachesnac(od, 0x000d, 0x0008, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x000d, 0x0008, 0x0000, snacid);
 
 	/* exchange */
-	byte_stream_put16(&frame->data, exchange);
+	byte_stream_put16(&bs, exchange);
 
 	/*
 	 * This looks to be a big hack.  You'll note that this entire
@@ -114,8 +113,8 @@
 	 * AOL style, I'm going to guess that it is the latter, and that
 	 * the value of the room name in create requests is ignored.
 	 */
-	byte_stream_put8(&frame->data, strlen(ck));
-	byte_stream_putstr(&frame->data, ck);
+	byte_stream_put8(&bs, strlen(ck));
+	byte_stream_putstr(&bs, ck);
 
 	/*
 	 * instance
@@ -123,22 +122,24 @@
 	 * Setting this to 0xffff apparently assigns the last instance.
 	 *
 	 */
-	byte_stream_put16(&frame->data, 0xffff);
+	byte_stream_put16(&bs, 0xffff);
 
 	/* detail level */
-	byte_stream_put8(&frame->data, 0x01);
+	byte_stream_put8(&bs, 0x01);
 
 	aim_tlvlist_add_str(&tlvlist, 0x00d3, name);
 	aim_tlvlist_add_str(&tlvlist, 0x00d6, charset);
 	aim_tlvlist_add_str(&tlvlist, 0x00d7, lang);
 
 	/* tlvcount */
-	byte_stream_put16(&frame->data, aim_tlvlist_count(tlvlist));
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	byte_stream_put16(&bs, aim_tlvlist_count(tlvlist));
+	aim_tlvlist_write(&bs, &tlvlist);
 
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x000d, 0x0008, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_feedbag.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_feedbag.c	Mon Apr 28 19:24:18 2008 +0000
@@ -1241,21 +1241,21 @@
 int aim_ssi_reqifchanged(OscarData *od, time_t timestamp, guint16 numitems)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)))
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+4+2);
+	byte_stream_new(&bs, 4+2);
+
+	byte_stream_put32(&bs, timestamp);
+	byte_stream_put16(&bs, numitems);
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid, &bs);
 
-	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_REQIFCHANGED, 0x0000, snacid);
-	byte_stream_put32(&frame->data, timestamp);
-	byte_stream_put16(&frame->data, numitems);
-
-	flap_connection_send(conn, frame);
+	byte_stream_destroy(&bs);
 
 	/* Free any current data, just in case */
 	aim_ssi_freelist(od);
@@ -1343,42 +1343,42 @@
 static int aim_ssi_addmoddel(OscarData *od)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
-	int snaclen;
+	int bslen;
 	struct aim_ssi_tmp *cur;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !od->ssi.pending || !od->ssi.pending->item)
 		return -EINVAL;
 
 	/* Calculate total SNAC size */
-	snaclen = 10; /* For family, subtype, flags, and SNAC ID */
+	bslen = 0;
 	for (cur=od->ssi.pending; cur; cur=cur->next) {
-		snaclen += 10; /* For length, GID, BID, type, and length */
+		bslen += 10; /* For length, GID, BID, type, and length */
 		if (cur->item->name)
-			snaclen += strlen(cur->item->name);
+			bslen += strlen(cur->item->name);
 		if (cur->item->data)
-			snaclen += aim_tlvlist_size(cur->item->data);
+			bslen += aim_tlvlist_size(cur->item->data);
 	}
 
-	frame = flap_frame_new(od, 0x02, snaclen);
+	byte_stream_new(&bs, bslen);
+
+	for (cur=od->ssi.pending; cur; cur=cur->next) {
+		byte_stream_put16(&bs, cur->item->name ? strlen(cur->item->name) : 0);
+		if (cur->item->name)
+			byte_stream_putstr(&bs, cur->item->name);
+		byte_stream_put16(&bs, cur->item->gid);
+		byte_stream_put16(&bs, cur->item->bid);
+		byte_stream_put16(&bs, cur->item->type);
+		byte_stream_put16(&bs, cur->item->data ? aim_tlvlist_size(cur->item->data) : 0);
+		if (cur->item->data)
+			aim_tlvlist_write(&bs, &cur->item->data);
+	}
 
 	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, snacid);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, od->ssi.pending->action, 0x0000, snacid, &bs);
 
-	for (cur=od->ssi.pending; cur; cur=cur->next) {
-		byte_stream_put16(&frame->data, cur->item->name ? strlen(cur->item->name) : 0);
-		if (cur->item->name)
-			byte_stream_putstr(&frame->data, cur->item->name);
-		byte_stream_put16(&frame->data, cur->item->gid);
-		byte_stream_put16(&frame->data, cur->item->bid);
-		byte_stream_put16(&frame->data, cur->item->type);
-		byte_stream_put16(&frame->data, cur->item->data ? aim_tlvlist_size(cur->item->data) : 0);
-		if (cur->item->data)
-			aim_tlvlist_write(&frame->data, &cur->item->data);
-	}
-
-	flap_connection_send(conn, frame);
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1684,32 +1684,32 @@
 int aim_ssi_sendauth(OscarData *od, char *sn, char *msg)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid);
+	byte_stream_new(&bs, 1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2);
 
 	/* Screen name */
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	/* Message (null terminated) */
-	byte_stream_put16(&frame->data, msg ? strlen(msg) : 0);
+	byte_stream_put16(&bs, msg ? strlen(msg) : 0);
 	if (msg) {
-		byte_stream_putstr(&frame->data, msg);
-		byte_stream_put8(&frame->data, 0x00);
+		byte_stream_putstr(&bs, msg);
+		byte_stream_put8(&bs, 0x00);
 	}
 
 	/* Unknown */
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTH, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1758,32 +1758,32 @@
 int aim_ssi_sendauthrequest(OscarData *od, char *sn, const char *msg)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn)+2+(msg ? strlen(msg)+1 : 0)+2);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid);
+	byte_stream_new(&bs, 1+strlen(sn) + 2+(msg ? (strlen(msg)+1) : 0) + 2);
 
 	/* Screen name */
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	/* Message (null terminated) */
-	byte_stream_put16(&frame->data, msg ? strlen(msg) : 0);
+	byte_stream_put16(&bs, msg ? strlen(msg) : 0);
 	if (msg) {
-		byte_stream_putstr(&frame->data, msg);
-		byte_stream_put8(&frame->data, 0x00);
+		byte_stream_putstr(&bs, msg);
+		byte_stream_put8(&bs, 0x00);
 	}
 
 	/* Unknown */
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREQ, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1835,36 +1835,36 @@
 int aim_ssi_sendauthreply(OscarData *od, char *sn, guint8 reply, const char *msg)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_FEEDBAG)) || !sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10 + 1+strlen(sn) + 1 + 2+(msg ? strlen(msg)+1 : 0) + 2);
-
-	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid);
+	byte_stream_new(&bs, 1+strlen(sn) + 1 + 2+(msg ? (strlen(msg)+1) : 0) + 2);
 
 	/* Screen name */
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	/* Grant or deny */
-	byte_stream_put8(&frame->data, reply);
+	byte_stream_put8(&bs, reply);
 
 	/* Message (null terminated) */
-	byte_stream_put16(&frame->data, msg ? (strlen(msg)+1) : 0);
+	byte_stream_put16(&bs, msg ? (strlen(msg)+1) : 0);
 	if (msg) {
-		byte_stream_putstr(&frame->data, msg);
-		byte_stream_put8(&frame->data, 0x00);
+		byte_stream_putstr(&bs, msg);
+		byte_stream_put8(&bs, 0x00);
 	}
 
 	/* Unknown */
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, SNAC_FAMILY_FEEDBAG, SNAC_SUBTYPE_FEEDBAG_SENDAUTHREP, 0x0000, snacid, &bs);
 
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
--- a/libpurple/protocols/oscar/family_icbm.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_icbm.c	Mon Apr 28 19:24:18 2008 +0000
@@ -161,7 +161,7 @@
 int aim_im_setparams(OscarData *od, struct aim_icbmparameters *params)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
@@ -170,23 +170,23 @@
 	if (!params)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+16);
-
-	snacid = aim_cachesnac(od, 0x0004, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0002, 0x0000, snacid);
+	byte_stream_new(&bs, 16);
 
 	/* This is read-only (see Parameter Reply). Must be set to zero here. */
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
 
 	/* These are all read-write */
-	byte_stream_put32(&frame->data, params->flags);
-	byte_stream_put16(&frame->data, params->maxmsglen);
-	byte_stream_put16(&frame->data, params->maxsenderwarn);
-	byte_stream_put16(&frame->data, params->maxrecverwarn);
-	byte_stream_put32(&frame->data, params->minmsginterval);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_put32(&bs, params->flags);
+	byte_stream_put16(&bs, params->maxmsglen);
+	byte_stream_put16(&bs, params->maxsenderwarn);
+	byte_stream_put16(&bs, params->maxrecverwarn);
+	byte_stream_put32(&bs, params->minmsginterval);
+
+	snacid = aim_cachesnac(od, 0x0004, 0x0002, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0002, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -413,7 +413,7 @@
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, args->destsn, strlen(args->destsn)+1);
 
 	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &data);
-	g_free(data.data);
+	byte_stream_destroy(&data);
 
 	/* clean out SNACs over 60sec old */
 	aim_cleansnacs(od, 60);
@@ -454,7 +454,7 @@
 int aim_im_sendch2_chatinvite(OscarData *od, const char *sn, const char *msg, guint16 exchange, const char *roomname, guint16 instance)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	IcbmCookie *msgcookie;
 	struct aim_invite_priv *priv;
@@ -470,10 +470,9 @@
 
 	aim_icbm_makecookie(cookie);
 
-	frame = flap_frame_new(od, 0x02, 1152+strlen(sn)+strlen(roomname)+strlen(msg));
+	byte_stream_new(&bs, 1142+strlen(sn)+strlen(roomname)+strlen(msg));
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* XXX should be uncached by an unwritten 'invite accept' handler */
 	priv = g_malloc(sizeof(struct aim_invite_priv));
@@ -488,7 +487,7 @@
 		g_free(priv);
 
 	/* ICBM Header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	/*
 	 * TLV t(0005)
@@ -513,14 +512,16 @@
 	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
 
 	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	g_free(hdrbs.data);
-
-	aim_tlvlist_write(&frame->data, &outer_tlvlist);
+	byte_stream_destroy(&hdrbs);
+
+	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -534,7 +535,7 @@
 int aim_im_sendch2_icon(OscarData *od, const char *sn, const guint8 *icon, int iconlen, time_t stamp, guint16 iconsum)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
@@ -546,51 +547,52 @@
 
 	aim_icbm_makecookie(cookie);
 
-	frame = flap_frame_new(od, 0x02, 10+8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2);
+	byte_stream_new(&bs, 8+2+1+strlen(sn)+2+2+2+8+16+2+2+2+2+2+2+2+4+4+4+iconlen+strlen(AIM_ICONIDENT)+2+2);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	/*
 	 * TLV t(0005)
 	 *
 	 * Encompasses everything below.
 	 */
-	byte_stream_put16(&frame->data, 0x0005);
-	byte_stream_put16(&frame->data, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT));
-
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_putraw(&frame->data, cookie, 8);
-	byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_BUDDYICON);
+	byte_stream_put16(&bs, 0x0005);
+	byte_stream_put16(&bs, 2+8+16+6+4+4+iconlen+4+4+4+strlen(AIM_ICONIDENT));
+
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_putraw(&bs, cookie, 8);
+	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_BUDDYICON);
 
 	/* TLV t(000a) */
-	byte_stream_put16(&frame->data, 0x000a);
-	byte_stream_put16(&frame->data, 0x0002);
-	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&bs, 0x000a);
+	byte_stream_put16(&bs, 0x0002);
+	byte_stream_put16(&bs, 0x0001);
 
 	/* TLV t(000f) */
-	byte_stream_put16(&frame->data, 0x000f);
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x000f);
+	byte_stream_put16(&bs, 0x0000);
 
 	/* TLV t(2711) */
-	byte_stream_put16(&frame->data, 0x2711);
-	byte_stream_put16(&frame->data, 4+4+4+iconlen+strlen(AIM_ICONIDENT));
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_put16(&frame->data, iconsum);
-	byte_stream_put32(&frame->data, iconlen);
-	byte_stream_put32(&frame->data, stamp);
-	byte_stream_putraw(&frame->data, icon, iconlen);
-	byte_stream_putstr(&frame->data, AIM_ICONIDENT);
+	byte_stream_put16(&bs, 0x2711);
+	byte_stream_put16(&bs, 4+4+4+iconlen+strlen(AIM_ICONIDENT));
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, iconsum);
+	byte_stream_put32(&bs, iconlen);
+	byte_stream_put32(&bs, stamp);
+	byte_stream_putraw(&bs, icon, iconlen);
+	byte_stream_putstr(&bs, AIM_ICONIDENT);
 
 	/* TLV t(0003) */
-	byte_stream_put16(&frame->data, 0x0003);
-	byte_stream_put16(&frame->data, 0x0000);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_put16(&bs, 0x0003);
+	byte_stream_put16(&bs, 0x0000);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -612,7 +614,7 @@
 int aim_im_sendch2_rtfmsg(OscarData *od, struct aim_sendrtfmsg_args *args)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 	const char rtfcap[] = {"{97B12751-243C-4334-AD22-D6ABF73F1492}"}; /* OSCAR_CAPABILITY_ICQRTF capability in string form */
@@ -628,61 +630,62 @@
 
 	aim_icbm_makecookie(cookie);
 
-	frame = flap_frame_new(od, 0x02, 10+128+servdatalen);
+	byte_stream_new(&bs, 128+servdatalen);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, args->destsn);
+	aim_im_puticbm(&bs, cookie, 0x0002, args->destsn);
 
 	/* TLV t(0005) - Encompasses everything below. */
-	byte_stream_put16(&frame->data, 0x0005);
-	byte_stream_put16(&frame->data, 2+8+16  +  2+2+2  +  2+2  +  2+2+servdatalen);
-
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_putraw(&frame->data, cookie, 8);
-	byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_ICQSERVERRELAY);
+	byte_stream_put16(&bs, 0x0005);
+	byte_stream_put16(&bs, 2+8+16  +  2+2+2  +  2+2  +  2+2+servdatalen);
+
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_putraw(&bs, cookie, 8);
+	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY);
 
 	/* t(000a) l(0002) v(0001) */
-	byte_stream_put16(&frame->data, 0x000a);
-	byte_stream_put16(&frame->data, 0x0002);
-	byte_stream_put16(&frame->data, 0x0001);
+	byte_stream_put16(&bs, 0x000a);
+	byte_stream_put16(&bs, 0x0002);
+	byte_stream_put16(&bs, 0x0001);
 
 	/* t(000f) l(0000) v() */
-	byte_stream_put16(&frame->data, 0x000f);
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x000f);
+	byte_stream_put16(&bs, 0x0000);
 
 	/* Service Data TLV */
-	byte_stream_put16(&frame->data, 0x2711);
-	byte_stream_put16(&frame->data, servdatalen);
-
-	byte_stream_putle16(&frame->data, 11 + 16 /* 11 + (sizeof CLSID) */);
-	byte_stream_putle16(&frame->data, 9);
-	byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_EMPTY);
-	byte_stream_putle16(&frame->data, 0);
-	byte_stream_putle32(&frame->data, 0);
-	byte_stream_putle8(&frame->data, 0);
-	byte_stream_putle16(&frame->data, 0x03ea); /* trid1 */
-
-	byte_stream_putle16(&frame->data, 14);
-	byte_stream_putle16(&frame->data, 0x03eb); /* trid2 */
-	byte_stream_putle32(&frame->data, 0);
-	byte_stream_putle32(&frame->data, 0);
-	byte_stream_putle32(&frame->data, 0);
-
-	byte_stream_putle16(&frame->data, 0x0001);
-	byte_stream_putle32(&frame->data, 0);
-	byte_stream_putle16(&frame->data, strlen(args->rtfmsg)+1);
-	byte_stream_putraw(&frame->data, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1);
-
-	byte_stream_putle32(&frame->data, args->fgcolor);
-	byte_stream_putle32(&frame->data, args->bgcolor);
-	byte_stream_putle32(&frame->data, strlen(rtfcap)+1);
-	byte_stream_putraw(&frame->data, (const guint8 *)rtfcap, strlen(rtfcap)+1);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_put16(&bs, 0x2711);
+	byte_stream_put16(&bs, servdatalen);
+
+	byte_stream_putle16(&bs, 11 + 16 /* 11 + (sizeof CLSID) */);
+	byte_stream_putle16(&bs, 9);
+	byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
+	byte_stream_putle16(&bs, 0);
+	byte_stream_putle32(&bs, 0);
+	byte_stream_putle8(&bs, 0);
+	byte_stream_putle16(&bs, 0x03ea); /* trid1 */
+
+	byte_stream_putle16(&bs, 14);
+	byte_stream_putle16(&bs, 0x03eb); /* trid2 */
+	byte_stream_putle32(&bs, 0);
+	byte_stream_putle32(&bs, 0);
+	byte_stream_putle32(&bs, 0);
+
+	byte_stream_putle16(&bs, 0x0001);
+	byte_stream_putle32(&bs, 0);
+	byte_stream_putle16(&bs, strlen(args->rtfmsg)+1);
+	byte_stream_putraw(&bs, (const guint8 *)args->rtfmsg, strlen(args->rtfmsg)+1);
+
+	byte_stream_putle32(&bs, args->fgcolor);
+	byte_stream_putle32(&bs, args->bgcolor);
+	byte_stream_putle32(&bs, strlen(rtfcap)+1);
+	byte_stream_putraw(&bs, (const guint8 *)rtfcap, strlen(rtfcap)+1);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -695,7 +698,7 @@
 {
 	OscarData *od;
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
 	ByteStream hdrbs;
@@ -705,13 +708,12 @@
 	if (conn == NULL)
 		return;
 
-	frame = flap_frame_new(od, 0x02, 128+strlen(peer_conn->sn));
+	byte_stream_new(&bs, 118+strlen(peer_conn->sn));
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, peer_conn->cookie, 0x0002, peer_conn->sn);
+	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->sn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -728,12 +730,14 @@
 	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
 	g_free(hdrbs.data);
 
-	aim_tlvlist_write(&frame->data, &outer_tlvlist);
+	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /**
@@ -745,7 +749,7 @@
 {
 	OscarData *od;
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	od = peer_conn->od;
@@ -753,21 +757,22 @@
 	if (conn == NULL)
 		return;
 
-	frame = flap_frame_new(od, 0x02, 10 + 11+strlen(peer_conn->sn) + 4+2+8+16);
+	byte_stream_new(&bs, 11+strlen(peer_conn->sn) + 4+2+8+16);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, peer_conn->cookie, 0x0002, peer_conn->sn);
-
-	byte_stream_put16(&frame->data, 0x0005);
-	byte_stream_put16(&frame->data, 0x001a);
-	byte_stream_put16(&frame->data, AIM_RENDEZVOUS_CONNECTED);
-	byte_stream_putraw(&frame->data, peer_conn->cookie, 8);
-	byte_stream_putcaps(&frame->data, peer_conn->type);
-
-	flap_connection_send(conn, frame);
+	aim_im_puticbm(&bs, peer_conn->cookie, 0x0002, peer_conn->sn);
+
+	byte_stream_put16(&bs, 0x0005);
+	byte_stream_put16(&bs, 0x001a);
+	byte_stream_put16(&bs, AIM_RENDEZVOUS_CONNECTED);
+	byte_stream_putraw(&bs, peer_conn->cookie, 8);
+	byte_stream_putcaps(&bs, peer_conn->type);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);	
 }
 
 /**
@@ -781,7 +786,7 @@
 aim_im_sendch2_odc_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
 	ByteStream hdrbs;
@@ -790,13 +795,12 @@
 	if (conn == NULL)
 		return;
 
-	frame = flap_frame_new(od, 0x02, 256+strlen(sn));
+	byte_stream_new(&bs, 246+strlen(sn));
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -814,14 +818,16 @@
 	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
 
 	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	g_free(hdrbs.data);
-
-	aim_tlvlist_write(&frame->data, &outer_tlvlist);
+	byte_stream_destroy(&hdrbs);
+
+	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /**
@@ -832,7 +838,7 @@
 aim_im_sendch2_odc_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
 	ByteStream hdrbs;
@@ -842,13 +848,12 @@
 	if (conn == NULL)
 		return;
 
-	frame = flap_frame_new(od, 0x02, 256+strlen(sn));
+	byte_stream_new(&bs, 246+strlen(sn));
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -876,14 +881,16 @@
 	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
 
 	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	g_free(hdrbs.data);
-
-	aim_tlvlist_write(&frame->data, &outer_tlvlist);
+	byte_stream_destroy(&hdrbs);
+
+	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /**
@@ -894,7 +901,7 @@
 aim_im_sendch2_sendfile_requestdirect(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 port, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
 	ByteStream hdrbs;
@@ -903,13 +910,12 @@
 	if (conn == NULL)
 		return;
 
-	frame = flap_frame_new(od, 0x02, 1024);
+	byte_stream_new(&bs, 1014);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -952,20 +958,22 @@
 		byte_stream_put8(&bs, 0x00);
 
 		aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, bs.len, bs.data);
-		g_free(bs.data);
+		byte_stream_destroy(&bs);
 		/* End TLV t(2711) */
 	}
 
 	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
 	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	g_free(hdrbs.data);
-
-	aim_tlvlist_write(&frame->data, &outer_tlvlist);
+	byte_stream_destroy(&hdrbs);
+
+	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /**
@@ -976,7 +984,7 @@
 aim_im_sendch2_sendfile_requestproxy(OscarData *od, guchar *cookie, const char *sn, const guint8 *ip, guint16 pin, guint16 requestnumber, const gchar *filename, guint32 size, guint16 numfiles)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *outer_tlvlist = NULL, *inner_tlvlist = NULL;
 	ByteStream hdrbs;
@@ -986,13 +994,12 @@
 	if (conn == NULL)
 		return;
 
-	frame = flap_frame_new(od, 0x02, 1024);
+	byte_stream_new(&bs, 1014);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	aim_tlvlist_add_noval(&outer_tlvlist, 0x0003);
 
@@ -1030,34 +1037,36 @@
 
 	if (filename != NULL)
 	{
-		ByteStream bs;
+		ByteStream filename_bs;
 
 		/* Begin TLV t(2711) */
-		byte_stream_new(&bs, 2+2+4+strlen(filename)+1);
-		byte_stream_put16(&bs, (numfiles > 1) ? 0x0002 : 0x0001);
-		byte_stream_put16(&bs, numfiles);
-		byte_stream_put32(&bs, size);
+		byte_stream_new(&filename_bs, 2+2+4+strlen(filename)+1);
+		byte_stream_put16(&filename_bs, (numfiles > 1) ? 0x0002 : 0x0001);
+		byte_stream_put16(&filename_bs, numfiles);
+		byte_stream_put32(&filename_bs, size);
 
 		/* Filename - NULL terminated, for some odd reason */
-		byte_stream_putstr(&bs, filename);
-		byte_stream_put8(&bs, 0x00);
-
-		aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, bs.len, bs.data);
-		g_free(bs.data);
+		byte_stream_putstr(&filename_bs, filename);
+		byte_stream_put8(&filename_bs, 0x00);
+
+		aim_tlvlist_add_raw(&inner_tlvlist, 0x2711, filename_bs.len, filename_bs.data);
+		byte_stream_destroy(&filename_bs);
 		/* End TLV t(2711) */
 	}
 
 	aim_tlvlist_write(&hdrbs, &inner_tlvlist);
 
 	aim_tlvlist_add_raw(&outer_tlvlist, 0x0005, byte_stream_curpos(&hdrbs), hdrbs.data);
-	g_free(hdrbs.data);
-
-	aim_tlvlist_write(&frame->data, &outer_tlvlist);
+	byte_stream_destroy(&hdrbs);
+
+	aim_tlvlist_write(&bs, &outer_tlvlist);
 
 	aim_tlvlist_free(inner_tlvlist);
 	aim_tlvlist_free(outer_tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /**
@@ -1072,7 +1081,7 @@
 int aim_im_sendch2_geticqaway(OscarData *od, const char *sn, int type)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
@@ -1081,79 +1090,80 @@
 
 	aim_icbm_makecookie(cookie);
 
-	frame = flap_frame_new(od, 0x02, 10+8+2+1+strlen(sn) + 4+0x5e + 4);
+	byte_stream_new(&bs, 8+2+1+strlen(sn) + 4+0x5e + 4);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0002, sn);
+	aim_im_puticbm(&bs, cookie, 0x0002, sn);
 
 	/* TLV t(0005) - Encompasses almost everything below. */
-	byte_stream_put16(&frame->data, 0x0005); /* T */
-	byte_stream_put16(&frame->data, 0x005e); /* L */
+	byte_stream_put16(&bs, 0x0005); /* T */
+	byte_stream_put16(&bs, 0x005e); /* L */
 	{ /* V */
-		byte_stream_put16(&frame->data, 0x0000);
+		byte_stream_put16(&bs, 0x0000);
 
 		/* Cookie */
-		byte_stream_putraw(&frame->data, cookie, 8);
+		byte_stream_putraw(&bs, cookie, 8);
 
 		/* Put the 16 byte server relay capability */
-		byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_ICQSERVERRELAY);
+		byte_stream_putcaps(&bs, OSCAR_CAPABILITY_ICQSERVERRELAY);
 
 		/* TLV t(000a) */
-		byte_stream_put16(&frame->data, 0x000a);
-		byte_stream_put16(&frame->data, 0x0002);
-		byte_stream_put16(&frame->data, 0x0001);
+		byte_stream_put16(&bs, 0x000a);
+		byte_stream_put16(&bs, 0x0002);
+		byte_stream_put16(&bs, 0x0001);
 
 		/* TLV t(000f) */
-		byte_stream_put16(&frame->data, 0x000f);
-		byte_stream_put16(&frame->data, 0x0000);
+		byte_stream_put16(&bs, 0x000f);
+		byte_stream_put16(&bs, 0x0000);
 
 		/* TLV t(2711) */
-		byte_stream_put16(&frame->data, 0x2711);
-		byte_stream_put16(&frame->data, 0x0036);
+		byte_stream_put16(&bs, 0x2711);
+		byte_stream_put16(&bs, 0x0036);
 		{ /* V */
-			byte_stream_putle16(&frame->data, 0x001b); /* L */
-			byte_stream_putle16(&frame->data, 0x0009); /* Protocol version */
-			byte_stream_putcaps(&frame->data, OSCAR_CAPABILITY_EMPTY);
-			byte_stream_putle16(&frame->data, 0x0000); /* Unknown */
-			byte_stream_putle16(&frame->data, 0x0001); /* Client features? */
-			byte_stream_putle16(&frame->data, 0x0000); /* Unknown */
-			byte_stream_putle8(&frame->data, 0x00); /* Unkizown */
-			byte_stream_putle16(&frame->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
-
-			byte_stream_putle16(&frame->data, 0x000e); /* L */
-			byte_stream_putle16(&frame->data, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
-			byte_stream_putle32(&frame->data, 0x00000000); /* Unknown */
-			byte_stream_putle32(&frame->data, 0x00000000); /* Unknown */
-			byte_stream_putle32(&frame->data, 0x00000000); /* Unknown */
+			byte_stream_putle16(&bs, 0x001b); /* L */
+			byte_stream_putle16(&bs, 0x0009); /* Protocol version */
+			byte_stream_putcaps(&bs, OSCAR_CAPABILITY_EMPTY);
+			byte_stream_putle16(&bs, 0x0000); /* Unknown */
+			byte_stream_putle16(&bs, 0x0001); /* Client features? */
+			byte_stream_putle16(&bs, 0x0000); /* Unknown */
+			byte_stream_putle8(&bs, 0x00); /* Unkizown */
+			byte_stream_putle16(&bs, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
+
+			byte_stream_putle16(&bs, 0x000e); /* L */
+			byte_stream_putle16(&bs, 0xffff); /* Sequence number?  XXX - This should decrement by 1 with each request */
+			byte_stream_putle32(&bs, 0x00000000); /* Unknown */
+			byte_stream_putle32(&bs, 0x00000000); /* Unknown */
+			byte_stream_putle32(&bs, 0x00000000); /* Unknown */
 
 			/* The type of status message being requested */
 			if (type & AIM_ICQ_STATE_CHAT)
-				byte_stream_putle16(&frame->data, 0x03ec);
+				byte_stream_putle16(&bs, 0x03ec);
 			else if(type & AIM_ICQ_STATE_DND)
-				byte_stream_putle16(&frame->data, 0x03eb);
+				byte_stream_putle16(&bs, 0x03eb);
 			else if(type & AIM_ICQ_STATE_OUT)
-				byte_stream_putle16(&frame->data, 0x03ea);
+				byte_stream_putle16(&bs, 0x03ea);
 			else if(type & AIM_ICQ_STATE_BUSY)
-				byte_stream_putle16(&frame->data, 0x03e9);
+				byte_stream_putle16(&bs, 0x03e9);
 			else if(type & AIM_ICQ_STATE_AWAY)
-				byte_stream_putle16(&frame->data, 0x03e8);
-
-			byte_stream_putle16(&frame->data, 0x0001); /* Status? */
-			byte_stream_putle16(&frame->data, 0x0001); /* Priority of this message? */
-			byte_stream_putle16(&frame->data, 0x0001); /* L */
-			byte_stream_putle8(&frame->data, 0x00); /* String of length L */
+				byte_stream_putle16(&bs, 0x03e8);
+
+			byte_stream_putle16(&bs, 0x0001); /* Status? */
+			byte_stream_putle16(&bs, 0x0001); /* Priority of this message? */
+			byte_stream_putle16(&bs, 0x0001); /* L */
+			byte_stream_putle8(&bs, 0x00); /* String of length L */
 		} /* End TLV t(2711) */
 	} /* End TLV t(0005) */
 
 	/* TLV t(0003) */
-	byte_stream_put16(&frame->data, 0x0003);
-	byte_stream_put16(&frame->data, 0x0000);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_put16(&bs, 0x0003);
+	byte_stream_put16(&bs, 0x0000);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -1174,7 +1184,7 @@
 int aim_im_sendch4(OscarData *od, const char *sn, guint16 type, const char *message)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	guchar cookie[8];
 
@@ -1184,44 +1194,45 @@
 	if (!sn || !type || !message)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+8+3+strlen(sn)+12+strlen(message)+1+4);
+	byte_stream_new(&bs, 8+3+strlen(sn)+12+strlen(message)+1+4);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
 
 	aim_icbm_makecookie(cookie);
 
 	/* ICBM header */
-	aim_im_puticbm(&frame->data, cookie, 0x0004, sn);
+	aim_im_puticbm(&bs, cookie, 0x0004, sn);
 
 	/*
 	 * TLV t(0005)
 	 *
 	 * ICQ data (the UIN and the message).
 	 */
-	byte_stream_put16(&frame->data, 0x0005);
-	byte_stream_put16(&frame->data, 4 + 2+2+strlen(message)+1);
+	byte_stream_put16(&bs, 0x0005);
+	byte_stream_put16(&bs, 4 + 2+2+strlen(message)+1);
 
 	/*
 	 * Your UIN
 	 */
-	byte_stream_putle32(&frame->data, atoi(od->sn));
+	byte_stream_putle32(&bs, atoi(od->sn));
 
 	/*
 	 * TLV t(type) l(strlen(message)+1) v(message+NULL)
 	 */
-	byte_stream_putle16(&frame->data, type);
-	byte_stream_putle16(&frame->data, strlen(message)+1);
-	byte_stream_putraw(&frame->data, (const guint8 *)message, strlen(message)+1);
+	byte_stream_putle16(&bs, type);
+	byte_stream_putle16(&bs, strlen(message)+1);
+	byte_stream_putraw(&bs, (const guint8 *)message, strlen(message)+1);
 
 	/*
 	 * TLV t(0006) l(0000) v()
 	 */
-	byte_stream_put16(&frame->data, 0x0006);
-	byte_stream_put16(&frame->data, 0x0000);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_put16(&bs, 0x0006);
+	byte_stream_put16(&bs, 0x0000);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -2249,22 +2260,23 @@
  */
 int aim_im_warn(OscarData *od, FlapConnection *conn, const char *sn, guint32 flags)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !conn || !sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, strlen(sn)+13);
+	byte_stream_new(&bs, strlen(sn)+3);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0008, 0x0000, sn, strlen(sn)+1);
-	aim_putsnac(&frame->data, 0x0004, 0x0008, 0x0000, snacid);
-
-	byte_stream_put16(&frame->data, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
-
-	flap_connection_send(conn, frame);
+
+	byte_stream_put16(&bs, (flags & AIM_WARN_ANON) ? 0x0001 : 0x0000);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0008, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -2305,29 +2317,30 @@
 int aim_im_denytransfer(OscarData *od, const char *sn, const guchar *cookie, guint16 code)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0004)))
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+8+2+1+strlen(sn)+6);
+	byte_stream_new(&bs, 8+2+1+strlen(sn)+6);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x000b, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x000b, 0x0000, snacid);
-
-	byte_stream_putraw(&frame->data, cookie, 8);
-
-	byte_stream_put16(&frame->data, 0x0002); /* channel */
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+
+	byte_stream_putraw(&bs, cookie, 8);
+
+	byte_stream_put16(&bs, 0x0002); /* channel */
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	aim_tlvlist_add_16(&tlvlist, 0x0003, code);
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0004, 0x000b, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -2662,7 +2675,7 @@
 int aim_im_sendmtn(OscarData *od, guint16 type1, const char *sn, guint16 type2)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, 0x0002)))
@@ -2671,38 +2684,39 @@
 	if (!sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+11+strlen(sn)+2);
+	byte_stream_new(&bs, 11+strlen(sn)+2);
 
 	snacid = aim_cachesnac(od, 0x0004, 0x0014, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0004, 0x0014, 0x0000, snacid);
 
 	/*
 	 * 8 days of light
 	 * Er, that is to say, 8 bytes of 0's
 	 */
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_put16(&frame->data, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, 0x0000);
 
 	/*
 	 * Type 1 (should be 0x0001 for mtn)
 	 */
-	byte_stream_put16(&frame->data, type1);
+	byte_stream_put16(&bs, type1);
 
 	/*
 	 * Dest sn
 	 */
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	/*
 	 * Type 2 (should be 0x0000, 0x0001, or 0x0002 for mtn)
 	 */
-	byte_stream_put16(&frame->data, type2);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_put16(&bs, type2);
+
+	flap_connection_send_snac(od, conn, 0x0004, 0x0014, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
--- a/libpurple/protocols/oscar/family_icq.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_icq.c	Mon Apr 28 19:24:18 2008 +0000
@@ -29,7 +29,7 @@
 int aim_icq_reqofflinemsgs(OscarData *od)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 
@@ -38,28 +38,29 @@
 
 	bslen = 2 + 4 + 2 + 2;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x003c); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x003c); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
 
 int aim_icq_ackofflinemsgs(OscarData *od)
 {
-	FlapConnection *conn;
+	ByteStream bs;
 	FlapFrame *frame;
 	aim_snacid_t snacid;
 	int bslen;
@@ -69,21 +70,22 @@
 
 	bslen = 2 + 4 + 2 + 2;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x003e); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x003e); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -93,7 +95,7 @@
 aim_icq_setsecurity(OscarData *od, gboolean auth_required, gboolean webaware)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 
@@ -102,30 +104,31 @@
 
 	bslen = 2+4+2+2+2+2+2+1+1+1+1+1+1;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x0c3a); /* shrug. */
-	byte_stream_putle16(&frame->data, 0x030c);
-	byte_stream_putle16(&frame->data, 0x0001);
-	byte_stream_putle8(&frame->data, webaware);
-	byte_stream_putle8(&frame->data, 0xf8);
-	byte_stream_putle8(&frame->data, 0x02);
-	byte_stream_putle8(&frame->data, 0x01);
-	byte_stream_putle8(&frame->data, 0x00);
-	byte_stream_putle8(&frame->data, !auth_required);
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x0c3a); /* shrug. */
+	byte_stream_putle16(&bs, 0x030c);
+	byte_stream_putle16(&bs, 0x0001);
+	byte_stream_putle8(&bs, webaware);
+	byte_stream_putle8(&bs, 0xf8);
+	byte_stream_putle8(&bs, 0x02);
+	byte_stream_putle8(&bs, 0x01);
+	byte_stream_putle8(&bs, 0x00);
+	byte_stream_putle8(&bs, !auth_required);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -141,7 +144,7 @@
 int aim_icq_changepasswd(OscarData *od, const char *passwd)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen, passwdlen;
 
@@ -156,25 +159,26 @@
 		passwdlen = MAXICQPASSLEN;
 	bslen = 2+4+2+2+2+2+passwdlen+1;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x042e); /* shrug. */
-	byte_stream_putle16(&frame->data, passwdlen+1);
-	byte_stream_putstr(&frame->data, passwd);
-	byte_stream_putle8(&frame->data, '\0');
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x042e); /* shrug. */
+	byte_stream_putle16(&bs, passwdlen+1);
+	byte_stream_putstr(&bs, passwd);
+	byte_stream_putle8(&bs, '\0');
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -182,7 +186,7 @@
 int aim_icq_getallinfo(OscarData *od, const char *uin)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
@@ -195,23 +199,24 @@
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x04b2); /* shrug. */
-	byte_stream_putle32(&frame->data, atoi(uin));
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x04b2); /* shrug. */
+	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	/* Keep track of this request and the ICQ number and request ID */
 	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
@@ -226,7 +231,7 @@
 int aim_icq_getalias(OscarData *od, const char *uin)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 	struct aim_icq_info *info;
@@ -239,24 +244,25 @@
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x04ba); /* shrug. */
-	byte_stream_putle32(&frame->data, atoi(uin));
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x04ba); /* shrug. */
+	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send(conn, frame);
-
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
+	
 	/* Keep track of this request and the ICQ number and request ID */
 	info = (struct aim_icq_info *)g_new0(struct aim_icq_info, 1);
 	info->reqid = snacid;
@@ -270,7 +276,7 @@
 int aim_icq_getsimpleinfo(OscarData *od, const char *uin)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 
@@ -282,23 +288,24 @@
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 4;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x051f); /* shrug. */
-	byte_stream_putle32(&frame->data, atoi(uin));
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x051f); /* shrug. */
+	byte_stream_putle32(&bs, atoi(uin));
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -307,7 +314,7 @@
 int aim_icq_sendxmlreq(OscarData *od, const char *xml)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 
@@ -319,25 +326,26 @@
 
 	bslen = 2 + 10 + 2 + strlen(xml) + 1;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x0998); /* shrug. */
-	byte_stream_putle16(&frame->data, strlen(xml) + 1);
-	byte_stream_putraw(&frame->data, (guint8 *)xml, strlen(xml) + 1);
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x0998); /* shrug. */
+	byte_stream_putle16(&bs, strlen(xml) + 1);
+	byte_stream_putraw(&bs, (guint8 *)xml, strlen(xml) + 1);
 
-	flap_connection_send(conn, frame);
-
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 #endif
@@ -363,7 +371,7 @@
 int aim_icq_sendsms(OscarData *od, const char *name, const char *msg, const char *alias)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen, xmllen;
 	char *xml;
@@ -401,35 +409,36 @@
 
 	bslen = 36 + xmllen;
 
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
 	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
 
 	/* From libicq200-0.3.2/src/SNAC-SRV.cpp */
-	byte_stream_putle16(&frame->data, 0x1482);
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, 0x0016);
-	byte_stream_put32(&frame->data, 0x00000000);
-	byte_stream_put32(&frame->data, 0x00000000);
-	byte_stream_put32(&frame->data, 0x00000000);
-	byte_stream_put32(&frame->data, 0x00000000);
+	byte_stream_putle16(&bs, 0x1482);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, 0x0016);
+	byte_stream_put32(&bs, 0x00000000);
+	byte_stream_put32(&bs, 0x00000000);
+	byte_stream_put32(&bs, 0x00000000);
+	byte_stream_put32(&bs, 0x00000000);
 
-	byte_stream_put16(&frame->data, 0x0000);
-	byte_stream_put16(&frame->data, xmllen);
-	byte_stream_putstr(&frame->data, xml);
-	byte_stream_put8(&frame->data, 0x00);
+	byte_stream_put16(&bs, 0x0000);
+	byte_stream_put16(&bs, xmllen);
+	byte_stream_putstr(&bs, xml);
+	byte_stream_put8(&bs, 0x00);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	g_free(xml);
 	g_free(stripped);
@@ -445,7 +454,7 @@
 int aim_icq_getstatusnote(OscarData *od, const char *uin, guint8 *note_hash, guint16 note_hash_len)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	int bslen;
 
@@ -458,40 +467,39 @@
 	}
 
 	bslen = 2 + 4 + 2 + 2 + 2 + 2 + 58 + strlen(uin);
-
-	frame = flap_frame_new(od, 0x02, 10 + 4 + bslen);
+	byte_stream_new(&bs, 4 + bslen);
 
 	snacid = aim_cachesnac(od, 0x0015, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0015, 0x0002, 0x0000, snacid);
 
-	/* For simplicity, don't bother using a tlvlist */
-	byte_stream_put16(&frame->data, 0x0001);
-	byte_stream_put16(&frame->data, bslen);
+	byte_stream_put16(&bs, 0x0001);
+	byte_stream_put16(&bs, bslen);
 
-	byte_stream_putle16(&frame->data, bslen - 2);
-	byte_stream_putle32(&frame->data, atoi(od->sn));
-	byte_stream_putle16(&frame->data, 0x07d0); /* I command thee. */
-	byte_stream_putle16(&frame->data, snacid); /* eh. */
-	byte_stream_putle16(&frame->data, 0x0fa0); /* shrug. */
-	byte_stream_putle16(&frame->data, 58 + strlen(uin));
+	byte_stream_putle16(&bs, bslen - 2);
+	byte_stream_putle32(&bs, atoi(od->sn));
+	byte_stream_putle16(&bs, 0x07d0); /* I command thee. */
+	byte_stream_putle16(&bs, snacid); /* eh. */
+	byte_stream_putle16(&bs, 0x0fa0); /* shrug. */
+	byte_stream_putle16(&bs, 58 + strlen(uin));
 
-	byte_stream_put32(&frame->data, 0x05b90002);    /* don't ask */
-	byte_stream_put32(&frame->data, 0x80000000);
-	byte_stream_put32(&frame->data, 0x00000006);
-	byte_stream_put32(&frame->data, 0x00010002);
-	byte_stream_put32(&frame->data, 0x00020000);
-	byte_stream_put32(&frame->data, 0x04e30000);
-	byte_stream_put32(&frame->data, 0x00020002);
-	byte_stream_put32(&frame->data, 0x00000001);
+	byte_stream_put32(&bs, 0x05b90002);    /* don't ask */
+	byte_stream_put32(&bs, 0x80000000);
+	byte_stream_put32(&bs, 0x00000006);
+	byte_stream_put32(&bs, 0x00010002);
+	byte_stream_put32(&bs, 0x00020000);
+	byte_stream_put32(&bs, 0x04e30000);
+	byte_stream_put32(&bs, 0x00020002);
+	byte_stream_put32(&bs, 0x00000001);
 
-	byte_stream_put16(&frame->data, 24 + strlen(uin));
-	byte_stream_put32(&frame->data, 0x003c0010);
-	byte_stream_putraw(&frame->data, note_hash, 16); /* status note hash */
-	byte_stream_put16(&frame->data, 0x0032);        /* buddy uin */
-	byte_stream_put16(&frame->data, strlen(uin));
-	byte_stream_putstr(&frame->data, uin);
+	byte_stream_put16(&bs, 24 + strlen(uin));
+	byte_stream_put32(&bs, 0x003c0010);
+	byte_stream_putraw(&bs, note_hash, 16); /* status note hash */
+	byte_stream_put16(&bs, 0x0032);        /* buddy uin */
+	byte_stream_put16(&bs, strlen(uin));
+	byte_stream_putstr(&bs, uin);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0015, 0x0002, 0x000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -768,8 +776,8 @@
 			else
 			{
 				struct aim_icq_info *info;
-				guint32 data_len;
-				FlapFrame *frame;
+				ByteStream bs;
+				guint32 bslen;
 				aim_snacid_t snacid;
 				guchar cookie[8];
 
@@ -783,84 +791,83 @@
 					break;
 				}
 
-				data_len = 13 + strlen(uin) + 30 + 6 + 4 + 55 + 85 + 4;
-				frame = flap_frame_new(od, 0x0002, 10 + 4 + data_len);
+				bslen = 13 + strlen(uin) + 30 + 6 + 4 + 55 + 85 + 4;
+				byte_stream_new(&bs, 4 + bslen);
+
 				snacid = aim_cachesnac(od, 0x0004, 0x0006, 0x0000, NULL, 0);
 
-				aim_putsnac(&frame->data, 0x0004, 0x0006, 0x0000, snacid);
-
 				aim_icbm_makecookie(cookie);
 
-				byte_stream_putraw(&frame->data, cookie, 8); /* ICBM cookie */
-				byte_stream_put16(&frame->data, 0x0002); /* message channel */
-				byte_stream_put8(&frame->data, strlen(uin)); /* uin */
-				byte_stream_putstr(&frame->data, uin);
+				byte_stream_putraw(&bs, cookie, 8); /* ICBM cookie */
+				byte_stream_put16(&bs, 0x0002); /* message channel */
+				byte_stream_put8(&bs, strlen(uin)); /* uin */
+				byte_stream_putstr(&bs, uin);
 
-				byte_stream_put16(&frame->data, 0x0005); /* rendez vous data */
-				byte_stream_put16(&frame->data, 0x00b2);
-				byte_stream_put16(&frame->data, 0x0000); /* request */
-				byte_stream_putraw(&frame->data, cookie, 8); /* ICBM cookie */
-				byte_stream_put32(&frame->data, 0x09461349); /* ICQ server relaying */
-				byte_stream_put16(&frame->data, 0x4c7f);
-				byte_stream_put16(&frame->data, 0x11d1);
-				byte_stream_put32(&frame->data, 0x82224445);
-				byte_stream_put32(&frame->data, 0x53540000);
+				byte_stream_put16(&bs, 0x0005); /* rendez vous data */
+				byte_stream_put16(&bs, 0x00b2);
+				byte_stream_put16(&bs, 0x0000); /* request */
+				byte_stream_putraw(&bs, cookie, 8); /* ICBM cookie */
+				byte_stream_put32(&bs, 0x09461349); /* ICQ server relaying */
+				byte_stream_put16(&bs, 0x4c7f);
+				byte_stream_put16(&bs, 0x11d1);
+				byte_stream_put32(&bs, 0x82224445);
+				byte_stream_put32(&bs, 0x53540000);
 
-				byte_stream_put16(&frame->data, 0x000a); /* unknown TLV */
-				byte_stream_put16(&frame->data, 0x0002);
-				byte_stream_put16(&frame->data, 0x0001);
+				byte_stream_put16(&bs, 0x000a); /* unknown TLV */
+				byte_stream_put16(&bs, 0x0002);
+				byte_stream_put16(&bs, 0x0001);
 
-				byte_stream_put16(&frame->data, 0x000f); /* unknown TLV */
-				byte_stream_put16(&frame->data, 0x0000);
+				byte_stream_put16(&bs, 0x000f); /* unknown TLV */
+				byte_stream_put16(&bs, 0x0000);
 
-				byte_stream_put16(&frame->data, 0x2711); /* extended data */
-				byte_stream_put16(&frame->data, 0x008a);
-				byte_stream_putle16(&frame->data, 0x001b); /* length */
-				byte_stream_putle16(&frame->data, 0x0009); /* version */
-				byte_stream_putle32(&frame->data, 0x00000000); /* plugin: none */
-				byte_stream_putle32(&frame->data, 0x00000000);
-				byte_stream_putle32(&frame->data, 0x00000000);
-				byte_stream_putle32(&frame->data, 0x00000000);
-				byte_stream_putle16(&frame->data, 0x0000); /* unknown */
-				byte_stream_putle32(&frame->data, 0x00000000); /* client capabilities flags */
-				byte_stream_put8(&frame->data, 0x00); /* unknown */
-				byte_stream_putle16(&frame->data, 0x0064); /* downcounter? */
-				byte_stream_putle16(&frame->data, 0x000e); /* length */
-				byte_stream_putle16(&frame->data, 0x0064); /* downcounter? */
-				byte_stream_putle32(&frame->data, 0x00000000); /* unknown */
-				byte_stream_putle32(&frame->data, 0x00000000);
-				byte_stream_putle32(&frame->data, 0x00000000);
-				byte_stream_put8(&frame->data, 0x1a); /* message type: plugin message descibed by text string */
-				byte_stream_put8(&frame->data, 0x00); /* message flags */
-				byte_stream_putle16(&frame->data, 0x0000); /* status code */
-				byte_stream_putle16(&frame->data, 0x0001); /* priority code */
-				byte_stream_putle16(&frame->data, 0x0000); /* text length */
+				byte_stream_put16(&bs, 0x2711); /* extended data */
+				byte_stream_put16(&bs, 0x008a);
+				byte_stream_putle16(&bs, 0x001b); /* length */
+				byte_stream_putle16(&bs, 0x0009); /* version */
+				byte_stream_putle32(&bs, 0x00000000); /* plugin: none */
+				byte_stream_putle32(&bs, 0x00000000);
+				byte_stream_putle32(&bs, 0x00000000);
+				byte_stream_putle32(&bs, 0x00000000);
+				byte_stream_putle16(&bs, 0x0000); /* unknown */
+				byte_stream_putle32(&bs, 0x00000000); /* client capabilities flags */
+				byte_stream_put8(&bs, 0x00); /* unknown */
+				byte_stream_putle16(&bs, 0x0064); /* downcounter? */
+				byte_stream_putle16(&bs, 0x000e); /* length */
+				byte_stream_putle16(&bs, 0x0064); /* downcounter? */
+				byte_stream_putle32(&bs, 0x00000000); /* unknown */
+				byte_stream_putle32(&bs, 0x00000000);
+				byte_stream_putle32(&bs, 0x00000000);
+				byte_stream_put8(&bs, 0x1a); /* message type: plugin message descibed by text string */
+				byte_stream_put8(&bs, 0x00); /* message flags */
+				byte_stream_putle16(&bs, 0x0000); /* status code */
+				byte_stream_putle16(&bs, 0x0001); /* priority code */
+				byte_stream_putle16(&bs, 0x0000); /* text length */
 
-				byte_stream_put8(&frame->data, 0x3a); /* message dump */
-				byte_stream_put32(&frame->data, 0x00811a18);
-				byte_stream_put32(&frame->data, 0xbc0e6c18);
-				byte_stream_put32(&frame->data, 0x47a5916f);
-				byte_stream_put32(&frame->data, 0x18dcc76f);
-				byte_stream_put32(&frame->data, 0x1a010013);
-				byte_stream_put32(&frame->data, 0x00000041);
-				byte_stream_put32(&frame->data, 0x77617920);
-				byte_stream_put32(&frame->data, 0x53746174);
-				byte_stream_put32(&frame->data, 0x7573204d);
-				byte_stream_put32(&frame->data, 0x65737361);
-				byte_stream_put32(&frame->data, 0x67650100);
-				byte_stream_put32(&frame->data, 0x00000000);
-				byte_stream_put32(&frame->data, 0x00000000);
-				byte_stream_put32(&frame->data, 0x00000000);
-				byte_stream_put32(&frame->data, 0x00000015);
-				byte_stream_put32(&frame->data, 0x00000000);
-				byte_stream_put32(&frame->data, 0x0000000d);
-				byte_stream_put32(&frame->data, 0x00000074);
-				byte_stream_put32(&frame->data, 0x6578742f);
-				byte_stream_put32(&frame->data, 0x782d616f);
-				byte_stream_put32(&frame->data, 0x6c727466);
+				byte_stream_put8(&bs, 0x3a); /* message dump */
+				byte_stream_put32(&bs, 0x00811a18);
+				byte_stream_put32(&bs, 0xbc0e6c18);
+				byte_stream_put32(&bs, 0x47a5916f);
+				byte_stream_put32(&bs, 0x18dcc76f);
+				byte_stream_put32(&bs, 0x1a010013);
+				byte_stream_put32(&bs, 0x00000041);
+				byte_stream_put32(&bs, 0x77617920);
+				byte_stream_put32(&bs, 0x53746174);
+				byte_stream_put32(&bs, 0x7573204d);
+				byte_stream_put32(&bs, 0x65737361);
+				byte_stream_put32(&bs, 0x67650100);
+				byte_stream_put32(&bs, 0x00000000);
+				byte_stream_put32(&bs, 0x00000000);
+				byte_stream_put32(&bs, 0x00000000);
+				byte_stream_put32(&bs, 0x00000015);
+				byte_stream_put32(&bs, 0x00000000);
+				byte_stream_put32(&bs, 0x0000000d);
+				byte_stream_put32(&bs, 0x00000074);
+				byte_stream_put32(&bs, 0x6578742f);
+				byte_stream_put32(&bs, 0x782d616f);
+				byte_stream_put32(&bs, 0x6c727466);
 
-				byte_stream_put16(&frame->data, 0x0003); /* server ACK requested */
-				byte_stream_put16(&frame->data, 0x0000);
+				byte_stream_put16(&bs, 0x0003); /* server ACK requested */
+				byte_stream_put16(&bs, 0x0000);
 
 				info->uin = atoi(uin);
 				info->status_note_title = status_note_title;
@@ -870,7 +877,9 @@
 				info->next = od->icq_info;
 				od->icq_info = info;
 
-				flap_connection_send(conn, frame);
+				flap_connection_send_snac(od, conn, 0x0004, 0x0006, 0x0000, snacid, &bs);
+
+				byte_stream_destroy(&bs);
 			}
 
 			g_free(uin);
--- a/libpurple/protocols/oscar/family_locate.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_locate.c	Mon Apr 28 19:24:18 2008 +0000
@@ -1047,7 +1047,7 @@
 				  const char *awaymsg_encoding, const gchar *awaymsg, const int awaymsg_len)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 	char *encoding;
@@ -1092,15 +1092,16 @@
 			aim_tlvlist_add_noval(&tlvlist, 0x0004);
 	}
 
-	frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist));
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
 	snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid);
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0002, 0x0004, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1112,7 +1113,7 @@
 aim_locate_setcaps(OscarData *od, guint32 caps)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -1121,15 +1122,16 @@
 
 	aim_tlvlist_add_caps(&tlvlist, 0x0005, caps);
 
-	frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist));
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
 	snacid = aim_cachesnac(od, 0x0002, 0x0004, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0002, 0x004, 0x0000, snacid);
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0002, 0x0004, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1147,22 +1149,23 @@
 aim_locate_getinfo(OscarData *od, const char *sn, guint16 infotype)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 12+1+strlen(sn));
+	byte_stream_new(&bs, 2+1+strlen(sn));
 
 	snacid = aim_cachesnac(od, 0x0002, 0x0005, 0x0000, NULL, 0);
 
-	aim_putsnac(&frame->data, 0x0002, 0x0005, 0x0000, snacid);
-	byte_stream_put16(&frame->data, infotype);
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+	byte_stream_put16(&bs, infotype);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0002, 0x0005, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1238,7 +1241,7 @@
 int aim_locate_setdirinfo(OscarData *od, const char *first, const char *middle, const char *last, const char *maiden, const char *nickname, const char *street, const char *city, const char *state, const char *zip, int country, guint16 privacy)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -1269,15 +1272,16 @@
 	if (street)
 		aim_tlvlist_add_str(&tlvlist, 0x0021, street);
 
-	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist));
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
 	snacid = aim_cachesnac(od, 0x0002, 0x0009, 0x0000, NULL, 0);
 
-	aim_putsnac(&frame->data, 0x0002, 0x0009, 0x0000, snacid);
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0002, 0x0009, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1288,7 +1292,7 @@
 int aim_locate_000b(OscarData *od, const char *sn)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 		return -EINVAL;
@@ -1296,15 +1300,16 @@
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+1+strlen(sn));
+	byte_stream_new(&bs, 1+strlen(sn));
 
 	snacid = aim_cachesnac(od, 0x0002, 0x000b, 0x0000, NULL, 0);
 
-	aim_putsnac(&frame->data, 0x0002, 0x000b, 0x0000, snacid);
-	byte_stream_put8(&frame->data, strlen(sn));
-	byte_stream_putstr(&frame->data, sn);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, 0x0002, 0x000b, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -1319,7 +1324,7 @@
 aim_locate_setinterests(OscarData *od, const char *interest1, const char *interest2, const char *interest3, const char *interest4, const char *interest5, guint16 privacy)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -1340,16 +1345,16 @@
 	if (interest5)
 		aim_tlvlist_add_str(&tlvlist, 0x0000b, interest5);
 
-	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist));
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
 	snacid = aim_cachesnac(od, 0x0002, 0x000f, 0x0000, NULL, 0);
 
-	aim_putsnac(&frame->data, 0x0002, 0x000f, 0x0000, 0);
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
-
+	flap_connection_send_snac(od, conn, 0x0002, 0x000f, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
 	return 0;
 }
 
@@ -1369,21 +1374,21 @@
 aim_locate_getinfoshort(OscarData *od, const char *sn, guint32 flags)
 {
 	FlapConnection *conn;
-	ByteStream data;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !(conn = flap_connection_findbygroup(od, SNAC_FAMILY_LOCATE)) || !sn)
 		return -EINVAL;
 
-	byte_stream_new(&data, 4 + 1 + strlen(sn));
-	byte_stream_put32(&data, flags);
-	byte_stream_put8(&data, strlen(sn));
-	byte_stream_putstr(&data, sn);
+	byte_stream_new(&bs, 4 + 1 + strlen(sn));
+	byte_stream_put32(&bs, flags);
+	byte_stream_put8(&bs, strlen(sn));
+	byte_stream_putstr(&bs, sn);
 
 	snacid = aim_cachesnac(od, 0x0002, 0x0015, 0x0000, sn, strlen(sn)+1);
-	flap_connection_send_snac(od, conn, 0x0002, 0x0015, 0x0000, snacid, &data);
+	flap_connection_send_snac(od, conn, 0x0002, 0x0015, 0x0000, snacid, &bs);
 
-	g_free(data.data);
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
--- a/libpurple/protocols/oscar/family_odir.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_odir.c	Mon Apr 28 19:24:18 2008 +0000
@@ -41,7 +41,7 @@
 int aim_odir_email(OscarData *od, const char *region, const char *email)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -53,14 +53,15 @@
 	aim_tlvlist_add_16(&tlvlist, 0x000a, 0x0001); /* Type of search */
 	aim_tlvlist_add_str(&tlvlist, 0x0005, email);
 
-	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist));
-	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid);
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x000f, 0x0002, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 
 	return 0;
 }
@@ -89,7 +90,7 @@
 int aim_odir_name(OscarData *od, const char *region, const char *first, const char *middle, const char *last, const char *maiden, const char *nick, const char *city, const char *state, const char *country, const char *zip, const char *address)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -120,15 +121,16 @@
 	if (address)
 		aim_tlvlist_add_str(&tlvlist, 0x0021, address);
 
-	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist));
-	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid);
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x000f, 0x0002, 0x0000, snacid, &bs);
 
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -143,7 +145,7 @@
 int aim_odir_interest(OscarData *od, const char *region, const char *interest)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -156,15 +158,16 @@
 	if (interest)
 		aim_tlvlist_add_str(&tlvlist, 0x0001, interest);
 
-	frame = flap_frame_new(od, 0x02, 10+aim_tlvlist_size(tlvlist));
-	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x000f, 0x0002, 0x0000, snacid);
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
-
+	snacid = aim_cachesnac(od, 0x000f, 0x0002, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x000f, 0x0002, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
--- a/libpurple/protocols/oscar/family_oservice.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_oservice.c	Mon Apr 28 19:24:18 2008 +0000
@@ -31,14 +31,11 @@
 void
 aim_clientready(OscarData *od, FlapConnection *conn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *cur;
 
-	frame = flap_frame_new(od, 0x02, 1152);
-
-	snacid = aim_cachesnac(od, 0x0001, 0x0002, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0001, 0x0002, 0x0000, snacid);
+	byte_stream_new(&bs, 1142);
 
 	/*
 	 * Send only the tool versions that the server cares about (that it
@@ -50,14 +47,17 @@
 
 		if ((mod = aim__findmodulebygroup(od, GPOINTER_TO_UINT(cur->data))))
 		{
-			byte_stream_put16(&frame->data, mod->family);
-			byte_stream_put16(&frame->data, mod->version);
-			byte_stream_put16(&frame->data, mod->toolid);
-			byte_stream_put16(&frame->data, mod->toolversion);
+			byte_stream_put16(&bs, mod->family);
+			byte_stream_put16(&bs, mod->version);
+			byte_stream_put16(&bs, mod->toolid);
+			byte_stream_put16(&bs, mod->toolversion);
 		}
 	}
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x0002, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0001, 0x0002, 0x0000, snacid, &bs);
+	
+	byte_stream_destroy(&bs);
 }
 
 /*
@@ -121,7 +121,7 @@
 aim_chat_join(OscarData *od, guint16 exchange, const char *roomname, guint16 instance)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 	struct chatsnacinfo csi;
@@ -130,27 +130,27 @@
 	if (!conn || !roomname || !strlen(roomname))
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 512);
+	byte_stream_new(&bs, 502);
 
 	memset(&csi, 0, sizeof(csi));
 	csi.exchange = exchange;
 	strncpy(csi.name, roomname, sizeof(csi.name));
 	csi.instance = instance;
 
-	snacid = aim_cachesnac(od, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
-	aim_putsnac(&frame->data, 0x0001, 0x0004, 0x0000, snacid);
-
 	/*
 	 * Requesting service chat (0x000e)
 	 */
-	byte_stream_put16(&frame->data, 0x000e);
+	byte_stream_put16(&bs, 0x000e);
 
 	aim_tlvlist_add_chatroom(&tlvlist, 0x0001, exchange, roomname, instance);
-	aim_tlvlist_write(&frame->data, &tlvlist);
+	aim_tlvlist_write(&bs, &tlvlist);
 	aim_tlvlist_free(tlvlist);
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x0004, 0x0000, &csi, sizeof(csi));
+	flap_connection_send_snac(od, conn, 0x0001, 0x0004, 0x0000, snacid, &bs);
 
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -376,46 +376,46 @@
 void
 aim_srv_rates_addparam(OscarData *od, FlapConnection *conn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tmp;
 
-	frame = flap_frame_new(od, 0x02, 512);
-
-	snacid = aim_cachesnac(od, 0x0001, 0x0008, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0001, 0x0008, 0x0000, snacid);
+	byte_stream_new(&bs, 502);
 
 	for (tmp = conn->rateclasses; tmp != NULL; tmp = tmp->next)
 	{
 		struct rateclass *rateclass;
 		rateclass = tmp->data;
-		byte_stream_put16(&frame->data, rateclass->classid);
+		byte_stream_put16(&bs, rateclass->classid);
 	}
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x0008, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0001, 0x0008, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);	
 }
 
 /* Subtype 0x0009 - Delete Rate Parameter */
 void
 aim_srv_rates_delparam(OscarData *od, FlapConnection *conn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tmp;
 
-	frame = flap_frame_new(od, 0x02, 512);
-
-	snacid = aim_cachesnac(od, 0x0001, 0x0009, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0001, 0x0009, 0x0000, snacid);
+	byte_stream_new(&bs, 502);
 
 	for (tmp = conn->rateclasses; tmp != NULL; tmp = tmp->next)
 	{
 		struct rateclass *rateclass;
 		rateclass = tmp->data;
-		byte_stream_put16(&frame->data, rateclass->classid);
+		byte_stream_put16(&bs, rateclass->classid);
 	}
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x0009, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0001, 0x0009, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);	
 }
 
 /* Subtype 0x000a - Rate Change */
@@ -489,14 +489,11 @@
 void
 aim_srv_sendpauseack(OscarData *od, FlapConnection *conn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *cur;
 
-	frame = flap_frame_new(od, 0x02, 1024);
-
-	snacid = aim_cachesnac(od, 0x0001, 0x000c, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0001, 0x000c, 0x0000, snacid);
+	byte_stream_new(&bs, 1014);
 
 	/*
 	 * This list should have all the groups that the original
@@ -504,9 +501,12 @@
 	 * we want them all back after the migration.
 	 */
 	for (cur = conn->groups; cur != NULL; cur = cur->next)
-		byte_stream_put16(&frame->data, GPOINTER_TO_UINT(cur->data));
+		byte_stream_put16(&bs, GPOINTER_TO_UINT(cur->data));
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x000c, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0001, 0x000c, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /* Subtype 0x000d - Service Resume */
@@ -732,14 +732,11 @@
 void
 aim_srv_setversions(OscarData *od, FlapConnection *conn)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *cur;
 
-	frame = flap_frame_new(od, 0x02, 1152);
-
-	snacid = aim_cachesnac(od, 0x0001, 0x0017, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0001, 0x0017, 0x0000, snacid);
+	byte_stream_new(&bs, 1142);
 
 	/*
 	 * Send only the versions that the server cares about (that it
@@ -751,12 +748,15 @@
 
 		if ((mod = aim__findmodulebygroup(od, GPOINTER_TO_UINT(cur->data))))
 		{
-			byte_stream_put16(&frame->data, mod->family);
-			byte_stream_put16(&frame->data, mod->version);
+			byte_stream_put16(&bs, mod->family);
+			byte_stream_put16(&bs, mod->version);
 		}
 	}
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x0017, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0001, 0x0017, 0x0000, snacid, &bs);
+
+	byte_stream_destroy(&bs);
 }
 
 /* Subtype 0x0018 - Host versions */
@@ -803,7 +803,7 @@
 		gboolean setavailmsg, const char *availmsg, const char *itmsurl)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 	GSList *tlvlist = NULL;
 
@@ -853,19 +853,19 @@
 
 		aim_tlvlist_add_raw(&tlvlist, 0x001d,
 				byte_stream_curpos(&tmpbs), tmpbs.data);
-		g_free(tmpbs.data);
+		byte_stream_destroy(&tmpbs);
 	}
 
-	frame = flap_frame_new(od, 0x02, 10 + aim_tlvlist_size(tlvlist));
+	byte_stream_new(&bs, aim_tlvlist_size(tlvlist));
+
+	aim_tlvlist_write(&bs, &tlvlist);
+	aim_tlvlist_free(tlvlist);
 
 	snacid = aim_cachesnac(od, 0x0001, 0x001e, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, 0x0001, 0x001e, 0x0000, snacid);
+	flap_connection_send_snac(od, conn, 0x0001, 0x001e, 0x0000, snacid, &bs);
 
-	aim_tlvlist_write(&frame->data, &tlvlist);
-	aim_tlvlist_free(tlvlist);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
@@ -937,22 +937,19 @@
 int
 aim_sendmemblock(OscarData *od, FlapConnection *conn, guint32 offset, guint32 len, const guint8 *buf, guint8 flag)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!od || !conn)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+2+16);
+	byte_stream_new(&bs, 2+16);
 
-	snacid = aim_cachesnac(od, 0x0001, 0x0020, 0x0000, NULL, 0);
-
-	aim_putsnac(&frame->data, 0x0001, 0x0020, 0x0000, snacid);
-	byte_stream_put16(&frame->data, 0x0010); /* md5 is always 16 bytes */
+	byte_stream_put16(&bs, 0x0010); /* md5 is always 16 bytes */
 
 	if ((flag == AIM_SENDMEMBLOCK_FLAG_ISHASH) && buf && (len == 0x10)) { /* we're getting a hash */
 
-		byte_stream_putraw(&frame->data, buf, 0x10);
+		byte_stream_putraw(&bs, buf, 0x10);
 
 	} else if (buf && (len > 0)) { /* use input buffer */
 		PurpleCipher *cipher;
@@ -966,7 +963,7 @@
 		purple_cipher_context_digest(context, 16, digest, NULL);
 		purple_cipher_context_destroy(context);
 
-		byte_stream_putraw(&frame->data, digest, 0x10);
+		byte_stream_putraw(&bs, digest, 0x10);
 
 	} else if (len == 0) { /* no length, just hash NULL (buf is optional) */
 		PurpleCipher *cipher;
@@ -985,7 +982,7 @@
 		purple_cipher_context_digest(context, 16, digest, NULL);
 		purple_cipher_context_destroy(context);
 
-		byte_stream_putraw(&frame->data, digest, 0x10);
+		byte_stream_putraw(&bs, digest, 0x10);
 
 	} else {
 
@@ -999,15 +996,15 @@
 		if ((offset == 0x03ffffff) && (len == 0x03ffffff)) {
 
 #if 1 /* with "AnrbnrAqhfzcd" */
-			byte_stream_put32(&frame->data, 0x44a95d26);
-			byte_stream_put32(&frame->data, 0xd2490423);
-			byte_stream_put32(&frame->data, 0x93b8821f);
-			byte_stream_put32(&frame->data, 0x51c54b01);
+			byte_stream_put32(&bs, 0x44a95d26);
+			byte_stream_put32(&bs, 0xd2490423);
+			byte_stream_put32(&bs, 0x93b8821f);
+			byte_stream_put32(&bs, 0x51c54b01);
 #else /* no filename */
-			byte_stream_put32(&frame->data, 0x1df8cbae);
-			byte_stream_put32(&frame->data, 0x5523b839);
-			byte_stream_put32(&frame->data, 0xa0e10db3);
-			byte_stream_put32(&frame->data, 0xa46d3b39);
+			byte_stream_put32(&bs, 0x1df8cbae);
+			byte_stream_put32(&bs, 0x5523b839);
+			byte_stream_put32(&bs, 0xa0e10db3);
+			byte_stream_put32(&bs, 0xa46d3b39);
 #endif
 
 		} else
@@ -1015,8 +1012,11 @@
 
 	}
 
-	flap_connection_send(conn, frame);
+	snacid = aim_cachesnac(od, 0x0001, 0x0020, 0x0000, NULL, 0);
+	flap_connection_send_snac(od, conn, 0x0001, 0x0020, 0x0000, snacid, &bs);
 
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
--- a/libpurple/protocols/oscar/family_userlookup.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/family_userlookup.c	Mon Apr 28 19:24:18 2008 +0000
@@ -62,7 +62,7 @@
 int aim_search_address(OscarData *od, const char *address)
 {
 	FlapConnection *conn;
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	conn = flap_connection_findbygroup(od, SNAC_FAMILY_USERLOOKUP);
@@ -70,15 +70,15 @@
 	if (!conn || !address)
 		return -EINVAL;
 
-	frame = flap_frame_new(od, 0x02, 10+strlen(address));
+	byte_stream_new(&bs, strlen(address));
+
+	byte_stream_putstr(&bs, address);
 
 	snacid = aim_cachesnac(od, 0x000a, 0x0002, 0x0000, address, strlen(address)+1);
-	aim_putsnac(&frame->data, 0x000a, 0x0002, 0x0000, snacid);
+	flap_connection_send_snac(od, conn, 0x000a, 0x0002, 0x0000, snacid, &bs);
 
-	byte_stream_putstr(&frame->data, address);
-
-	flap_connection_send(conn, frame);
-
+	byte_stream_destroy(&bs);
+	
 	return 0;
 }
 
--- a/libpurple/protocols/oscar/flap_connection.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/flap_connection.c	Mon Apr 28 19:24:18 2008 +0000
@@ -115,6 +115,7 @@
 	conn = data;
 	gettimeofday(&now, NULL);
 
+	purple_debug_info("oscar", "Attempting to send %i queued SNACs for %p\n", g_queue_get_length(conn->queued_snacs), conn);
 	while (!g_queue_is_empty(conn->queued_snacs))
 	{
 		QueuedSnac *queued_snac;
@@ -189,6 +190,8 @@
 		/* (Add 100ms padding to account for inaccuracies in the calculation) */
 		if (new_current < rateclass->alert + 100)
 		{
+			purple_debug_info("oscar", "Current rate for conn %p would be %u, but we alert at %u; enqueueing\n", conn, new_current, (rateclass->alert + 100));
+
 			enqueue = TRUE;
 		}
 		else
@@ -197,6 +200,8 @@
 			rateclass->last.tv_sec = now.tv_sec;
 			rateclass->last.tv_usec = now.tv_usec;
 		}
+	} else {
+		purple_debug_warning("oscar", "No rate class found for family %u subtype %u\n", family, subtype);
 	}
 
 	if (enqueue)
@@ -983,7 +988,7 @@
 	byte_stream_rewind(&bs);
 	flap_connection_send_byte_stream(&bs, conn, bslen);
 
-	g_free(bs.data); /* XXX byte_stream_free */
+	byte_stream_destroy(&bs);
 }
 
 void
--- a/libpurple/protocols/oscar/misc.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/misc.c	Mon Apr 28 19:24:18 2008 +0000
@@ -42,11 +42,7 @@
 	FlapFrame *frame;
 	aim_snacid_t snacid = 0x00000000;
 
-	frame = flap_frame_new(od, 0x02, 10);
-
-	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
-
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
 }
 
 void
@@ -55,18 +51,15 @@
 	FlapFrame *frame;
 	aim_snacid_t snacid;
 
-	frame = flap_frame_new(od, 0x02, 10);
+	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
 
-	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
-	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
-
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
 }
 
 void
 aim_genericreq_l(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint32 *longdata)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!longdata)
@@ -75,20 +68,21 @@
 		return;
 	}
 
-	frame = flap_frame_new(od, 0x02, 10+4);
+	byte_stream_new(&bs, 4);
 
 	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
 
-	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
-	byte_stream_put32(&frame->data, *longdata);
+	byte_stream_put32(&bs, *longdata);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
+
+	byte_stream_destroy(&bs);
 }
 
 void
 aim_genericreq_s(OscarData *od, FlapConnection *conn, guint16 family, guint16 subtype, guint16 *shortdata)
 {
-	FlapFrame *frame;
+	ByteStream bs;
 	aim_snacid_t snacid;
 
 	if (!shortdata)
@@ -97,14 +91,15 @@
 		return;
 	}
 
-	frame = flap_frame_new(od, 0x02, 10+2);
+	byte_stream_new(&bs, 2);
 
 	snacid = aim_cachesnac(od, family, subtype, 0x0000, NULL, 0);
 
-	aim_putsnac(&frame->data, family, subtype, 0x0000, snacid);
-	byte_stream_put16(&frame->data, *shortdata);
+	byte_stream_put16(&bs, *shortdata);
 
-	flap_connection_send(conn, frame);
+	flap_connection_send_snac(od, conn, family, subtype, 0x0000, snacid, NULL);
+
+	byte_stream_destroy(&bs);
 }
 
 /*
--- a/libpurple/protocols/oscar/odc.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/odc.c	Mon Apr 28 19:24:18 2008 +0000
@@ -121,7 +121,7 @@
 
 	peer_connection_send(conn, &bs);
 
-	g_free(bs.data);
+	byte_stream_destroy(&bs);
 }
 
 /**
--- a/libpurple/protocols/oscar/oft.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/oft.c	Mon Apr 28 19:24:18 2008 +0000
@@ -304,7 +304,7 @@
 
 	peer_connection_send(conn, &bs);
 
-	g_free(bs.data);
+	byte_stream_destroy(&bs);
 }
 
 void
--- a/libpurple/protocols/oscar/oscar.h	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/oscar.h	Mon Apr 28 19:24:18 2008 +0000
@@ -1549,6 +1549,7 @@
 /* bstream.c */
 int byte_stream_new(ByteStream *bs, guint32 len);
 int byte_stream_init(ByteStream *bs, guint8 *data, int len);
+void byte_stream_destroy(ByteStream *bs);
 int byte_stream_empty(ByteStream *bs);
 int byte_stream_curpos(ByteStream *bs);
 int byte_stream_setpos(ByteStream *bs, unsigned int off);
--- a/libpurple/protocols/oscar/peer_proxy.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/peer_proxy.c	Mon Apr 28 19:24:18 2008 +0000
@@ -48,7 +48,7 @@
 
 	peer_connection_send(conn, &bs);
 
-	g_free(bs.data);
+	byte_stream_destroy(&bs);
 }
 
 /**
--- a/libpurple/protocols/oscar/tlv.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/tlv.c	Mon Apr 28 19:24:18 2008 +0000
@@ -231,13 +231,13 @@
 	aim_tlvlist_write(&bs2, &two);
 
 	if (memcmp(bs1.data, bs2.data, bs1.len)) {
-		g_free(bs1.data);
-		g_free(bs2.data);
+		byte_stream_destroy(&bs1);
+		byte_stream_destroy(&bs2);
 		return 1;
 	}
 
-	g_free(bs1.data);
-	g_free(bs2.data);
+	byte_stream_destroy(&bs1);
+	byte_stream_destroy(&bs2);
 
 	return 0;
 }
@@ -445,7 +445,7 @@
 
 	len = aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
 
-	g_free(bs.data);
+	byte_stream_destroy(&bs);
 
 	return len;
 }
@@ -494,7 +494,7 @@
 
 	aim_tlvlist_add_raw(list, type, byte_stream_curpos(&bs), bs.data);
 
-	g_free(bs.data);
+	byte_stream_destroy(&bs);
 
 	return buflen;
 }
--- a/libpurple/protocols/oscar/util.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/oscar/util.c	Mon Apr 28 19:24:18 2008 +0000
@@ -156,7 +156,7 @@
 		return FALSE;
 
 	for (i = 0; sn[i] != '\0'; i++) {
-		if (!isalnum(sn[i]) && (sn[i] != ' ') && (sn[i] != '.'))
+		if (!isalnum(sn[i]) && (sn[i] != ' '))
 			return FALSE;
 	}
 
--- a/libpurple/protocols/silc/silc.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/silc/silc.c	Mon Apr 28 19:24:18 2008 +0000
@@ -380,14 +380,6 @@
 
 	client = sg->client;
 
-	/* Progress */
-	if (params.detach_data) {
-		purple_connection_update_progress(gc, _("Resuming session"), 2, 5);
-		sg->resuming = TRUE;
-	} else {
-		purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
-	}
-
 	/* Get session detachment data, if available */
 	memset(&params, 0, sizeof(params));
 	dfile = silcpurple_session_file(purple_account_get_username(sg->account));
@@ -397,6 +389,14 @@
 	params.ignore_requested_attributes = FALSE;
 	params.pfs = purple_account_get_bool(sg->account, "pfs", FALSE);
 
+	/* Progress */
+	if (params.detach_data) {
+		purple_connection_update_progress(gc, _("Resuming session"), 2, 5);
+		sg->resuming = TRUE;
+	} else {
+		purple_connection_update_progress(gc, _("Performing key exchange"), 2, 5);
+	}
+
 	/* Perform SILC Key Exchange. */
 	silc_client_key_exchange(sg->client, &params, sg->public_key,
 				 sg->private_key, stream, SILC_CONN_SERVER,
@@ -433,6 +433,83 @@
 				      silcpurple_stream_created, gc);
 }
 
+static void silcpurple_continue_running(SilcPurple sg)
+{
+	PurpleConnection *gc = sg->gc;
+	PurpleAccount *account = purple_connection_get_account(gc);
+
+	/* Connect to the SILC server */
+	if (purple_proxy_connect(gc, account,
+				 purple_account_get_string(account, "server",
+							   "silc.silcnet.org"),
+				 purple_account_get_int(account, "port", 706),
+				 silcpurple_login_connected, gc) == NULL)
+	{
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+		                             _("Unable to create connection"));
+		gc->proto_data = NULL;
+		silc_free(sg);
+		return;
+	}
+}
+
+static void silcpurple_got_password_cb(PurpleConnection *gc, PurpleRequestFields *fields)
+{
+	SilcPurple sg = (SilcPurple)gc->proto_data;
+	PurpleAccount *account = purple_connection_get_account(gc);
+	char pkd[256], prd[256];
+	const char *password;
+	gboolean remember;
+
+	/* The password prompt dialog doesn't get disposed if the account disconnects */
+	if (!PURPLE_CONNECTION_IS_VALID(gc))
+		return;
+
+	password = purple_request_fields_get_string(fields, "password");
+	remember = purple_request_fields_get_bool(fields, "remember");
+
+	if (!password || !*password)
+	{
+		purple_notify_error(gc, NULL, _("Password is required to sign on."), NULL);
+		gc->proto_data = NULL;
+		silc_free(sg);
+		return;
+	}
+
+	if (remember)
+		purple_account_set_remember_password(account, TRUE);
+
+	purple_account_set_password(account, password);
+
+	/* Load SILC key pair */
+	g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
+	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
+	if (!silc_load_key_pair((char *)purple_account_get_string(account, "public-key", pkd),
+				(char *)purple_account_get_string(account, "private-key", prd),
+				password,
+				&sg->public_key, &sg->private_key)) {
+		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+		                             _("Could not load SILC key pair"));
+		gc->proto_data = NULL;
+		silc_free(sg);
+		return;
+	}
+	silcpurple_continue_running(sg);
+}
+
+static void silcpurple_no_password_cb(PurpleConnection *gc, PurpleRequestFields *fields)
+{
+	SilcPurple sg;
+	/* The password prompt dialog doesn't get disposed if the account disconnects */
+	if (!PURPLE_CONNECTION_IS_VALID(gc))
+		return;
+	sg = gc->proto_data;
+	purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
+			_("Could not load SILC key pair"));
+	gc->proto_data = NULL;
+	silc_free(sg);
+}
+
 static void silcpurple_running(SilcClient client, void *context)
 {
 	SilcPurple sg = context;
@@ -451,26 +528,18 @@
 				(char *)purple_account_get_string(account, "private-key", prd),
 				(gc->password == NULL) ? "" : gc->password,
 				&sg->public_key, &sg->private_key)) {
+		if (!purple_account_get_password(account)) {
+			purple_account_request_password(account, G_CALLBACK(silcpurple_got_password_cb),
+											G_CALLBACK(silcpurple_no_password_cb), gc);
+			return;
+		}
 		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
 		                             _("Could not load SILC key pair"));
 		gc->proto_data = NULL;
 		silc_free(sg);
 		return;
 	}
-
-	/* Connect to the SILC server */
-	if (purple_proxy_connect(gc, account,
-				 purple_account_get_string(account, "server",
-							   "silc.silcnet.org"),
-				 purple_account_get_int(account, "port", 706),
-				 silcpurple_login_connected, gc) == NULL)
-	{
-		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-		                             _("Unable to create connection"));
-		gc->proto_data = NULL;
-		silc_free(sg);
-		return;
-	}
+	silcpurple_continue_running(sg);
 }
 
 static void
@@ -550,8 +619,12 @@
 		                             _("Cannot initialize SILC protocol"));
 		gc->proto_data = NULL;
 		silc_free(sg);
+		free(hostname);
+		free(username);
 		return;
 	}
+	free(hostname);
+	free(username);
 
 	/* Check the ~/.silc dir and create it, and new key pair if necessary. */
 	if (!silcpurple_check_silc_dir(gc)) {
@@ -1188,11 +1261,11 @@
 static void
 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
 {
-        char prd[256];
+	char prd[256];
 	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
 	silc_change_private_key_passphrase(purple_account_get_string(gc->account,
 								     "private-key",
-								     prd), old, new);
+								     prd), old ? old : "", new ? new : "");
 }
 
 static void
--- a/libpurple/protocols/silc10/silc.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/protocols/silc10/silc.c	Mon Apr 28 19:24:18 2008 +0000
@@ -962,11 +962,11 @@
 static void
 silcpurple_change_passwd(PurpleConnection *gc, const char *old, const char *new)
 {
-        char prd[256];
+	char prd[256];
 	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.pub", silcpurple_silcdir());
 	silc_change_private_key_passphrase(purple_account_get_string(gc->account,
 								   "private-key",
-								   prd), old, new);
+								   prd), old ? old : "", new ? new : "");
 }
 
 static void
--- a/libpurple/savedstatuses.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/savedstatuses.c	Mon Apr 28 19:24:18 2008 +0000
@@ -1128,10 +1128,12 @@
 
 	g_list_free(accounts);
 
-	purple_savedstatus_set_idleaway(FALSE);
-
-	purple_signal_emit(purple_savedstatuses_get_handle(), "savedstatus-changed",
-					 saved_status, old);
+	if (purple_savedstatus_is_idleaway()) {
+		purple_savedstatus_set_idleaway(FALSE);
+	} else {
+		purple_signal_emit(purple_savedstatuses_get_handle(), "savedstatus-changed",
+					 	   saved_status, old);
+	}
 }
 
 void
@@ -1250,6 +1252,7 @@
 	}
 
 	g_hash_table_destroy(creation_times);
+	creation_times = NULL;
 
 	purple_signals_unregister_by_instance(purple_savedstatuses_get_handle());
 }
--- a/libpurple/win32/giowin32.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/win32/giowin32.c	Mon Apr 28 19:24:18 2008 +0000
@@ -37,8 +37,8 @@
 #include <glib.h>
 
 #include <stdlib.h>
+#include <winsock2.h>
 #include <windows.h>
-#include <winsock.h>          /* Not everybody has winsock2 */
 #include <fcntl.h>
 #include <io.h>
 #include <process.h>
@@ -541,7 +541,7 @@
   g_io_channel_unref (watch->channel);
 }
 
-GSourceFuncs g_io_watch_funcs = {
+static GSourceFuncs wp_g_io_watch_funcs = {
   g_io_win32_prepare,
   g_io_win32_check,
   g_io_win32_dispatch,
@@ -559,7 +559,7 @@
   GSource *source;
   char send_buffer[] = "c";
 
-  source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
+  source = g_source_new (&wp_g_io_watch_funcs, sizeof (GIOWin32Watch));
   watch = (GIOWin32Watch *)source;
   
   watch->channel = channel;
--- a/libpurple/win32/libc_interface.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/win32/libc_interface.c	Mon Apr 28 19:24:18 2008 +0000
@@ -319,23 +319,23 @@
 	if (errornum > WSABASEERR) {
 		switch(errornum) {
 			case WSAECONNABORTED: /* 10053 */
-				snprintf(errbuf, sizeof(errbuf), _("Connection interrupted by other software on your computer."));
+				g_snprintf(errbuf, sizeof(errbuf), _("Connection interrupted by other software on your computer."));
 				break;
 			case WSAECONNRESET: /* 10054 */
-				snprintf(errbuf, sizeof(errbuf), _("Remote host closed connection."));
+				g_snprintf(errbuf, sizeof(errbuf), _("Remote host closed connection."));
 				break;
 			case WSAETIMEDOUT: /* 10060 */
-				snprintf(errbuf, sizeof(errbuf), _("Connection timed out."));
+				g_snprintf(errbuf, sizeof(errbuf), _("Connection timed out."));
 				break;
 			case WSAECONNREFUSED: /*10061 */
-				snprintf(errbuf, sizeof(errbuf), _("Connection refused."));
+				g_snprintf(errbuf, sizeof(errbuf), _("Connection refused."));
 				break;
 			default:
-				snprintf(errbuf, sizeof(errbuf), "Windows socket error #%d", errornum);
+				g_snprintf(errbuf, sizeof(errbuf), "Windows socket error #%d", errornum);
 		}
 	} else {
 		const char *tmp = g_strerror(errornum);
-		snprintf(errbuf, sizeof(errbuf), tmp);
+		g_snprintf(errbuf, sizeof(errbuf), tmp);
 	}
 	return errbuf;
 }
@@ -368,7 +368,7 @@
 		}
 	} else {
 		/* fd is not a socket handle.. pass it off to read */
-		return read(fd, buf, size);
+		return _read(fd, buf, size);
 	}
 }
 
@@ -391,7 +391,7 @@
 	if(wpurple_is_socket(fd))
 		return wpurple_send(fd, buf, size, 0);
 	else
-		return write(fd, buf, size);
+		return _write(fd, buf, size);
 }
 
 int wpurple_recv(int fd, void *buf, size_t len, int flags) {
@@ -419,7 +419,7 @@
 			return 0;
 	}
 	else
-		return close(fd);
+		return _close(fd);
 }
 
 int wpurple_gethostname(char *name, size_t size) {
@@ -454,6 +454,14 @@
 /* stdio.h */
 
 int wpurple_rename (const char *oldname, const char *newname) {
+
+#if GLIB_CHECK_VERSION(2,8,5)
+
+	return g_rename(oldname, newname);
+
+#else
+
+	/* This is a ugly, but we still compile with 2.6.10 but use newer runtimes */
 	struct stat oldstat, newstat;
 
 	/* As of Glib 2.8.5, g_rename() uses MoveFileEx() with MOVEFILE_REPLACE_EXISTING to behave more sanely */
@@ -503,6 +511,8 @@
 		return -1;
 	}
 
+#endif
+
 }
 
 /* time.h */
@@ -1080,7 +1090,6 @@
 	return "";
 }
 
-#if !GLIB_CHECK_VERSION(2,8,0)
 /**
  * g_access:
  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
@@ -1105,6 +1114,12 @@
 wpurple_g_access (const gchar *filename,
 	  int          mode)
 {
+#if GLIB_CHECK_VERSION(2,8,0)
+
+	return g_access(filename, mode);
+
+#else
+
   if (G_WIN32_HAVE_WIDECHAR_API ())
     {
       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
@@ -1145,7 +1160,8 @@
       errno = save_errno;
       return retval;
     }
+
+#endif
 }
-#endif
 
 
--- a/libpurple/win32/win32dep.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/win32/win32dep.c	Mon Apr 28 19:24:18 2008 +0000
@@ -23,23 +23,12 @@
  *
  */
 #define _WIN32_IE 0x500
-#include <windows.h>
-#include <io.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include "internal.h"
 #include <winuser.h>
 
-#include <glib.h>
-#include <glib/gstdio.h>
-
-#include "internal.h"
 #include "debug.h"
 #include "notify.h"
 
-#include <libintl.h>
-
-#include "win32dep.h"
-
 /*
  *  DEFINES & MACROS
  */
--- a/libpurple/win32/win32dep.h	Sat Apr 19 21:57:17 2008 +0000
+++ b/libpurple/win32/win32dep.h	Mon Apr 28 19:24:18 2008 +0000
@@ -22,8 +22,9 @@
  */
 #ifndef _WIN32DEP_H_
 #define _WIN32DEP_H_
+#include <winsock2.h>
+#include <windows.h>
 #include <shlobj.h>
-#include <winsock2.h>
 #include <process.h>
 #include "wpurpleerror.h"
 #include "libc_interface.h"
--- a/pidgin/gtkblist.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtkblist.c	Mon Apr 28 19:24:18 2008 +0000
@@ -695,6 +695,7 @@
 	{
 		purple_blist_node_set_bool(node, "show_offline",
 		                           !purple_blist_node_get_bool(node, "show_offline"));
+		pidgin_blist_update(purple_get_blist(), node);
 	}
 	else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
 	{
@@ -704,6 +705,7 @@
 		purple_blist_node_set_bool(node, "show_offline", setting);
 		for (bnode = node->child; bnode != NULL; bnode = bnode->next) {
 			purple_blist_node_set_bool(bnode, "show_offline", setting);
+			pidgin_blist_update(purple_get_blist(), bnode);
 		}
 	} else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
 		PurpleBlistNode *cnode, *bnode;
@@ -714,10 +716,10 @@
 			purple_blist_node_set_bool(cnode, "show_offline", setting);
 			for (bnode = cnode->child; bnode != NULL; bnode = bnode->next) {
 				purple_blist_node_set_bool(bnode, "show_offline", setting);
+				pidgin_blist_update(purple_get_blist(), bnode);
 			}
 		}
 	}
-	pidgin_blist_update(purple_get_blist(), node);
 }
 
 static void gtk_blist_show_systemlog_cb(void)
--- a/pidgin/gtkconv.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtkconv.c	Mon Apr 28 19:24:18 2008 +0000
@@ -101,6 +101,9 @@
 #define DEFAULT_HIGHLIGHT_COLOR "#AF7F00"
 #define DEFAULT_ACTION_COLOR "#062585"
 
+#define BUDDYICON_SIZE_MIN    32
+#define BUDDYICON_SIZE_MAX    96
+
 /* Undef this to turn off "custom-smiley" debug messages */
 #define DEBUG_CUSTOM_SMILEY
 
@@ -2507,14 +2510,18 @@
 
 	if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/blist/show_protocol_icons")) {
 		emblem = pidgin_create_prpl_icon(gtkconv->active_conv->account, PIDGIN_PRPL_ICON_SMALL);
-		gtk_list_store_set(GTK_LIST_STORE(gtkconv->infopane_model),
+	} else {
+		emblem = NULL;
+	}
+
+	gtk_list_store_set(GTK_LIST_STORE(gtkconv->infopane_model),
 			&(gtkconv->infopane_iter),
 			CONV_PROTOCOL_ICON_COLUMN, emblem, -1);
-		if (emblem)
-			g_object_unref(emblem);
-	}
+	if (emblem)
+		g_object_unref(emblem);
 
 	/* XXX seanegan Why do I have to do this? */
+	gtk_widget_queue_resize(gtkconv->infopane);
 	gtk_widget_queue_draw(gtkconv->infopane);
 
 	if (status != NULL)
@@ -2557,6 +2564,7 @@
 	GdkPixbuf *scale;
 	gint delay;
 	int scale_width, scale_height;
+	int size;
 
 	gtkconv = PIDGIN_CONVERSATION(conv);
 	account = purple_conversation_get_account(conv);
@@ -2571,17 +2579,22 @@
 	gdk_pixbuf_animation_iter_advance(gtkconv->u.im->iter, NULL);
 	buf = gdk_pixbuf_animation_iter_get_pixbuf(gtkconv->u.im->iter);
 
- 	scale_width = gdk_pixbuf_get_width(buf);
-        scale_height = gdk_pixbuf_get_height(buf);
-        if (scale_width == scale_height) {
-		scale_width = scale_height = 32;
+	scale_width = gdk_pixbuf_get_width(buf);
+	scale_height = gdk_pixbuf_get_height(buf);
+
+	gtk_widget_get_size_request(gtkconv->infopane_hbox, NULL, &size);
+	size = MIN(size, MIN(scale_width, scale_height));
+	size = CLAMP(size, BUDDYICON_SIZE_MIN, BUDDYICON_SIZE_MAX);
+
+	if (scale_width == scale_height) {
+		scale_width = scale_height = size;
 	} else if (scale_height > scale_width) {
-                scale_width = 32 * scale_width / scale_height;
-                scale_height = 32;
-        } else {
-                scale_height = 32 * scale_height / scale_width;
-                scale_width = 32;
-        }
+		scale_width = size * scale_width / scale_height;
+		scale_height = size;
+	} else {
+		scale_height = size * scale_height / scale_width;
+		scale_width = size;
+	}
 
 	scale = gdk_pixbuf_scale_simple(buf, scale_width, scale_height,
 		GDK_INTERP_BILINEAR);
@@ -2701,6 +2714,33 @@
 }
 
 static void
+change_size_cb(GtkWidget *widget, PidginConversation *gtkconv)
+{
+	int size = 0;
+	PurpleConversation *conv = gtkconv->active_conv;
+	GSList *buddies;
+
+	gtk_widget_get_size_request(gtkconv->infopane_hbox, NULL, &size);
+
+	if (size == BUDDYICON_SIZE_MAX) {
+		size = BUDDYICON_SIZE_MIN;
+	} else {
+		size = BUDDYICON_SIZE_MAX;
+	}
+
+	gtk_widget_set_size_request(gtkconv->infopane_hbox, -1, size);
+	pidgin_conv_update_buddy_icon(conv);
+
+	buddies = purple_find_buddies(purple_conversation_get_account(conv),
+			purple_conversation_get_name(conv));
+	for (; buddies; buddies = g_slist_delete_link(buddies, buddies)) {
+		PurpleBuddy *buddy = buddies->data;
+		PurpleContact *contact = purple_buddy_get_contact(buddy);
+		purple_blist_node_set_int((PurpleBlistNode*)contact, "pidgin-infopane-iconsize", size);
+	}
+}
+
+static void
 remove_custom_icon_cb(GtkWidget *widget, PidginConversation *gtkconv)
 {
 	PurpleConversation *conv;
@@ -2761,8 +2801,14 @@
 	PurpleConversation *conv;
 	PurpleBuddy *buddy;
 
-	if (e->button != 3 || e->type != GDK_BUTTON_PRESS)
+	if (e->button == 1 && e->type == GDK_BUTTON_PRESS) {
+		change_size_cb(NULL, gtkconv);
+		return TRUE;
+	}
+
+	if (e->button != 3 || e->type != GDK_BUTTON_PRESS) {
 		return FALSE;
+	}
 
 	/*
 	 * If a menu already exists, destroy it before creating a new one,
@@ -2792,6 +2838,10 @@
 							 G_CALLBACK(set_custom_icon_cb), gtkconv,
 							 0, 0, NULL);
 
+	pidgin_new_item_from_stock(menu, _("Change Size"), NULL,
+							 G_CALLBACK(change_size_cb), gtkconv,
+							 0, 0, NULL);
+
 	/* Is there a custom icon for this person? */
 	conv = gtkconv->active_conv;
 	buddy = purple_find_buddy(purple_conversation_get_account(conv),
@@ -3636,6 +3686,20 @@
 	gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
 }
 
+static gboolean
+compare_buddy_presence(PurplePresence *p1, PurplePresence *p2)
+{
+	/* This is necessary because multiple PurpleBuddy's don't share the same
+	 * PurplePresence anymore.
+	 */
+	PurpleBuddy *b1 = purple_presence_get_buddy(p1);
+	PurpleBuddy *b2 = purple_presence_get_buddy(p2);
+	if (purple_buddy_get_account(b1) == purple_buddy_get_account(b2) &&
+			strcmp(purple_buddy_get_name(b1), purple_buddy_get_name(b2)) == 0)
+		return FALSE;
+	return TRUE;
+}
+
 static void
 generate_send_to_items(PidginWindow *win)
 {
@@ -3670,8 +3734,7 @@
 
 		if (buds == NULL)
 		{
-			/* The user isn't on the buddy list. */
-			create_sendto_item(menu, sg, &group, NULL, gtkconv->active_conv->account, gtkconv->active_conv->name);
+			/* The user isn't on the buddy list. So we don't create any sendto menu. */
 		}
 		else
 		{
@@ -3695,20 +3758,22 @@
 					{
 						/* Use the PurplePresence to get unique buddies. */
 						PurplePresence *presence = purple_buddy_get_presence(buddy);
-						if (!g_list_find(list, presence))
+						if (!g_list_find_custom(list, presence, (GCompareFunc)compare_buddy_presence))
 							list = g_list_prepend(list, presence);
 					}
 				}
 			}
 
-			/* Loop over the list backwards so we get the items in the right order,
-			 * since we did a g_list_prepend() earlier. */
-			for (iter = g_list_last(list); iter != NULL; iter = iter->prev)
-			{
-				PurplePresence *pre = iter->data;
-				PurpleBuddy *buddy = purple_presence_get_buddy(pre);
-				create_sendto_item(menu, sg, &group, buddy,
+			/* Create the sendto menu only if it has more than one item to show */
+			if (list && list->next) {
+				/* Loop over the list backwards so we get the items in the right order,
+				 * since we did a g_list_prepend() earlier. */
+				for (iter = g_list_last(list); iter != NULL; iter = iter->prev) {
+					PurplePresence *pre = iter->data;
+					PurpleBuddy *buddy = purple_presence_get_buddy(pre);
+					create_sendto_item(menu, sg, &group, buddy,
 							purple_buddy_get_account(buddy), purple_buddy_get_name(buddy));
+				}
 			}
 			g_list_free(list);
 			g_slist_free(buds);
@@ -4618,8 +4683,10 @@
 	GtkCellRenderer *rend;
 	GtkTreePath *path;
 	PurpleConversation *conv = gtkconv->active_conv;
+	PurpleBuddy *buddy;
 	gboolean chat = (conv->type == PURPLE_CONV_TYPE_CHAT);
 	GtkPolicyType imhtml_sw_hscroll;
+	int buddyicon_size = 0;
 
 	/* Setup the top part of the pane */
 	vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
@@ -4647,12 +4714,22 @@
 	gtkconv->infopane_model = gtk_list_store_new(CONV_NUM_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF);
 	gtk_cell_view_set_model(GTK_CELL_VIEW(gtkconv->infopane), 
 				GTK_TREE_MODEL(gtkconv->infopane_model));
+	g_object_unref(gtkconv->infopane_model);
 	gtk_list_store_append(gtkconv->infopane_model, &(gtkconv->infopane_iter));
 	gtk_box_pack_start(GTK_BOX(gtkconv->infopane_hbox), gtkconv->infopane, TRUE, TRUE, 0);
 	path = gtk_tree_path_new_from_string("0");
 	gtk_cell_view_set_displayed_row(GTK_CELL_VIEW(gtkconv->infopane), path);
 	gtk_tree_path_free(path);
-	gtk_widget_set_size_request(gtkconv->infopane_hbox, -1, 32);
+
+	if ((buddy = purple_find_buddy(purple_conversation_get_account(conv),
+					purple_conversation_get_name(conv))) != NULL) {
+		PurpleContact *contact = purple_buddy_get_contact(buddy);
+		if (contact) {
+			buddyicon_size = purple_blist_node_get_int((PurpleBlistNode*)contact, "pidgin-infopane-iconsize");
+		}
+	}
+	buddyicon_size = CLAMP(buddyicon_size, BUDDYICON_SIZE_MIN, BUDDYICON_SIZE_MAX);
+	gtk_widget_set_size_request(gtkconv->infopane_hbox, -1, buddyicon_size);
 	gtk_widget_show(gtkconv->infopane);
 
 	rend = gtk_cell_renderer_pixbuf_new();
@@ -6763,6 +6840,7 @@
 	GtkWidget *event;
 	GdkPixbuf *scale;
 	int scale_width, scale_height;
+	int size = 0;
 
 	PurpleAccount *account;
 	PurplePluginProtocolInfo *prpl_info = NULL;
@@ -6875,14 +6953,20 @@
 
 	scale_width = gdk_pixbuf_get_width(buf);
 	scale_height = gdk_pixbuf_get_height(buf);
+
+	gtk_widget_get_size_request(gtkconv->infopane_hbox, NULL, &size);
+	size = MIN(size, MIN(scale_width, scale_height));
+
+	/* Some sanity checks */
+	size = CLAMP(size, BUDDYICON_SIZE_MIN, BUDDYICON_SIZE_MAX);
 	if (scale_width == scale_height) {
-		scale_width = scale_height = 32;
+		scale_width = scale_height = size;
 	} else if (scale_height > scale_width) {
-		scale_width = 32 * scale_width / scale_height;
-		scale_height = 32;
+		scale_width = size * scale_width / scale_height;
+		scale_height = size;
 	} else {
-		scale_height = 32 * scale_height / scale_width;
-		scale_width = 32;
+		scale_height = size * scale_height / scale_width;
+		scale_width = size;
 	}
 	scale = gdk_pixbuf_scale_simple(buf, scale_width, scale_height,
 				GDK_INTERP_BILINEAR);
@@ -7722,7 +7806,7 @@
 								animate_buddy_icons_pref_cb, NULL);
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/show_buddy_icons",
 								show_buddy_icons_pref_cb, NULL);
-	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/show_protocol_icons",
+	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/blist/show_protocol_icons",
 								show_protocol_icons_pref_cb, NULL);
 	purple_prefs_connect_callback(handle, PIDGIN_PREFS_ROOT "/conversations/im/hide_new",
                                 hide_new_pref_cb, NULL);
@@ -8265,7 +8349,7 @@
 		} else {
 			page_num = 0;
 			to_right = pidgin_conv_xy_to_right_infopane(dest_win, e->x_root, e->y_root);
-			tab = pidgin_conv_window_get_gtkconv_at_index(dest_win, page_num)->infopane;
+			tab = pidgin_conv_window_get_gtkconv_at_index(dest_win, page_num)->infopane_hbox;
 		}
 
 		if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP ||
--- a/pidgin/gtkimhtml.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtkimhtml.c	Mon Apr 28 19:24:18 2008 +0000
@@ -758,6 +758,7 @@
 
 		
 			rect.height = tag_area.y + tag_area.height - rect.y
+				+ gtk_text_view_get_pixels_above_lines(GTK_TEXT_VIEW(widget))
 				+ gtk_text_view_get_pixels_below_lines(GTK_TEXT_VIEW(widget));
 
 			color = tag->name + 11;
@@ -1201,16 +1202,20 @@
 }
 
 static void
-gtk_imhtml_undo(GtkIMHtml *imhtml) {
+gtk_imhtml_undo(GtkIMHtml *imhtml)
+{
 	g_return_if_fail(GTK_IS_IMHTML(imhtml));
-	if (imhtml->editable)
+	if (imhtml->editable &&
+			gtk_source_undo_manager_can_undo(imhtml->undo_manager))
 		gtk_source_undo_manager_undo(imhtml->undo_manager);
 }
 
 static void
-gtk_imhtml_redo(GtkIMHtml *imhtml) {
+gtk_imhtml_redo(GtkIMHtml *imhtml)
+{
 	g_return_if_fail(GTK_IS_IMHTML(imhtml));
-	if (imhtml->editable)
+	if (imhtml->editable &&
+			gtk_source_undo_manager_can_redo(imhtml->undo_manager))
 		gtk_source_undo_manager_redo(imhtml->undo_manager);
 
 }
@@ -1459,7 +1464,8 @@
 	gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter);
 	gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer);
 	gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR);
-	gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5);
+	gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(imhtml), 2);
+	gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 3);
 	gtk_text_view_set_left_margin(GTK_TEXT_VIEW(imhtml), 2);
 	gtk_text_view_set_right_margin(GTK_TEXT_VIEW(imhtml), 2);
 	/*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/
@@ -2425,6 +2431,7 @@
 	ws = g_malloc(len + 1);
 	ws[0] = 0;
 
+	gtk_text_buffer_begin_user_action(imhtml->text_buffer);
 	while (pos < len) {
 		if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) {
 			c++;
@@ -3153,6 +3160,7 @@
 	g_signal_emit(object, signals[UPDATE_FORMAT], 0);
 	g_object_unref(object);
 
+	gtk_text_buffer_end_user_action(imhtml->text_buffer);
 }
 
 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml)
--- a/pidgin/gtkmain.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtkmain.c	Mon Apr 28 19:24:18 2008 +0000
@@ -27,6 +27,7 @@
 #include "account.h"
 #include "conversation.h"
 #include "core.h"
+#include "dbus-maybe.h"
 #include "debug.h"
 #include "eventloop.h"
 #include "ft.h"
@@ -783,6 +784,15 @@
 	}
 
 	if (opt_si && !purple_core_ensure_single_instance()) {
+#ifdef HAVE_DBUS
+		DBusConnection *conn = purple_dbus_get_connection();
+		DBusMessage *message = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE,
+				DBUS_INTERFACE_PURPLE, "PurpleBlistSetVisible");
+		gboolean tr = TRUE;
+		dbus_message_append_args(message, DBUS_TYPE_UINT32, &tr, DBUS_TYPE_INVALID);
+		dbus_connection_send_with_reply_and_block(conn, message, -1, NULL);
+		dbus_message_unref(message);
+#endif
 		purple_debug_info("main", "exiting because another libpurple client is already running\n");
 		purple_core_quit();
 #ifdef HAVE_SIGNAL_H
--- a/pidgin/gtkmenutray.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtkmenutray.c	Mon Apr 28 19:24:18 2008 +0000
@@ -134,8 +134,6 @@
 	if(!GTK_IS_WIDGET(menu_tray->tray))
 		menu_tray->tray = gtk_hbox_new(FALSE, 0);
 
-	menu_tray->tooltips = gtk_tooltips_new();
-
 #if GTK_CHECK_VERSION(2,2,0)
 	settings =
 		gtk_settings_get_for_screen(gtk_widget_get_screen(widget));
@@ -235,7 +233,7 @@
 pidgin_menu_tray_set_tooltip(PidginMenuTray *menu_tray, GtkWidget *widget, const char *tooltip)
 {
 	if (!menu_tray->tooltips)
-		return;
+		menu_tray->tooltips = gtk_tooltips_new();
 
 	/* Should we check whether widget is a child of menu_tray? */
 
--- a/pidgin/gtksourceundomanager.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtksourceundomanager.c	Mon Apr 28 19:24:18 2008 +0000
@@ -41,10 +41,12 @@
 typedef struct _GtkSourceUndoAction  			GtkSourceUndoAction;
 typedef struct _GtkSourceUndoInsertAction		GtkSourceUndoInsertAction;
 typedef struct _GtkSourceUndoDeleteAction		GtkSourceUndoDeleteAction;
+typedef struct _GtkSourceUndoInsertAnchorAction GtkSourceUndoInsertAnchorAction;
 
 typedef enum {
 	GTK_SOURCE_UNDO_ACTION_INSERT,
-	GTK_SOURCE_UNDO_ACTION_DELETE
+	GTK_SOURCE_UNDO_ACTION_DELETE,
+	GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR,
 } GtkSourceUndoActionType;
 
 /* 
@@ -68,6 +70,12 @@
 	gboolean forward;
 };
 
+struct _GtkSourceUndoInsertAnchorAction
+{
+	gint pos;
+	GtkTextChildAnchor *anchor;
+};
+
 struct _GtkSourceUndoAction
 {
 	GtkSourceUndoActionType action_type;
@@ -75,6 +83,7 @@
 	union {
 		GtkSourceUndoInsertAction  insert;
 		GtkSourceUndoDeleteAction  delete;
+		GtkSourceUndoInsertAnchorAction insert_anchor;
 	} action;
 
 	gint order_in_group;
@@ -139,6 +148,10 @@
 		                             		 	 const 	gchar 			*text, 
 							 	 gint 				 length, 
 							 	 GtkSourceUndoManager 		*um);
+static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer,
+			                   GtkTextIter            *pos,
+			                   GtkTextChildAnchor     *anchor,
+			                   GtkSourceUndoManager   *um);
 static void gtk_source_undo_manager_delete_range_handler 	(GtkTextBuffer 			*buffer, 
 							 	 GtkTextIter 			*start,
                         		      		 	 GtkTextIter 			*end,
@@ -275,6 +288,10 @@
 			  um);
 	
 	g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
+			  G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler), 
+			  um);
+	
+	g_signal_handlers_disconnect_by_func (G_OBJECT (um->priv->document),
 			  G_CALLBACK (gtk_source_undo_manager_begin_user_action_handler), 
 			  um);
 
@@ -297,6 +314,10 @@
 			  G_CALLBACK (gtk_source_undo_manager_insert_text_handler), 
 			  um);
 
+	g_signal_connect (G_OBJECT (buffer), "insert_child_anchor",
+			  G_CALLBACK (gtk_source_undo_manager_insert_anchor_handler), 
+			  um);
+
 	g_signal_connect (G_OBJECT (buffer), "delete_range",
 			  G_CALLBACK (gtk_source_undo_manager_delete_range_handler), 
 			  um);
@@ -403,6 +424,15 @@
 }
 
 static void 
+insert_anchor (GtkTextBuffer *buffer, gint pos, GtkTextChildAnchor *anchor)
+{
+	GtkTextIter iter;
+	
+	gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
+	gtk_text_buffer_insert_child_anchor (buffer, &iter, anchor);
+}
+
+static void 
 delete_text (GtkTextBuffer *buffer, gint start, gint end)
 {
 	GtkTextIter start_iter;
@@ -497,6 +527,13 @@
 					undo_action->action.insert.pos);
 				break;
 
+			case GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR:
+				delete_text (
+					um->priv->document,
+					undo_action->action.insert_anchor.pos,
+					undo_action->action.insert_anchor.pos + 1);
+				undo_action->action.insert_anchor.anchor->segment = NULL; /* XXX: This may be a bug in GTK+ */
+				break;
 			default:
 				/* Unknown action type. */
 				g_return_if_reached ();
@@ -588,6 +625,17 @@
 
 				break;
 
+			case GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR:
+				set_cursor (
+					um->priv->document,
+					undo_action->action.insert_anchor.pos);
+
+				insert_anchor (
+					um->priv->document,
+					undo_action->action.insert_anchor.pos,
+					undo_action->action.insert_anchor.anchor);
+				break;
+
 			default:
 				/* Unknown action type */
 				++um->priv->next_redo;
@@ -633,6 +681,8 @@
 		g_free (action->action.insert.text);
 	else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
 		g_free (action->action.delete.text);
+	else if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
+		g_object_unref(action->action.insert_anchor.anchor);
 	else
 		g_return_if_reached ();
 
@@ -695,6 +745,27 @@
 	gtk_source_undo_manager_add_action (um, &undo_action);
 }
 
+static void gtk_source_undo_manager_insert_anchor_handler (GtkTextBuffer *buffer,
+			                   GtkTextIter            *pos,
+			                   GtkTextChildAnchor     *anchor,
+			                   GtkSourceUndoManager   *um)
+{
+	GtkSourceUndoAction undo_action;
+
+	if (um->priv->running_not_undoable_actions > 0)
+		return;
+
+	undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR;
+
+	undo_action.action.insert_anchor.pos    = gtk_text_iter_get_offset (pos);
+	undo_action.action.insert_anchor.anchor = g_object_ref (anchor);
+
+	undo_action.mergeable = FALSE;
+	undo_action.modified = FALSE;
+
+	gtk_source_undo_manager_add_action (um, &undo_action);
+}
+
 static void 
 gtk_source_undo_manager_delete_range_handler (GtkTextBuffer 		*buffer, 
 					      GtkTextIter 		*start,
@@ -775,6 +846,10 @@
 			action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length);
 		else if (action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
 			action->action.delete.text = g_strdup (undo_action->action.delete.text); 
+		else if (action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
+		{
+			/* Nothing needs to be done */
+		}
 		else
 		{
 			g_free (action);
@@ -998,6 +1073,10 @@
 		last_action->action.insert.chars += undo_action->action.insert.chars;
 
 	}
+	else if (undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT_ANCHOR)
+	{
+		/* Nothing needs to be done */
+	}
 	else
 		/* Unknown action inside undo merge encountered */
 		g_return_val_if_reached (TRUE);
--- a/pidgin/gtkstatusbox.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/gtkstatusbox.c	Mon Apr 28 19:24:18 2008 +0000
@@ -74,6 +74,7 @@
 static void remove_typing_cb(PidginStatusBox *box);
 static void update_size (PidginStatusBox *box);
 static gint get_statusbox_index(PidginStatusBox *box, PurpleSavedStatus *saved_status);
+static PurpleAccount* check_active_accounts_for_identical_statuses(void);
 
 static void pidgin_status_box_pulse_typing(PidginStatusBox *status_box);
 static void pidgin_status_box_refresh(PidginStatusBox *status_box);
@@ -497,6 +498,10 @@
 		break;
 	case PROP_ACCOUNT:
 		statusbox->account = g_value_get_pointer(value);
+		if (statusbox->account)
+			statusbox->token_status_account = NULL;
+		else
+			statusbox->token_status_account = check_active_accounts_for_identical_statuses();
 
 		pidgin_status_box_regenerate(statusbox);
 
@@ -628,7 +633,7 @@
 	GdkPixbuf *pixbuf, *emblem = NULL;
 	GtkTreePath *path;
 	gboolean account_status = FALSE;
-	PurpleAccount *acct = (status_box->token_status_account) ? status_box->token_status_account : status_box->account;
+	PurpleAccount *acct = (status_box->account) ? status_box->account : status_box->token_status_account;
 
 	icon_size = gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_EXTRA_SMALL);
 
@@ -1135,7 +1140,7 @@
 				                  GTK_DIR_TAB_BACKWARD: GTK_DIR_TAB_FORWARD);
 		return TRUE;
 	}
-	if (!status_box->typing != 0)
+	if (status_box->typing == 0)
 		return FALSE;
 
 	/* Reset the status if Escape was pressed */
@@ -1228,9 +1233,13 @@
 								     icon_size, "PidginStatusBox");
 }
 
-static void account_enabled_cb(PurpleAccount *acct, PidginStatusBox *status_box) {
+static void account_enabled_cb(PurpleAccount *acct, PidginStatusBox *status_box)
+{
 	PurpleAccount *initial_token_acct = status_box->token_status_account;
 
+	if (status_box->account)
+		return;
+
 	status_box->token_status_account = check_active_accounts_for_identical_statuses();
 
 	/* Regenerate the list if it has changed */
@@ -1686,6 +1695,17 @@
 }
 
 static void
+imhtml_cursor_moved_cb(gpointer data, GtkMovementStep step, gint count, gboolean extend,
+		GtkWidget *widget)
+{
+	/* Restart the typing timeout if arrow keys are pressed while editing the message */
+	PidginStatusBox *status_box = data;
+	if (status_box->typing == 0)
+		return;
+	imhtml_changed_cb(NULL, status_box);
+}
+
+static void
 pidgin_status_box_init (PidginStatusBox *status_box)
 {
 	GtkCellRenderer *text_rend;
@@ -1714,6 +1734,8 @@
 	gtk_cell_view_set_model(GTK_CELL_VIEW(status_box->cell_view), GTK_TREE_MODEL(status_box->store));
 	gtk_list_store_append(status_box->store, &(status_box->iter));
 
+	atk_object_set_name(gtk_widget_get_accessible(status_box->toggle_button), _("Status Selector"));
+
 	gtk_container_add(GTK_CONTAINER(status_box->toggle_button), status_box->hbox);
 	gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->cell_view, TRUE, TRUE, 0);
 	gtk_box_pack_start(GTK_BOX(status_box->hbox), status_box->vsep, FALSE, FALSE, 0);
@@ -1825,6 +1847,8 @@
 	g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(imhtml_changed_cb), status_box);
 	g_signal_connect(G_OBJECT(status_box->imhtml), "format_function_toggle",
 			 G_CALLBACK(imhtml_format_changed_cb), status_box);
+	g_signal_connect_swapped(G_OBJECT(status_box->imhtml), "move_cursor",
+			 G_CALLBACK(imhtml_cursor_moved_cb), status_box);
 	g_signal_connect(G_OBJECT(status_box->imhtml), "key_press_event",
 			 G_CALLBACK(imhtml_remove_focus), status_box);
 	g_signal_connect_swapped(G_OBJECT(status_box->imhtml), "message_send", G_CALLBACK(remove_typing_cb), status_box);
--- a/pidgin/minidialog.c	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/minidialog.c	Mon Apr 28 19:24:18 2008 +0000
@@ -406,6 +406,7 @@
 	priv->title = GTK_LABEL(gtk_label_new(NULL));
 	gtk_widget_set_size_request(GTK_WIDGET(priv->title), label_width, -1);
 	gtk_label_set_line_wrap(priv->title, TRUE);
+	gtk_label_set_selectable(priv->title, TRUE);
 	gtk_misc_set_alignment(GTK_MISC(priv->title), 0, 0);
 
 	gtk_box_pack_start(priv->title_box, GTK_WIDGET(priv->icon), FALSE, FALSE, 0);
@@ -415,6 +416,7 @@
 	gtk_widget_set_size_request(GTK_WIDGET(priv->desc), label_width, -1);
 	gtk_label_set_line_wrap(priv->desc, TRUE);
 	gtk_misc_set_alignment(GTK_MISC(priv->desc), 0, 0);
+	gtk_label_set_selectable(priv->desc, TRUE);
 	/* make calling show_all() on the minidialog not affect desc even though
 	 * it's packed inside it.
 	 */
--- a/pidgin/plugins/perl/Makefile.am	Sat Apr 19 21:57:17 2008 +0000
+++ b/pidgin/plugins/perl/Makefile.am	Mon Apr 28 19:24:18 2008 +0000
@@ -39,7 +39,9 @@
 common/Makefile: common/Makefile.PL
 	@if test "x${top_srcdir}" != "x${top_builddir}"; then \
 		for f in ${common_sources}; do \
-			${LN_S} -f ../${srcdir}/$$f $$f; \
+			srcloc=${srcdir}; \
+			case $$srcloc in /*) ;; *) srcloc=../${srcdir} ;; esac; \
+			${LN_S} -f $$srcloc/$$f $$f; \
 		done; \
 	fi
 	@cd common && $(perlpath) Makefile.PL $(PERL_MM_PARAMS)