Index: .bzrignore
===================================================================
--- .bzrignore	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ .bzrignore	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -17,2 +17,4 @@
 *.gcno
 *.o
+coverage
+bitlbee.info
Index: account.c
===================================================================
--- account.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ account.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -182,17 +182,15 @@
 	account_t *a, *l = NULL;
 	
+	if( acc->ic )
+		/* Caller should have checked, accounts still in use can't be deleted. */
+		return;
+	
 	for( a = irc->accounts; a; a = (l=a)->next )
 		if( a == acc )
 		{
-			if( a->ic ) return; /* Caller should have checked, accounts still in use can't be deleted. */
-			
 			if( l )
-			{
 				l->next = a->next;
-			}
 			else
-			{
 				irc->accounts = a->next;
-			}
 			
 			while( a->set )
@@ -203,5 +201,5 @@
 			g_free( a->user );
 			g_free( a->pass );
-			if( a->server ) g_free( a->server );
+			g_free( a->server );
 			if( a->reconnect )	/* This prevents any reconnect still queued to happen */
 				cancel_auto_reconnect( a );
Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ bitlbee.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -54,9 +54,9 @@
 	;
 
-	i = getaddrinfo( global.conf->iface, global.conf->port, &hints, &addrinfo_bind );
+	i = getaddrinfo( global.conf->iface_in, global.conf->port, &hints, &addrinfo_bind );
 	if( i )
 	{
 		log_message( LOGLVL_ERROR, "Couldn't parse address `%s': %s",
-		                           global.conf->iface, gai_strerror(i) );
+		                           global.conf->iface_in, gai_strerror(i) );
 		return -1;
 	}
@@ -226,10 +226,14 @@
 	if( st == size )
 	{
-		g_free( irc->sendbuffer );
-		irc->sendbuffer = NULL;
-		irc->w_watch_source_id = 0;
-		
 		if( irc->status & USTATUS_SHUTDOWN )
+		{
 			irc_free( irc );
+		}
+		else
+		{
+			g_free( irc->sendbuffer );
+			irc->sendbuffer = NULL;
+			irc->w_watch_source_id = 0;
+		}
 		
 		return FALSE;
Index: bitlbee.conf
===================================================================
--- bitlbee.conf	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ bitlbee.conf	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -10,8 +10,7 @@
 ##
 ##  Inetd -- Run from inetd (default)
-##  Daemon -- Run as a stand-alone daemon -- EXPERIMENTAL! BitlBee is not yet
-##    stable enough to serve lots of users from one process. Because of this
-##    and other reasons, the use of daemon-mode is *STRONGLY* discouraged,
-##    don't even *think* of reporting bugs when you use this.
+##  Daemon -- Run as a stand-alone daemon, serving all users from one process.
+##    This saves memory if there are more users, the downside is that when one
+##    user hits a crash-bug, all other users will also lose their connection.
 ##  ForkDaemon -- Run as a stand-alone daemon, but keep all clients in separate
 ##    child processes. This should be pretty safe and reliable to use instead
@@ -34,4 +33,11 @@
 # DaemonInterface = 0.0.0.0
 # DaemonPort = 6667
+
+## ClientInterface:
+##
+## If for any reason, you want BitlBee to use a specific address/interface
+## for outgoing traffic (IM connections, HTTP(S), etc.), set it here.
+##
+# ClientInterface = 0.0.0.0
 
 ## AuthMode
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ bitlbee.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -95,8 +95,4 @@
 #define g_main_quit		__PLEASE_USE_B_MAIN_QUIT__
 
-#ifndef F_OK
-#define F_OK 0
-#endif
-
 #ifndef G_GNUC_MALLOC
 /* Doesn't exist in GLib <=2.4 while everything else in BitlBee should
@@ -160,4 +156,6 @@
 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
 
+char *set_eval_root_nick( set_t *set, char *new_nick );
+
 extern global_t global;
 
Index: conf.c
===================================================================
--- conf.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ conf.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -45,5 +45,6 @@
 	conf = g_new0( conf_t, 1 );
 	
-	conf->iface = NULL;
+	conf->iface_in = NULL;
+	conf->iface_out = NULL;
 	conf->port = g_strdup( "6667" );
 	conf->nofork = 0;
@@ -82,5 +83,5 @@
 		if( opt == 'i' )
 		{
-			conf->iface = g_strdup( optarg );
+			conf->iface_in = g_strdup( optarg );
 		}
 		else if( opt == 'p' )
@@ -131,5 +132,5 @@
 			        "\n"
 			        "  -I  Classic/InetD mode. (Default)\n"
-			        "  -D  Daemon mode. (Still EXPERIMENTAL!)\n"
+			        "  -D  Daemon mode. (one process serves all)\n"
 			        "  -F  Forking daemon. (one process per client)\n"
 				"  -u  Run daemon as specified user.\n"
@@ -202,6 +203,6 @@
 			else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 )
 			{
-				g_free( conf->iface );
-				conf->iface = g_strdup( ini->value );
+				g_free( conf->iface_in );
+				conf->iface_in = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "daemonport" ) == 0 )
@@ -209,4 +210,9 @@
 				g_free( conf->port );
 				conf->port = g_strdup( ini->value );
+			}
+			else if( g_strcasecmp( ini->key, "clientinterface" ) == 0 )
+			{
+				g_free( conf->iface_out );
+				conf->iface_out = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "authmode" ) == 0 )
Index: conf.h
===================================================================
--- conf.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ conf.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -32,5 +32,5 @@
 typedef struct conf
 {
-	char *iface;
+	char *iface_in, *iface_out;
 	char *port;
 	int nofork;
Index: configure
===================================================================
--- configure	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ configure	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -74,4 +74,6 @@
 --ssl=...	SSL library to use (gnutls, nss, openssl, bogus, auto)
 							$ssl
+
+--target=...	Cross compilation target 		same as host
 EOF
 		exit;
@@ -132,4 +134,11 @@
 EOF
 
+if [ -n "$target" ]; then
+	PKG_CONFIG_PATH=/usr/$target/lib/pkgconfig
+	PATH=/usr/$target/bin:$PATH
+	CC=$target-cc
+	LD=$target-ld
+fi
+
 if [ "$debug" = "1" ]; then
 	[ -z "$CFLAGS" ] && CFLAGS=-g
@@ -158,12 +167,14 @@
 echo "CC=$CC" >> Makefile.settings;
 
-if [ -n "$LD" ]; then
-	echo "LD=$LD" >> Makefile.settings;
-elif type ld > /dev/null 2> /dev/null; then
-	echo "LD=ld" >> Makefile.settings;
-else
-	echo 'Cannot find ld, aborting.'
-	exit 1;
-fi
+if [ -z "$LD" ]; then
+	if type ld > /dev/null 2> /dev/null; then
+		LD=ld
+	else
+		echo 'Cannot find ld, aborting.'
+		exit 1;
+	fi
+fi
+
+echo "LD=$LD" >> Makefile.settings
 
 if [ -z "$PKG_CONFIG" ]; then
@@ -213,5 +224,12 @@
 detect_gnutls()
 {
-	if libgnutls-config --version > /dev/null 2> /dev/null; then
+	if $PKG_CONFIG --exists gnutls; then
+		cat <<EOF>>Makefile.settings
+EFLAGS+=`$PKG_CONFIG --libs gnutls`
+CFLAGS+=`$PKG_CONFIG --cflags gnutls`
+EOF
+		ssl=gnutls
+		ret=1
+	elif libgnutls-config --version > /dev/null 2> /dev/null; then
 		cat <<EOF>>Makefile.settings
 EFLAGS+=`libgnutls-config --libs`
@@ -375,6 +393,6 @@
 
 if [ "$gcov" = "1" ]; then
-	echo "CFLAGS+=-ftest-coverage -fprofile-arcs" >> Makefile.settings
-	echo "EFLAGS+=-lgcov" >> Makefile.settings
+	echo "CFLAGS+=--coverage" >> Makefile.settings
+	echo "EFLAGS+=--coverage" >> Makefile.settings
 fi
 
@@ -489,4 +507,8 @@
 esac
 
+if [ -n "$target" ]; then
+	echo "Cross-compiling for: $target"
+fi
+
 echo
 echo 'Configuration done:'
Index: debian/changelog
===================================================================
--- debian/changelog	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ debian/changelog	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -1,2 +1,8 @@
+bitlbee (1.2-6) UNRELEASED; urgency=low
+
+  * Add Homepage and Vcs-Bzr fields.
+
+ -- Jelmer Vernooij <jelmer@samba.org>  Sun, 11 May 2008 14:18:16 +0200
+
 bitlbee (1.2-5) unstable; urgency=low
 
Index: debian/control
===================================================================
--- debian/control	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ debian/control	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -6,4 +6,6 @@
 Standards-Version: 3.8.0
 Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), debconf-2.0, po-debconf
+Homepage: http://www.bitlbee.org/
+Vcs-Bzr: http://code.bitlbee.org/bitlbee/
 DM-Upload-Allowed: yes
 
Index: doc/CHANGES
===================================================================
--- doc/CHANGES	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ doc/CHANGES	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -1,2 +1,16 @@
+Version 1.2.1:
+- Fixed proxy support.
+- Fixed stalling issues while connecting to Jabber when using the OpenSSL
+  module.
+- Fixed problem with GLib and ForkDaemon where processes didn't die when
+  the client disconnects.
+- Fixed handling of "set charset none". (Which pretty much breaks the account
+  completely in 1.2.)
+- You can now automatically identify yourself to BitlBee by setting a server
+  password in your IRC client.
+- Compatible with all crazy kinds of line endings that clients can send.
+
+Finished ...
+
 Version 1.2:
 - Added ForkDaemon mode next to the existing Daemon- and inetd modes. With
Index: doc/README
===================================================================
--- doc/README	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ doc/README	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -56,4 +56,9 @@
 a package from your distro would've been a better idea. :-P)
 
+Note that the BitlBee code is getting stable enough for daemon mode to be
+useful. Some public servers use it, and it saves a lot of memory by serving
+tens of users from a single process. One crash affects all users, but these
+are becoming quite rare.
+
 
 DEPENDENCIES
@@ -98,32 +103,4 @@
 versions of make, we'd love to hear it, but it seems this just isn't
 possible.
-
-
-RUNNING ON SERVERS WITH MANY USERS
-==================================
-
-BitlBee is not yet bug-free. Sometimes a bug causes the program to get into
-an infinite loop. Something you really don't want on a public server,
-especially when that machine is also used for other (mission-critical) things.
-For now we can't do much about it. We haven't seen that happen for a long
-time already on our own machines, but some people still manage to get
-themselves in nasty situations we haven't seen before.
-
-For now the best we can offer against this problem is bitlbeed, which allows
-you to setrlimit() the child processes to use no more than a specified
-number of CPU seconds. Not the best solution (not really a solution anyway),
-but certainly trashing one busy daemon process is better than trashing your
-whole machine.
-
-We don't believe adding a limit for bitlbee to /etc/security/limits.conf will
-work, because that file is only read by PAM (ie just for real login users,
-not daemons).
-
-See utils/bitlbeed.c for more information about the program.
-
-Just a little note: Now that we reach version 1.0, this shouldn't be that
-much of an issue anymore. However, on a public server, especially if you
-also use it for other things, it can't hurt to protect yourself against
-possible problems.
 
 
Index: c/RELEASE-SPEECH-1.2
===================================================================
--- doc/RELEASE-SPEECH-1.2	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ 	(revision )
@@ -1,57 +1,0 @@
-BitlBee ... is Bitl
--------------------
-
-"I CAN HAS SPEEECH?" This is how Wilmer announced to me that he was going to do
-another BitlBee release. I was as surprised as you are. I thought he had given
-up on this whole releasing business.
-
-There is some humor in using a LOLcats reference to announce a new Bee
-release. The last major BitlBee release (1.0) was done a long time before the
-hype even begun. Between then and now we've celebrated BitlBee's fifth birthday
-and had a handful of releases, but nothing big happened. As a user this lax
-release planning worries me. What if this means that later releases will take
-even longer? I don't think we should fear this. Let us explore why this release
-took so long.
-
-Personally, I blame Google.
-
-There, I've said it. Google. The guys who are so big on "Do No Evil" and all
-that jazz. They caused this release to be so late. Let me explain why.
-
-They made Wilmer an offer. Wilmer, being the sillily naive guy he is, couldn't
-refuse. There were no decapitated horses involved, but he couldn't refuse
-nonetheless. That's not a big problem of course. Lots of guys (and gals, sure)
-work for Google. It wouldn't have become a problem if they hadn't shipped him of
-to Ireland. That's where the trouble starts.
-
-Ireland. Home of the leprechauns. These rascals joined forces with aliens and
-LOLcats to abduct Wilmer. The aliens had been trying for years to kidnap him,
-but they were on his turf and his trusty sidekicks Jelmer and Maurits were there
-to help him. All that changed when he moved to Ireland.
-
-But it wasn't just that Wilmer was all alone in some strange place. It was also
-that the aliens had created the LOLcats and made an alliance with the
-leprechauns--the real rulers of Ireland. Wilmer is cool, but he's not that
-cool. So they abducted him for a few years. When he finally came back, he
-regathered his mad coding skills and hacked a new release together.
-
-By now you're thinking, what has happened to Jelmer and Maurits? Well, they're
-still here and they worked on the Bee while Wilmer was absent. But, like open
-source, they are very Bitl--they're cool, but they're ready when they're
-ready.
-
-Well, whatever you may think of my little theory, they did take forever to
-launch this release. We're not mad at them, because it shows. They have
-added some cool new features and made plenty of changes under the hood. Let me
-give you a sneak preview of some of the new features: Jabber groupchats are
-supported. Configuration files are stored encrypted. You can now use
-ForkDaemon mode, which gives better stability over normal daemon mode, but
-doesn't require inetd. Also, server owners can now use the /OPER command to
-spy on their users. And--as I was specifically asked to mention--this is the
-first stable release that supports plugins. That's some Bitl changes for ya.
-
-BitlBee is cool, but ready when it's ready. Very Bitl.
-
-Sjoerd. LOL.
-
-(LOLBee by Erik Bosman.)
Index: doc/bitlbee.8
===================================================================
--- doc/bitlbee.8	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ doc/bitlbee.8	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -44,11 +44,6 @@
 
 \fBbitlbee\fP should be called by
-.BR inetd (8).
-(Or \fBbitlbeed\fP,
-if you can't run and/or configure \fBinetd\fP.) There is an experimental
-daemon mode too, in which BitlBee will serve all clients in one process
-(and does not require inetd), but this mode is still experimental.
-There are still some bugs left in BitlBee, and if they cause a crash,
-that would terminate the BitlBee connection for all clients.
+.BR inetd (8),
+or you can run it as a stand-alone daemon.
 .PP
 .SH OPTIONS
@@ -62,8 +57,7 @@
 Run in daemon mode. In this mode, BitlBee forks to the background and
 waits for new connections. All clients will be served from one process.
-This is still experimental. See the note above for more information.
 .IP "-F"
 Run in ForkDaemon mode. This is similar to ordinary daemon mode, but every
-client gets its own process. Easier to set up than inetd mode, but without
+client gets its own process. Easier to set up than inetd mode, and without
 the possible stability issues.
 .IP "-i \fIaddress\fP"
Index: doc/user-guide/commands.xml
===================================================================
--- doc/user-guide/commands.xml	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ doc/user-guide/commands.xml	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -589,4 +589,14 @@
 	</bitlbee-setting>
 
+	<bitlbee-setting name="root_nick" type="string" scope="global">
+		<default>root</default>
+
+		<description>
+			<para>
+				Normally the "bot" that takes all your BitlBee commands is called "root". If you don't like this name, you can rename it to anything else using the <emphasis>rename</emphasis> command, or by changing this setting.
+			</para>
+		</description>
+	</bitlbee-setting>
+
 	<bitlbee-setting name="save_on_quit" type="boolean" scope="global">
 		<default>true</default>
Index: irc.c
===================================================================
--- irc.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ irc.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -42,4 +42,33 @@
 }
 
+static char *set_eval_charset( set_t *set, char *value )
+{
+	irc_t *irc = set->data;
+	GIConv ic, oc;
+
+	if( g_strcasecmp( value, "none" ) == 0 )
+		value = g_strdup( "utf-8" );
+
+	if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
+	{
+		return NULL;
+	}
+	if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
+	{
+		g_iconv_close( ic );
+		return NULL;
+	}
+	
+	if( irc->iconv != (GIConv) -1 )
+		g_iconv_close( irc->iconv );
+	if( irc->oconv != (GIConv) -1 )
+		g_iconv_close( irc->oconv );
+	
+	irc->iconv = ic;
+	irc->oconv = oc;
+
+	return value;
+}
+
 irc_t *irc_new( int fd )
 {
@@ -64,4 +93,7 @@
 	irc->mynick = g_strdup( ROOT_NICK );
 	irc->channel = g_strdup( ROOT_CHAN );
+	
+	irc->iconv = (GIConv) -1;
+	irc->oconv = (GIConv) -1;
 	
 	if( global.conf->hostname )
@@ -119,4 +151,5 @@
 	set_add( &irc->set, "private", "true", set_eval_bool, irc );
 	set_add( &irc->set, "query_order", "lifo", NULL, irc );
+	set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
 	set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
 	set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
@@ -127,4 +160,7 @@
 	conf_loaddefaults( irc );
 	
+	/* Evaluator sets the iconv/oconv structures. */
+	set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
+	
 	return( irc );
 }
@@ -164,10 +200,12 @@
 	if( irc->sendbuffer && !immed )
 	{
-		/* We won't read from this socket anymore. Instead, we'll connect a timer
-		   to it that should shut down the connection in a second, just in case
-		   bitlbee_.._write doesn't do it first. */
+		/* Set up a timeout event that should shut down the connection
+		   in a second, just in case ..._write doesn't do it first. */
 		
 		b_event_remove( irc->r_watch_source_id );
-		irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
+		irc->r_watch_source_id = 0;
+		
+		b_event_remove( irc->ping_source_id );
+		irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
 	}
 	else
@@ -185,7 +223,6 @@
 
 /* Because we have no garbage collection, this is quite annoying */
-void irc_free(irc_t * irc)
-{
-	account_t *account;
+void irc_free( irc_t * irc )
+{
 	user_t *user, *usertmp;
 	
@@ -196,74 +233,84 @@
 			irc_usermsg( irc, "Error while saving settings!" );
 	
-	closesocket( irc->fd );
-	
-	if( irc->ping_source_id > 0 )
-		b_event_remove( irc->ping_source_id );
-	b_event_remove( irc->r_watch_source_id );
-	if( irc->w_watch_source_id > 0 )
-		b_event_remove( irc->w_watch_source_id );
-	
 	irc_connection_list = g_slist_remove( irc_connection_list, irc );
 	
-	for (account = irc->accounts; account; account = account->next) {
-		if (account->ic) {
-			imc_logout(account->ic, TRUE);
-		} else if (account->reconnect) {
-			cancel_auto_reconnect(account);
-		}
-	}
-	
-	g_free(irc->sendbuffer);
-	g_free(irc->readbuffer);
-	
-	g_free(irc->nick);
-	g_free(irc->user);
-	g_free(irc->host);
-	g_free(irc->realname);
-	g_free(irc->password);
-	
-	g_free(irc->myhost);
-	g_free(irc->mynick);
-	
-	g_free(irc->channel);
-	
-	while (irc->queries != NULL)
-		query_del(irc, irc->queries);
-	
-	while (irc->accounts)
-		if (irc->accounts->ic == NULL)
-			account_del(irc, irc->accounts);
+	while( irc->accounts )
+	{
+		if( irc->accounts->ic )
+			imc_logout( irc->accounts->ic, FALSE );
+		else if( irc->accounts->reconnect )
+			cancel_auto_reconnect( irc->accounts );
+		
+		if( irc->accounts->ic == NULL )
+			account_del( irc, irc->accounts );
 		else
 			/* Nasty hack, but account_del() doesn't work in this
 			   case and we don't want infinite loops, do we? ;-) */
 			irc->accounts = irc->accounts->next;
-	
-	while (irc->set)
-		set_del(&irc->set, irc->set->key);
-	
-	if (irc->users != NULL) {
+	}
+	
+	while( irc->queries != NULL )
+		query_del( irc, irc->queries );
+	
+	while( irc->set )
+		set_del( &irc->set, irc->set->key );
+	
+	if (irc->users != NULL)
+	{
 		user = irc->users;
-		while (user != NULL) {
-			g_free(user->nick);
-			g_free(user->away);
-			g_free(user->handle);
-			if(user->user!=user->nick) g_free(user->user);
-			if(user->host!=user->nick) g_free(user->host);
-			if(user->realname!=user->nick) g_free(user->realname);
-			b_event_remove(user->sendbuf_timer);
+		while( user != NULL )
+		{
+			g_free( user->nick );
+			g_free( user->away );
+			g_free( user->handle );
+			if( user->user != user->nick ) g_free( user->user );
+			if( user->host != user->nick ) g_free( user->host );
+			if( user->realname != user->nick ) g_free( user->realname );
+			b_event_remove( user->sendbuf_timer );
 					
 			usertmp = user;
 			user = user->next;
-			g_free(usertmp);
-		}
-	}
-	
-	g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL);
-	g_hash_table_destroy(irc->userhash);
-	
-	g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);
-	g_hash_table_destroy(irc->watches);
-	
-	g_free(irc);
+			g_free( usertmp );
+		}
+	}
+	
+	if( irc->ping_source_id > 0 )
+		b_event_remove( irc->ping_source_id );
+	if( irc->r_watch_source_id > 0 )
+		b_event_remove( irc->r_watch_source_id );
+	if( irc->w_watch_source_id > 0 )
+		b_event_remove( irc->w_watch_source_id );
+	
+	closesocket( irc->fd );
+	irc->fd = -1;
+	
+	g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
+	g_hash_table_destroy( irc->userhash );
+	
+	g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
+	g_hash_table_destroy( irc->watches );
+	
+	if( irc->iconv != (GIConv) -1 )
+		g_iconv_close( irc->iconv );
+	if( irc->oconv != (GIConv) -1 )
+		g_iconv_close( irc->oconv );
+	
+	g_free( irc->sendbuffer );
+	g_free( irc->readbuffer );
+	
+	g_free( irc->nick );
+	g_free( irc->user );
+	g_free( irc->host );
+	g_free( irc->realname );
+	g_free( irc->password );
+	
+	g_free( irc->myhost );
+	g_free( irc->mynick );
+	
+	g_free( irc->channel );
+	
+	g_free( irc->last_target );
+	
+	g_free( irc );
 	
 	if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
@@ -286,5 +333,5 @@
 void irc_process( irc_t *irc )
 {
-	char **lines, *temp, **cmd, *cs;
+	char **lines, *temp, **cmd;
 	int i;
 
@@ -295,9 +342,8 @@
 		for( i = 0; *lines[i] != '\0'; i ++ )
 		{
-			char conv[IRC_MAX_LINE+1];
+			char *conv = NULL;
 			
-			/* [WvG] Because irc_tokenize splits at every newline, the lines[] list
-			    should end with an empty string. This is why this actually works.
-			    Took me a while to figure out, Maurits. :-P */
+			/* [WvG] If the last line isn't empty, it's an incomplete line and we
+			   should wait for the rest to come in before processing it. */
 			if( lines[i+1] == NULL )
 			{
@@ -309,8 +355,12 @@
 			}
 			
-			if( ( cs = set_getstr( &irc->set, "charset" ) ) && g_strcasecmp( cs, "none" ) != 0 )
-			{
-				conv[IRC_MAX_LINE] = 0;
-				if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 )
+			if( irc->iconv != (GIConv) -1 )
+			{
+				gsize bytes_read, bytes_written;
+				
+				conv = g_convert_with_iconv( lines[i], -1, irc->iconv,
+				                             &bytes_read, &bytes_written, NULL );
+				
+				if( conv == NULL || bytes_read != strlen( lines[i] ) )
 				{
 					/* GLib can do strange things if things are not in the expected charset,
@@ -324,6 +374,9 @@
 						                  "expect by changing the charset setting. See "
 						                  "`help set charset' for more information. Your "
-						                  "message was ignored.", cs );
-						*conv = 0;
+						                  "message was ignored.",
+						                  set_getstr( &irc->set, "charset" ) );
+						
+						g_free( conv );
+						conv = NULL;
 					}
 					else
@@ -332,5 +385,5 @@
 						           "Warning: invalid characters received at login time." );
 						
-						strncpy( conv, lines[i], IRC_MAX_LINE );
+						conv = g_strdup( lines[i] );
 						for( temp = conv; *temp; temp ++ )
 							if( *temp & 0x80 )
@@ -341,9 +394,13 @@
 			}
 			
-			if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
-				continue;
-			irc_exec( irc, cmd );
+			if( lines[i] )
+			{
+				if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
+					continue;
+				irc_exec( irc, cmd );
+				g_free( cmd );
+			}
 			
-			g_free( cmd );
+			g_free( conv );
 			
 			/* Shouldn't really happen, but just in case... */
@@ -369,40 +426,39 @@
 char **irc_tokenize( char *buffer )
 {
-	int i, j;
+	int i, j, n = 3;
 	char **lines;
 
-	/* Count the number of elements we're gonna need. */
-	for( i = 0, j = 1; buffer[i] != '\0'; i ++ )
-	{
-		if( buffer[i] == '\n' )
-			if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
-				j ++;
-	}
-	
-	/* Allocate j+1 elements. */
-	lines = g_new( char *, j + 1 );
+	/* Allocate n+1 elements. */
+	lines = g_new( char *, n + 1 );
+	
+	lines[0] = buffer;
+	
+	/* Split the buffer in several strings, and accept any kind of line endings,
+	 * knowing that ERC on Windows may send something interesting like \r\r\n,
+	 * and surely there must be clients that think just \n is enough... */
+	for( i = 0, j = 0; buffer[i] != '\0'; i ++ )
+	{
+		if( buffer[i] == '\r' || buffer[i] == '\n' )
+		{
+			while( buffer[i] == '\r' || buffer[i] == '\n' )
+				buffer[i++] = '\0';
+			
+			lines[++j] = buffer + i;
+			
+			if( j >= n )
+			{
+				n *= 2;
+				lines = g_renew( char *, lines, n + 1 );
+			}
+
+			if( buffer[i] == '\0' )
+				break;
+		}
+	}
 	
 	/* NULL terminate our list. */ 
-	lines[j] = NULL;
-	
-	lines[0] = buffer;
-	
-	/* Split the buffer in several strings, using \r\n as our seperator, where \r is optional.
-	 * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too. 
-	 */
-	for( i = 0, j = 0; buffer[i] != '\0'; i ++)
-	{
-		if( buffer[i] == '\n' )
-		{
-			buffer[i] = '\0';
-			
-			if( i > 0 && buffer[i-1] == '\r' )
-				buffer[i-1] = '\0';
-			if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
-				lines[++j] = buffer + i + 1;
-		}
-	}
-	
-	return( lines );
+	lines[++j] = NULL;
+	
+	return lines;
 }
 
@@ -538,5 +594,4 @@
 
 	return;
-
 }
 
@@ -544,5 +599,5 @@
 {
 	int size;
-	char line[IRC_MAX_LINE+1], *cs;
+	char line[IRC_MAX_LINE+1];
 		
 	/* Don't try to write anything new anymore when shutting down. */
@@ -550,18 +605,22 @@
 		return;
 	
-	line[IRC_MAX_LINE] = 0;
+	memset( line, 0, sizeof( line ) );
 	g_vsnprintf( line, IRC_MAX_LINE - 2, format, params );
-	
 	strip_newlines( line );
-	if( ( cs = set_getstr( &irc->set, "charset" ) ) &&
-	    g_strcasecmp( cs, "none" ) != 0 && g_strcasecmp( cs, "utf-8" ) != 0 )
-	{
-		char conv[IRC_MAX_LINE+1];
-		
-		conv[IRC_MAX_LINE] = 0;
-		if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 )
-			strcpy( line, conv );
-	}
-	strcat( line, "\r\n" );
+	
+	if( irc->oconv != (GIConv) -1 )
+	{
+		gsize bytes_read, bytes_written;
+		char *conv;
+		
+		conv = g_convert_with_iconv( line, -1, irc->oconv,
+		                             &bytes_read, &bytes_written, NULL );
+
+		if( bytes_read == strlen( line ) )
+			strncpy( line, conv, IRC_MAX_LINE - 2 );
+		
+		g_free( conv );
+	}
+	g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 );
 	
 	if( irc->sendbuffer != NULL )
@@ -736,5 +795,10 @@
 	irc_spawn( irc, u );
 	
-	irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQs are answered there." );
+	irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
+	                  "If you've never used BitlBee before, please do read the help "
+	                  "information using the \x02help\x02 command. Lots of FAQs are "
+	                  "answered there.\n"
+	                  "If you already have an account on this server, just use the "
+	                  "\x02identify\x02 command to identify yourself." );
 	
 	if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
@@ -742,4 +806,14 @@
 	
 	irc->status |= USTATUS_LOGGED_IN;
+	
+	/* This is for bug #209 (use PASS to identify to NickServ). */
+	if( irc->password != NULL )
+	{
+		char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
+		
+		irc_setpass( irc, NULL );
+		root_command( irc, send_cmd );
+		g_free( send_cmd[1] );
+	}
 }
 
Index: irc.h
===================================================================
--- irc.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ irc.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -61,4 +61,5 @@
 	char *sendbuffer;
 	char *readbuffer;
+	GIConv iconv, oconv;
 
 	int sentbytes;
@@ -69,5 +70,7 @@
 	char *host;
 	char *realname;
-	char *password;
+	char *password; /* HACK: Used to save the user's password, but before
+	                   logging in, this may contain a password we should
+	                   send to identify after USER/NICK are received. */
 
 	char umode[8];
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ irc_commands.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -30,5 +30,17 @@
 static void irc_cmd_pass( irc_t *irc, char **cmd )
 {
-	if( global.conf->auth_pass &&
+	if( irc->status & USTATUS_LOGGED_IN )
+	{
+		char *send_cmd[] = { "identify", cmd[1], NULL };
+		
+		/* We're already logged in, this client seems to send the PASS
+		   command last. (Possibly it won't send it at all if it turns
+		   out we don't require it, which will break this feature.)
+		   Try to identify using the given password. */
+		return root_command( irc, send_cmd );
+	}
+	/* Handling in pre-logged-in state, first see if this server is
+	   password-protected: */
+	else if( global.conf->auth_pass &&
 	    ( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ?
 	        md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 :
@@ -38,7 +50,13 @@
 		irc_check_login( irc );
 	}
-	else
+	else if( global.conf->auth_pass )
 	{
 		irc_reply( irc, 464, ":Incorrect password" );
+	}
+	else
+	{
+		/* Remember the password and try to identify after USER/NICK. */
+		irc_setpass( irc, cmd[1] );
+		irc_check_login( irc );
 	}
 }
@@ -260,6 +278,5 @@
 			if( cmd[1] != irc->last_target )
 			{
-				if( irc->last_target )
-					g_free( irc->last_target );
+				g_free( irc->last_target );
 				irc->last_target = g_strdup( cmd[1] );
 			}
@@ -581,5 +598,5 @@
 
 static const command_t irc_commands[] = {
-	{ "pass",        1, irc_cmd_pass,        IRC_CMD_PRE_LOGIN },
+	{ "pass",        1, irc_cmd_pass,        0 },
 	{ "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
 	{ "nick",        1, irc_cmd_nick,        0 },
Index: lib/arc.h
===================================================================
--- lib/arc.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ lib/arc.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -31,4 +31,8 @@
 };
 
+#ifndef G_GNUC_MALLOC
+#define G_GNUC_MALLOC
+#endif
+
 G_GNUC_MALLOC struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles );
 unsigned char arc_getbyte( struct arc_state *st );
Index: lib/proxy.c
===================================================================
--- lib/proxy.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ lib/proxy.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -114,4 +114,5 @@
 {
 	struct sockaddr_in *sin;
+	struct sockaddr_in me;
 	int fd = -1;
 
@@ -127,4 +128,14 @@
 
 	sock_make_nonblocking(fd);
+	
+	if( global.conf->iface_out )
+	{
+		me.sin_family = AF_INET;
+		me.sin_port = 0;
+		me.sin_addr.s_addr = inet_addr( global.conf->iface_out );
+		
+		if( bind( fd, (struct sockaddr *) &me, sizeof( me ) ) != 0 )
+			event_debug( "bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out );
+	}
 	
 	event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd);
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/jabber/jabber.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -37,9 +37,28 @@
 GSList *jabber_connections;
 
+/* First enty is the default */
+static const int jabber_port_list[] = {
+	5222,
+	5223,
+	5220,
+	5221,
+	5224,
+	5225,
+	5226,
+	5227,
+	5228,
+	5229,
+	80,
+	443,
+	0
+};
+
 static void jabber_init( account_t *acc )
 {
 	set_t *s;
-	
-	s = set_add( &acc->set, "port", JABBER_PORT_DEFAULT, set_eval_int, acc );
+	char str[16];
+	
+	g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] );
+	s = set_add( &acc->set, "port", str, set_eval_int, acc );
 	s->flags |= ACC_SET_OFFLINE_ONLY;
 	
@@ -72,4 +91,5 @@
 	struct ns_srv_reply *srv = NULL;
 	char *connect_to, *s;
+	int i;
 	
 	/* For now this is needed in the _connected() handlers if using
@@ -177,9 +197,11 @@
 	imcb_log( ic, "Connecting" );
 	
-	if( set_getint( &acc->set, "port" ) < JABBER_PORT_MIN ||
-	    set_getint( &acc->set, "port" ) > JABBER_PORT_MAX )
-	{
-		imcb_log( ic, "Incorrect port number, must be in the %d-%d range",
-		               JABBER_PORT_MIN, JABBER_PORT_MAX );
+	for( i = 0; jabber_port_list[i] > 0; i ++ )
+		if( set_getint( &acc->set, "port" ) == jabber_port_list[i] )
+			break;
+
+	if( jabber_port_list[i] == 0 )
+	{
+		imcb_log( ic, "Illegal port number" );
 		imc_logout( ic, FALSE );
 		return;
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/jabber/jabber.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -134,8 +134,4 @@
 
 #define JABBER_XMLCONSOLE_HANDLE "xmlconsole"
-
-#define JABBER_PORT_DEFAULT "5222"
-#define JABBER_PORT_MIN 5220
-#define JABBER_PORT_MAX 5229
 
 /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/jabber/jabber_util.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -246,6 +246,8 @@
 };
 
-static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla )
-{
+static void jabber_buddy_ask_yes( void *data )
+{
+	struct jabber_buddy_ask_data *bla = data;
+	
 	presence_send_request( bla->ic, bla->handle, "subscribed" );
 	
@@ -257,6 +259,8 @@
 }
 
-static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla )
-{
+static void jabber_buddy_ask_no( void *data )
+{
+	struct jabber_buddy_ask_data *bla = data;
+	
 	presence_send_request( bla->ic, bla->handle, "subscribed" );
 	
Index: protocols/jabber/message.c
===================================================================
--- protocols/jabber/message.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/jabber/message.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -49,4 +49,21 @@
 	{
 		GString *fullmsg = g_string_new( "" );
+
+		for( c = node->children; ( c = xt_find_node( c, "x" ) ); c = c->next )
+		{
+			char *ns = xt_find_attr( c, "xmlns" ), *room;
+			struct xt_node *inv, *reason;
+			
+			if( strcmp( ns, XMLNS_MUC_USER ) == 0 &&
+			    ( inv = xt_find_node( c->children, "invite" ) ) )
+			{
+				room = from;
+				from = xt_find_attr( inv, "from" ) ? : from;
+
+				g_string_append_printf( fullmsg, "<< \002BitlBee\002 - Invitation to chatroom %s >>\n", room );
+				if( ( reason = xt_find_node( inv->children, "reason" ) ) && reason->text_len > 0 )
+					g_string_append( fullmsg, reason->text );
+			}
+		}
 		
 		if( ( s = strchr( from, '/' ) ) )
Index: protocols/msn/msn.h
===================================================================
--- protocols/msn/msn.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/msn/msn.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -29,5 +29,5 @@
 #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r"
 
-#ifdef DEBUG
+#ifdef DEBUG_MSN
 #define debug( text... ) imcb_log( ic, text );
 #else
Index: protocols/msn/msn_util.c
===================================================================
--- protocols/msn/msn_util.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/msn/msn_util.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -90,6 +90,8 @@
 };
 
-static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla )
-{
+static void msn_buddy_ask_yes( void *data )
+{
+	struct msn_buddy_ask_data *bla = data;
+	
 	msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname );
 	
@@ -102,6 +104,8 @@
 }
 
-static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla )
-{
+static void msn_buddy_ask_no( void *data )
+{
+	struct msn_buddy_ask_data *bla = data;
+	
 	msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname );
 	
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/msn/ns.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -178,5 +178,13 @@
 			
 			debug( "Connecting to a new switchboard with key %s", cmd[5] );
-			sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW );
+
+			if( ( sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ) ) == NULL )
+			{
+				/* Although this isn't strictly fatal for the NS connection, it's
+				   definitely something serious (we ran out of file descriptors?). */
+				imcb_error( ic, "Could not create new switchboard" );
+				imc_logout( ic, TRUE );
+				return( 0 );
+			}
 			
 			if( md->msgq )
@@ -468,6 +476,16 @@
 		debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] );
 		
-		sb = msn_sb_create( ic, server, port, cmd[4], session );
-		sb->who = g_strdup( cmd[5] );
+		if( ( sb = msn_sb_create( ic, server, port, cmd[4], session ) ) == NULL )
+		{
+			/* Although this isn't strictly fatal for the NS connection, it's
+			   definitely something serious (we ran out of file descriptors?). */
+			imcb_error( ic, "Could not create new switchboard" );
+			imc_logout( ic, TRUE );
+			return( 0 );
+		}
+		else
+		{
+			sb->who = g_strdup( cmd[5] );
+		}
 	}
 	else if( strcmp( cmd[0], "ADD" ) == 0 )
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/nogaim.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -343,5 +343,6 @@
 /* dialogs.c */
 
-void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont )
+void imcb_ask( struct im_connection *ic, char *msg, void *data,
+               query_callback doit, query_callback dont )
 {
 	query_add( ic->irc, ic, msg, doit, dont, data );
@@ -495,16 +496,18 @@
 };
 
-void show_got_added_no( gpointer w, struct show_got_added_data *data )
-{
-	g_free( data->handle );
+void show_got_added_no( void *data )
+{
+	g_free( ((struct show_got_added_data*)data)->handle );
 	g_free( data );
 }
 
-void show_got_added_yes( gpointer w, struct show_got_added_data *data )
-{
-	data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL );
-	/* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */
-	
-	return show_got_added_no( w, data );
+void show_got_added_yes( void *data )
+{
+	struct show_got_added_data *sga = data;
+	
+	sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL );
+	/* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */
+	
+	return show_got_added_no( data );
 }
 
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/nogaim.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -42,4 +42,5 @@
 #include "account.h"
 #include "proxy.h"
+#include "query.h"
 #include "md5.h"
 
@@ -261,5 +262,5 @@
  * - 'doit' or 'dont' will be called depending of the answer of the user.
  */
-G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont );
+G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont );
 G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname );
 
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/oscar/oscar.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -1084,6 +1084,6 @@
 }
 
-void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv);
-void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv);
+void oscar_accept_chat(void *data);
+void oscar_reject_chat(void *data);
 	
 static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) {
@@ -1119,5 +1119,6 @@
 }
 
-static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) {
+static void gaim_icq_authgrant(void *data_) {
+	struct icq_auth *data = data_;
 	char *uin, message;
 	struct oscar_data *od = (struct oscar_data *)data->ic->proto_data;
@@ -1134,5 +1135,6 @@
 }
 
-static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) {
+static void gaim_icq_authdeny(void *data_) {
+	struct icq_auth *data = data_;
 	char *uin, *message;
 	struct oscar_data *od = (struct oscar_data *)data->ic->proto_data;
@@ -2588,6 +2590,8 @@
 }
 
-void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv)
+void oscar_accept_chat(void *data)
 {
+	struct aim_chat_invitation * inv = data;
+	
 	oscar_chat_join(inv->ic, inv->name, NULL, NULL);
 	g_free(inv->name);
@@ -2595,6 +2599,8 @@
 }
 
-void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv)
+void oscar_reject_chat(void *data)
 {
+	struct aim_chat_invitation * inv = data;
+	
 	g_free(inv->name);
 	g_free(inv);
Index: protocols/yahoo/libyahoo2.c
===================================================================
--- protocols/yahoo/libyahoo2.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/yahoo/libyahoo2.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -381,5 +381,4 @@
 
 /* call repeatedly to get the next one */
-/*
 static struct yahoo_input_data * find_input_by_id(int id)
 {
@@ -392,5 +391,4 @@
 	return NULL;
 }
-*/
 
 static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
@@ -797,4 +795,5 @@
 {
 	struct yahoo_data *yd = find_conn_by_id(id);
+	
 	if(!yd)
 		return;
@@ -3166,5 +3165,5 @@
 
 	LOG(("write callback: id=%d fd=%d data=%p", id, fd, data));
-	if(!yid || !yid->txqueues)
+	if(!yid || !yid->txqueues || !find_conn_by_id(id))
 		return -2;
 	
@@ -3842,9 +3841,7 @@
 	}
 
-	
-/*	do {
+	do {
 		yahoo_input_close(yid);
-	} while((yid = find_input_by_id(id)));*/
-	
+	} while((yid = find_input_by_id(id)));
 }
 
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ protocols/yahoo/yahoo.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -454,8 +454,4 @@
 	struct byahoo_write_ready_data *d = data;
 	
-	if( !byahoo_get_ic_by_id( d->id ) )
-		/* WTF doesn't libyahoo clean this up? */
-		return FALSE;
-	
 	yahoo_write_ready( d->id, d->fd, d->data );
 	
@@ -797,6 +793,8 @@
 }
 
-static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv )
-{
+static void byahoo_accept_conf( void *data )
+{
+	struct byahoo_conf_invitation *inv = data;
+	
 	yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name );
 	imcb_chat_add_buddy( inv->c, inv->ic->acc->user );
@@ -805,6 +803,8 @@
 }
 
-static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv )
-{
+static void byahoo_reject_conf( void *data )
+{
+	struct byahoo_conf_invitation *inv = data;
+	
 	yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" );
 	imcb_chat_free( inv->c );
Index: query.c
===================================================================
--- query.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ query.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -30,5 +30,6 @@
 static query_t *query_default( irc_t *irc );
 
-query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data )
+query_t *query_add( irc_t *irc, struct im_connection *ic, char *question,
+                    query_callback yes, query_callback no, void *data )
 {
 	query_t *q = g_new0( query_t, 1 );
@@ -144,5 +145,5 @@
 		else
 			irc_usermsg( irc, "Accepted: %s", q->question );
-		q->yes( NULL, q->data );
+		q->yes( q->data );
 	}
 	else
@@ -152,5 +153,5 @@
 		else
 			irc_usermsg( irc, "Rejected: %s", q->question );
-		q->no( NULL, q->data );
+		q->no( q->data );
 	}
 	q->data = NULL;
Index: query.h
===================================================================
--- query.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ query.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -27,15 +27,17 @@
 #define _QUERY_H
 
+typedef void (*query_callback) ( void *data );
+
 typedef struct query
 {
 	struct im_connection *ic;
 	char *question;
-	void (* yes) ( gpointer w, void *data );
-	void (* no) ( gpointer w, void *data );
+	query_callback yes, no;
 	void *data;
 	struct query *next;
 } query_t;
 
-query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data );
+query_t *query_add( irc_t *irc, struct im_connection *ic, char *question,
+                    query_callback yes, query_callback no, void *data );
 void query_del( irc_t *irc, query_t *q );
 void query_del_by_conn( irc_t *irc, struct im_connection *ic );
Index: root_commands.c
===================================================================
--- root_commands.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ root_commands.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -204,22 +204,36 @@
 }
 
-void cmd_account_del_yes( gpointer w, void *data )
-{
-	account_t *a = data;
-	irc_t *irc = a->irc;
-	
-	if( a->ic )
-	{
-		irc_usermsg( irc, "Account is still logged in, can't delete" );
-	}
-	else
-	{
-		account_del( irc, a );
-		irc_usermsg( irc, "Account deleted" );
-	}
-}
-
-void cmd_account_del_no( gpointer w, void *data )
-{
+struct cmd_account_del_data
+{
+	account_t *a;
+	irc_t *irc;
+};
+
+void cmd_account_del_yes( void *data )
+{
+	struct cmd_account_del_data *cad = data;
+	account_t *a;
+	
+	for( a = cad->irc->accounts; a && a != cad->a; a = a->next );
+	
+	if( a == NULL )
+	{
+		irc_usermsg( cad->irc, "Account already deleted" );
+	}
+	else if( a->ic )
+	{
+		irc_usermsg( cad->irc, "Account is still logged in, can't delete" );
+	}
+	else
+	{
+		account_del( cad->irc, a );
+		irc_usermsg( cad->irc, "Account deleted" );
+	}
+	g_free( data );
+}
+
+void cmd_account_del_no( void *data )
+{
+	g_free( data );
 }
 
@@ -278,5 +292,10 @@
 		else
 		{
+			struct cmd_account_del_data *cad;
 			char *msg;
+			
+			cad = g_malloc( sizeof( struct cmd_account_del_data ) );
+			cad->a = a;
+			cad->irc = irc;
 			
 			msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will "
@@ -285,5 +304,5 @@
 			                       "set' command. Are you sure you want to delete this "
 			                       "account?", a->prpl->name, a->user );
-			query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, a );
+			query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad );
 			g_free( msg );
 		}
@@ -404,4 +423,10 @@
 			acc_handle = g_strdup( cmd[2] );
 		
+		if( !acc_handle )
+		{
+			irc_usermsg( irc, "Not enough parameters given (need %d)", 3 );
+			return;
+		}
+		
 		if( ( tmp = strchr( acc_handle, '/' ) ) )
 		{
@@ -584,4 +609,7 @@
 			g_free( irc->mynick );
 			irc->mynick = g_strdup( cmd[2] );
+			
+			if( strcmp( cmd[0], "set_rename" ) != 0 )
+				set_setstr( &irc->set, "root_nick", cmd[2] );
 		}
 		else if( u->send_handler == buddy_send_handler )
@@ -592,4 +620,18 @@
 		irc_usermsg( irc, "Nick successfully changed" );
 	}
+}
+
+char *set_eval_root_nick( set_t *set, char *new_nick )
+{
+	irc_t *irc = set->data;
+	
+	if( strcmp( irc->mynick, new_nick ) != 0 )
+	{
+		char *cmd[] = { "set_rename", irc->mynick, new_nick, NULL };
+		
+		cmd_rename( irc, cmd );
+	}
+	
+	return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : NULL;
 }
 
Index: set.c
===================================================================
--- set.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ set.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -230,17 +230,2 @@
 	return value;
 }
-
-char *set_eval_charset( set_t *set, char *value )
-{
-	GIConv cd;
-
-	if( g_strcasecmp( value, "none" ) == 0 )
-		return value;
-
-	cd = g_iconv_open( "UTF-8", value );
-	if( cd == (GIConv) -1 )
-		return NULL;
-
-	g_iconv_close( cd );
-	return value;
-}
Index: set.h
===================================================================
--- set.h	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ set.h	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -97,5 +97,4 @@
 char *set_eval_to_char( set_t *set, char *value );
 char *set_eval_ops( set_t *set, char *value );
-char *set_eval_charset( set_t *set, char *value );
 
 #endif /* __SET_H__ */
Index: storage_xml.c
===================================================================
--- storage_xml.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ storage_xml.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -29,4 +29,5 @@
 #include "arc.h"
 #include "md5.h"
+#include <glib/gstdio.h>
 
 typedef enum
@@ -243,7 +244,7 @@
 static void xml_init( void )
 {
-	if( access( global.conf->configdir, F_OK ) != 0 )
+	if( ! g_file_test( global.conf->configdir, G_FILE_TEST_EXISTS ) )
 		log_message( LOGLVL_WARNING, "The configuration directory `%s' does not exist. Configuration won't be saved.", global.conf->configdir );
-	else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 )
+	else if( ! g_file_test( global.conf->configdir, G_FILE_TEST_EXISTS ) || g_access( global.conf->configdir, W_OK ) != 0 )
 		log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to `%s'.", global.conf->configdir );
 }
@@ -372,5 +373,5 @@
 	g_free( path2 );
 	
-	if( !overwrite && access( path, F_OK ) != -1 )
+	if( !overwrite && g_file_test( path, G_FILE_TEST_EXISTS ) )
 		return STORAGE_ALREADY_EXISTS;
 	
Index: tests/check_irc.c
===================================================================
--- tests/check_irc.c	(revision f00e3ad082f84bd3e513bffa6ebe6800c4f66282)
+++ tests/check_irc.c	(revision d41907342cdb619c80bb7013136e9609f725e0e4)
@@ -37,6 +37,6 @@
 	irc = irc_new(g_io_channel_unix_get_fd(ch1));
 
-	fail_unless(g_io_channel_write_chars(ch2, "NICK bla\r\n"
-			"USER a a a a\r\n", -1, NULL, NULL) == G_IO_STATUS_NORMAL);
+	fail_unless(g_io_channel_write_chars(ch2, "NICK bla\r\r\n"
+			"USER a a a a\n", -1, NULL, NULL) == G_IO_STATUS_NORMAL);
 	fail_unless(g_io_channel_flush(ch2, NULL) == G_IO_STATUS_NORMAL);
 
