Index: .bzrignore
===================================================================
--- .bzrignore	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ .bzrignore	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -17,2 +17,5 @@
 *.gcno
 *.o
+coverage
+bitlbee.info
+bitlbee.exe
Index: Makefile
===================================================================
--- Makefile	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ Makefile	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -10,7 +10,17 @@
 
 # Program variables
-objects = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) unix.o user.o dcc.o
-headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h dcc.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h protocols/ft.h
+objects = account.o bitlbee.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o dcc.o
+headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h protocols/ft.h
 subdirs = lib protocols
+
+ifeq ($(TARGET),i586-mingw32msvc)
+objects += win32.o
+LFLAGS+=-lws2_32
+EFLAGS+=-lsecur32
+OUTFILE=bitlbee.exe
+else
+objects += unix.o conf.o log.o
+OUTFILE=bitlbee
+endif
 
 # Expansion of variables
Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ bitlbee.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -118,9 +118,10 @@
 	
 	if( global.conf->runmode == RUNMODE_FORKDAEMON )
-		ipc_master_load_state();
+		ipc_master_load_state( getenv( "_BITLBEE_RESTART_STATE" ) );
 
 	if( global.conf->runmode == RUNMODE_DAEMON || global.conf->runmode == RUNMODE_FORKDAEMON )
 		ipc_master_listen_socket();
 	
+#ifndef _WIN32
 	if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
 	{
@@ -132,4 +133,5 @@
 		log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile );
 	}
+#endif
 	
 	return( 0 );
@@ -140,7 +142,4 @@
 	if( !irc_new( 0 ) )
 		return( 1 );
-	
-	log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
-	log_link( LOGLVL_WARNING, LOGOUTPUT_IRC );
 	
 	return( 0 );
@@ -254,5 +253,4 @@
 	struct sockaddr_in conn_info;
 	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
-	pid_t client_pid = 0;
 	
 	if( new_socket == -1 )
@@ -262,6 +260,8 @@
 	}
 	
+#ifndef _WIN32
 	if( global.conf->runmode == RUNMODE_FORKDAEMON )
 	{
+		pid_t client_pid = 0;
 		int fds[2];
 		
@@ -320,4 +320,5 @@
 	}
 	else
+#endif
 	{
 		log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ bitlbee.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -29,6 +29,9 @@
 #define _GNU_SOURCE /* Stupid GNU :-P */
 
+/* Depend on Windows 2000 for now since we need getaddrinfo() */
+#define _WIN32_WINNT 0x0501
+
 #define PACKAGE "BitlBee"
-#define BITLBEE_VERSION "1.2"
+#define BITLBEE_VERSION "1.2.1"
 #define VERSION BITLBEE_VERSION
 
@@ -48,7 +51,8 @@
 #include <stdio.h>
 #include <ctype.h>
+#include <errno.h>
+
 #ifndef _WIN32
 #include <syslog.h>
-#include <errno.h>
 #endif
 
@@ -94,8 +98,4 @@
 #undef g_main_quit
 #define g_main_quit		__PLEASE_USE_B_MAIN_QUIT__
-
-#ifndef F_OK
-#define F_OK 0
-#endif
 
 #ifndef G_GNUC_MALLOC
Index: conf.c
===================================================================
--- conf.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ conf.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -79,5 +79,5 @@
 	}
 	
-	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:u:" ) ) >= 0 )
+	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hu:" ) ) >= 0 )
 	/*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
 	{
@@ -146,12 +146,4 @@
 			        "  -h  Show this help page.\n" );
 			return NULL;
-		}
-		else if( opt == 'R' )
-		{
-			/* We can't load the statefile yet (and should make very sure we do this
-			   only once), so set the filename here and load the state information
-			   when initializing ForkDaemon. (This option only makes sense in that
-			   mode anyway!) */
-			ipc_master_set_statefile( optarg );
 		}
 		else if( opt == 'u' )
Index: configure
===================================================================
--- configure	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ configure	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -20,4 +20,5 @@
 ipcsocket='/var/run/bitlbee.sock'
 pcdir='$prefix/lib/pkgconfig'
+systemlibdirs="/lib /usr/lib /usr/local/lib"
 
 msn=1
@@ -74,4 +75,6 @@
 --ssl=...	SSL library to use (gnutls, nss, openssl, bogus, auto)
 							$ssl
+
+--target=...	Cross compilation target 		same as host
 EOF
 		exit;
@@ -107,7 +110,7 @@
 PCDIR=$pcdir
 
+TARGET=$target
 ARCH=$arch
 CPU=$cpu
-OUTFILE=bitlbee
 
 DESTDIR=
@@ -132,4 +135,16 @@
 EOF
 
+
+
+if [ -n "$target" ]; then
+	PKG_CONFIG_LIBDIR=/usr/$target/lib/pkgconfig
+	export PKG_CONFIG_LIBDIR
+	PATH=/usr/$target/bin:$PATH
+	CC=$target-cc
+	LD=$target-ld
+	systemlibdirs="/usr/$target/lib"
+fi
+
+
 if [ "$debug" = "1" ]; then
 	[ -z "$CFLAGS" ] && CFLAGS=-g
@@ -158,12 +173,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 +230,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`
@@ -267,4 +291,6 @@
 elif [ "$ssl" = "nss" ]; then
 	detect_nss
+elif [ "$ssl" = "sspi" ]; then
+	echo
 elif [ "$ssl" = "openssl" ]; then
 	echo
@@ -323,5 +349,5 @@
 echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
 
-for i in /lib /usr/lib /usr/local/lib; do
+for i in $systemlibdirs; do
 	if [ -f $i/libresolv.a ]; then
 		echo '#define HAVE_RESOLV_A' >> config.h
@@ -375,6 +401,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
 
@@ -483,4 +509,6 @@
 	echo 'Cygwin is not officially supported.'
 ;;
+Windows )
+;;
 * )
 	echo 'We haven'\''t tested BitlBee on many platforms yet, yours is untested. YMMV.'
@@ -489,4 +517,8 @@
 esac
 
+if [ -n "$target" ]; then
+	echo "Cross-compiling for: $target"
+fi
+
 echo
 echo 'Configuration done:'
Index: debian/bitlbee.init
===================================================================
--- debian/bitlbee.init	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ debian/bitlbee.init	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -44,5 +44,4 @@
 	
 	start-stop-daemon --start --quiet --pidfile $PIDFILE \
-		-c bitlbee: \
 		--exec $DAEMON -- -p $BITLBEE_PORT -P $PIDFILE $BITLBEE_OPTS
 }
Index: debian/changelog
===================================================================
--- debian/changelog	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ debian/changelog	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -1,2 +1,17 @@
+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
+
+  * Add myself to uploaders.
+  * Bump standards version to 3.8.0.
+  * Fix FSF address.
+  * Avoid changing uid from init script. (Closes: #474589)
+
+ -- Jelmer Vernooij <jelmer@samba.org>  Mon, 16 Jun 2008 00:53:20 +0200
+
 bitlbee (1.2-4) unstable; urgency=low
 
Index: debian/control
===================================================================
--- debian/control	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ debian/control	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -3,6 +3,10 @@
 Priority: optional
 Maintainer: Wilmer van der Gaast <wilmer@gaast.net>
-Standards-Version: 3.5.9
+Uploaders: Jelmer Vernooij <jelmer@samba.org>
+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
 
 Package: bitlbee
Index: debian/copyright
===================================================================
--- debian/copyright	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ debian/copyright	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -26,6 +26,6 @@
   You should have received a copy of the GNU General Public License with
   the Debian GNU/Linux distribution in file /usr/share/common-licenses/GPL;
-  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-  Suite 330, Boston, MA  02111-1307  USA
+  if not, write to the Free Software Foundation, Inc., 51 Franklin St, 
+  Fifth Floor, Boston, MA 02110-1301, USA.
 ============================================================================
 
@@ -40,5 +40,5 @@
 
  Copyright (C) 2000  Free Software Foundation, Inc.
-     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ 	51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
Index: debian/rules
===================================================================
--- debian/rules	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ debian/rules	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -22,5 +22,5 @@
 	[ "`whoami`" = "root" -a -d debian ]
 	rm -rf build-arch-stamp debian/bitlbee debian/*.substvars debian/files debian/bitlbee-dev
-	-$(MAKE) distclean
+	$(MAKE) distclean
 #	-$(MAKE) -C doc/ clean
 				
Index: doc/BUILD.win32
===================================================================
--- doc/BUILD.win32	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
+++ doc/BUILD.win32	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -0,0 +1,10 @@
+Instructions for building BitlBee for Windows
+=============================================
+
+1) Install the mingw32 compiler
+
+2) Compile GLib2 for the target i586-mingw32msvc
+
+3) Cross-compile BitlBee:
+
+$ ./configure --target=i586-mingw32msvc --ssl=bogus --arch=Windows
Index: doc/CHANGES
===================================================================
--- doc/CHANGES	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ doc/CHANGES	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -1,2 +1,7 @@
+This ChangeLog mostly lists changes relevant to users. A full log can be
+found in the bzr commit logs, for example you can try:
+
+http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
+
 Version 1.2.1:
 - Fixed proxy support.
@@ -10,6 +15,20 @@
   password in your IRC client.
 - Compatible with all crazy kinds of line endings that clients can send.
-
-Finished ...
+- Changed root nicknames are now saved.
+- Added ClientInterface setting to bind() outgoing connections to a specific
+  network interface.
+- Support for receiving Jabber chatroom invitations.
+- Relaxed port restriction of the Jabber module: added ports 80 and 443.
+- Preserving case in Jabber resources of buddies, since these should
+  officially be treated as case sensitive.
+- Fully stripping spaces from AIM screennames, this didn't happen completely
+  which severly breaks the IRC protocol.
+- Removed all the yellow tape around daemon mode, it's pretty mature by now:
+  testing.bitlbee.org serves all (~30) SSL users from one daemon mode
+  process without any serious stability issues.
+- Fixed GLib <2.6 compatibility issue.
+- Misc. memory leak/crash fixes.
+
+Finished 24 Jun 2008
 
 Version 1.2:
Index: ipc.c
===================================================================
--- ipc.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ ipc.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -33,5 +33,4 @@
 
 GSList *child_list = NULL;
-static char *statefile = NULL;
 
 static void ipc_master_cmd_client( irc_t *data, char **cmd )
@@ -63,4 +62,23 @@
 }
 
+static void ipc_master_cmd_deaf( irc_t *data, char **cmd )
+{
+	if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		b_event_remove( global.listen_watch_source_id );
+		close( global.listen_socket );
+		
+		global.listen_socket = global.listen_watch_source_id = -1;
+	
+		ipc_to_children_str( "OPERMSG :Closed listening socket, waiting "
+		                     "for all users to disconnect." );
+	}
+	else
+	{
+		ipc_to_children_str( "OPERMSG :The DEAF command only works in "
+		                     "normal daemon mode. Try DIE instead." );
+	}
+}
+
 void ipc_master_cmd_rehash( irc_t *data, char **cmd )
 {
@@ -98,4 +116,5 @@
 	{ "hello",      0, ipc_master_cmd_client,     0 },
 	{ "die",        0, ipc_master_cmd_die,        0 },
+	{ "deaf",       0, ipc_master_cmd_deaf,       0 },
 	{ "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
 	{ "wall",       1, NULL,                      IPC_CMD_TO_CHILDREN },
@@ -209,10 +228,10 @@
 }
 
+/* Return just one line. Returns NULL if something broke, an empty string
+   on temporary "errors" (EAGAIN and friends). */
 static char *ipc_readline( int fd )
 {
-	char *buf, *eol;
+	char buf[513], *eol;
 	int size;
-	
-	buf = g_new0( char, 513 );
 	
 	/* Because this is internal communication, it should be pretty safe
@@ -221,5 +240,5 @@
 	   sockets and limites message length, messages should always be
 	   complete. Saves us quite a lot of code and buffering. */
-	size = recv( fd, buf, 512, MSG_PEEK );
+	size = recv( fd, buf, sizeof( buf ) - 1, MSG_PEEK );
 	if( size == 0 || ( size < 0 && !sockerr_again() ) )
 		return NULL;
@@ -229,19 +248,13 @@
 		buf[size] = 0;
 	
-	eol = strstr( buf, "\r\n" );
-	if( eol == NULL )
+	if( ( eol = strstr( buf, "\r\n" ) ) == NULL )
 		return NULL;
 	else
 		size = eol - buf + 2;
-	
-	g_free( buf );
-	buf = g_new0( char, size + 1 );
 	
 	if( recv( fd, buf, size, 0 ) != size )
 		return NULL;
 	else
-		buf[size-2] = 0;
-	
-	return buf;
+		return g_strndup( buf, size - 2 );
 }
 
@@ -254,5 +267,9 @@
 		cmd = irc_parse_line( buf );
 		if( cmd )
+		{
 			ipc_command_exec( data, cmd, ipc_master_commands );
+			g_free( cmd );
+		}
+		g_free( buf );
 	}
 	else
@@ -272,5 +289,9 @@
 		cmd = irc_parse_line( buf );
 		if( cmd )
+		{
 			ipc_command_exec( data, cmd, ipc_child_commands );
+			g_free( cmd );
+		}
+		g_free( buf );
 	}
 	else
@@ -439,4 +460,5 @@
 }
 
+#ifndef _WIN32
 char *ipc_master_save_state()
 {
@@ -479,9 +501,4 @@
 }
 
-void ipc_master_set_statefile( char *fn )
-{
-	statefile = g_strdup( fn );
-}
-
 
 static gboolean new_ipc_client( gpointer data, gint serversock, b_input_condition cond )
@@ -504,5 +521,4 @@
 }
 
-#ifndef _WIN32
 int ipc_master_listen_socket()
 {
@@ -541,8 +557,12 @@
 }
 #else
+int ipc_master_listen_socket()
+{
 	/* FIXME: Open named pipe \\.\BITLBEE */
+	return 0;
+}
 #endif
 
-int ipc_master_load_state()
+int ipc_master_load_state( char *statefile )
 {
 	struct bitlbee_child *child;
@@ -552,4 +572,5 @@
 	if( statefile == NULL )
 		return 0;
+	
 	fp = fopen( statefile, "r" );
 	unlink( statefile );	/* Why do it later? :-) */
Index: ipc.h
===================================================================
--- ipc.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ ipc.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -58,6 +58,5 @@
 
 char *ipc_master_save_state();
-void ipc_master_set_statefile( char *fn );
-int ipc_master_load_state();
+int ipc_master_load_state( char *statefile );
 int ipc_master_listen_socket();
 
Index: irc.c
===================================================================
--- irc.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ irc.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -26,4 +26,5 @@
 #define BITLBEE_CORE
 #include "bitlbee.h"
+#include "sock.h"
 #include "crypting.h"
 #include "ipc.h"
@@ -315,5 +316,9 @@
 	g_free( irc );
 	
-	if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
+	if( global.conf->runmode == RUNMODE_INETD ||
+	    global.conf->runmode == RUNMODE_FORKDAEMON ||
+	    ( global.conf->runmode == RUNMODE_DAEMON &&
+	      global.listen_socket == -1 &&
+	      irc_connection_list == NULL ) )
 		b_main_quit();
 }
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ irc_commands.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -626,4 +626,5 @@
 	{ "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
 	{ "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+	{ "deaf",        0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
 	{ "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
 	{ "wall",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
Index: lib/misc.c
===================================================================
--- lib/misc.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ lib/misc.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -60,29 +60,4 @@
 	strcpy(text, text2);
 	g_free(text2);
-}
-
-char *normalize(const char *s)
-{
-	static char buf[BUF_LEN];
-	char *t, *u;
-	int x = 0;
-
-	g_return_val_if_fail((s != NULL), NULL);
-
-	u = t = g_strdup(s);
-
-	strcpy(t, s);
-	g_strdown(t);
-
-	while (*t && (x < BUF_LEN - 1)) {
-		if (*t != ' ') {
-			buf[x] = *t;
-			x++;
-		}
-		t++;
-	}
-	buf[x] = '\0';
-	g_free(u);
-	return buf;
 }
 
@@ -398,4 +373,5 @@
 void random_bytes( unsigned char *buf, int count )
 {
+#ifndef _WIN32
 	static int use_dev = -1;
 	
@@ -447,4 +423,5 @@
 	
 	if( !use_dev )
+#endif
 	{
 		int i;
@@ -607,11 +584,7 @@
 	md5_byte_t pass_md5[16];
 	md5_state_t md5_state;
-	int ret, i;
-	
-	if( base64_decode( hash, &pass_dec ) != 21 )
-	{
-		ret = -1;
-	}
-	else
+	int ret = -1, i;
+	
+	if( base64_decode( hash, &pass_dec ) == 21 )
 	{
 		md5_init( &md5_state );
Index: lib/misc.h
===================================================================
--- lib/misc.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ lib/misc.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -41,5 +41,4 @@
 G_MODULE_EXPORT char *add_cr( char *text );
 G_MODULE_EXPORT char *strip_newlines(char *source);
-G_MODULE_EXPORT char *normalize( const char *s );
 
 G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec );
Index: lib/ssl_bogus.c
===================================================================
--- lib/ssl_bogus.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ lib/ssl_bogus.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -61,2 +61,7 @@
 	return GAIM_INPUT_READ;
 }
+
+int ssl_pending( void *conn )
+{
+	return 0;
+}
Index: lib/ssl_sspi.c
===================================================================
--- lib/ssl_sspi.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
+++ lib/ssl_sspi.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -0,0 +1,278 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* SSL module - SSPI backend */
+
+/* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "ssl_client.h"
+#include <windows.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <sspi.h>
+#include <schannel.h>
+#include "sock.h"
+
+static gboolean initialized = FALSE;
+int ssl_errno;
+
+struct scd
+{
+	int fd;
+	ssl_input_function func;
+	gpointer data;
+	gboolean established;
+  	CredHandle cred;		/* SSL credentials */
+	CtxtHandle context;		/* SSL context */
+	SecPkgContext_StreamSizes sizes;
+
+	char *host;
+
+	char *pending_raw_data;
+	gsize pending_raw_data_len;
+	char *pending_data;
+	gsize pending_data_len;
+};
+
+static void ssl_connected(gpointer, gint, GaimInputCondition);
+
+void sspi_global_init(void)
+{
+	/* FIXME */
+}
+
+void sspi_global_deinit(void)
+{
+	/* FIXME */
+}
+
+void *ssl_connect(char *host, int port, ssl_input_function func, gpointer data)
+{
+	struct scd *conn = g_new0(struct scd, 1);
+		
+	conn->fd = proxy_connect(host, port, ssl_connected, conn);
+	sock_make_nonblocking(conn->fd);
+	conn->func = func;
+	conn->data = data;
+	conn->host = g_strdup(host);
+	
+	if (conn->fd < 0)
+	{
+		g_free(conn);
+		return NULL;
+	}
+	
+	if (!initialized)
+	{
+		sspi_global_init();
+		initialized = TRUE;
+		atexit(sspi_global_deinit);
+	}
+
+	return conn;
+}
+
+static void ssl_connected(gpointer _conn, gint fd, GaimInputCondition cond)
+{
+	struct scd *conn = _conn;
+	SCHANNEL_CRED ssl_cred;
+	TimeStamp timestamp;
+	SecBuffer ibuf[2],obuf[1];
+	SecBufferDesc ibufs,obufs;
+	ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT |
+    	ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY |
+      	ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR |
+		ISC_REQ_MANUAL_CRED_VALIDATION;
+	ULONG a;
+	gsize size = 0;
+	gchar *data = NULL;
+
+	memset(&ssl_cred, 0, sizeof(SCHANNEL_CRED));
+	ssl_cred.dwVersion = SCHANNEL_CRED_VERSION;
+	ssl_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
+
+	SECURITY_STATUS st = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL, &ssl_cred, NULL, NULL, &conn->cred, &timestamp);
+
+	if (st != SEC_E_OK) {
+		conn->func(conn->data, NULL, cond);
+		return;
+	}
+	
+	do {
+		/* initialize buffers */
+	    ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = data;
+	    ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NULL;
+	    obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NULL;
+    	ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN;
+	    ibuf[1].BufferType = SECBUFFER_EMPTY;
+
+		/* initialize buffer descriptors */
+	    ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION;
+	    ibufs.cBuffers = 2; obufs.cBuffers = 1;
+	    ibufs.pBuffers = ibuf; obufs.pBuffers = obuf;
+
+		st = InitializeSecurityContext(&conn->cred, size?&conn->context:NULL, conn->host, req, 0, SECURITY_NETWORK_DREP, size?&ibufs:NULL, 0, &conn->context, &obufs, &a, &timestamp);  
+    	if (obuf[0].pvBuffer && obuf[0].cbBuffer) {
+			/* FIXME: Check return value */
+			send(conn->fd, obuf[0].pvBuffer, obuf[0].cbBuffer, 0);
+		}
+
+		switch (st) {
+		case SEC_I_INCOMPLETE_CREDENTIALS:
+			break;
+		case SEC_I_CONTINUE_NEEDED:
+			break;
+		case SEC_E_INCOMPLETE_MESSAGE:
+			break;
+		case SEC_E_OK:
+			break;
+		}
+	
+		QueryContextAttributes(&conn->context, SECPKG_ATTR_STREAM_SIZES, &conn->sizes);
+	} while (1);
+
+	conn->func(conn->data, conn, cond);
+}
+
+int ssl_read(void *conn, char *retdata, int len)
+{
+	struct scd *scd = conn;
+	SecBufferDesc msg;
+	SecBuffer buf[4];
+	int ret = -1, i;
+	char *data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer);
+
+	/* FIXME: Try to read some data */
+
+  	msg.ulVersion = SECBUFFER_VERSION;
+	msg.cBuffers = 4;
+	msg.pBuffers = buf;
+	
+	buf[0].BufferType = SECBUFFER_DATA;
+	buf[0].cbBuffer = len;
+	buf[0].pvBuffer = data;
+
+	buf[1].BufferType = SECBUFFER_EMPTY;
+	buf[2].BufferType = SECBUFFER_EMPTY;
+	buf[3].BufferType = SECBUFFER_EMPTY;
+
+	SECURITY_STATUS st = DecryptMessage(&scd->context, &msg, 0, NULL);
+
+	if (st != SEC_E_OK) {
+		/* FIXME */
+		return -1;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (buf[i].BufferType == SECBUFFER_DATA) {
+			memcpy(retdata, buf[i].pvBuffer, len);
+			ret = len;
+		}	
+	}
+
+	g_free(data);
+	return -1;
+}
+
+int ssl_write(void *conn, const char *userdata, int len)
+{
+	struct scd *scd = conn;
+	SecBuffer buf[4];
+	SecBufferDesc msg;
+	char *data;
+	int ret;
+
+	msg.ulVersion = SECBUFFER_VERSION;
+	msg.cBuffers = 4;
+	msg.pBuffers = buf;
+
+	data = g_malloc(scd->sizes.cbHeader + scd->sizes.cbMaximumMessage + scd->sizes.cbTrailer);
+	memcpy(data + scd->sizes.cbHeader, userdata, len);
+
+	buf[0].BufferType = SECBUFFER_STREAM_HEADER;
+	buf[0].cbBuffer = scd->sizes.cbHeader;
+	buf[0].pvBuffer = data;
+
+	buf[1].BufferType = SECBUFFER_DATA;
+	buf[1].cbBuffer = len;
+	buf[1].pvBuffer = data + scd->sizes.cbHeader;
+
+	buf[2].BufferType = SECBUFFER_STREAM_TRAILER;
+	buf[2].cbBuffer = scd->sizes.cbTrailer;
+	buf[2].pvBuffer = data + scd->sizes.cbHeader + len;
+	buf[3].BufferType = SECBUFFER_EMPTY;
+
+	SECURITY_STATUS st = EncryptMessage(&scd->context, 0, &msg, 0);
+
+	ret = send(scd->fd, data, 
+				buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer, 0);
+
+	g_free(data);
+
+	return ret;
+}
+
+void ssl_disconnect(void *conn)
+{
+	struct scd *scd = conn;
+
+	SecBufferDesc msg;
+	SecBuffer buf;
+	DWORD dw;
+
+	dw = SCHANNEL_SHUTDOWN;
+	buf.cbBuffer = sizeof(dw);
+	buf.BufferType = SECBUFFER_TOKEN;
+	buf.pvBuffer = &dw;
+	
+	msg.ulVersion = SECBUFFER_VERSION;
+	msg.cBuffers = 1;
+	msg.pBuffers = &buf;
+
+	SECURITY_STATUS st = ApplyControlToken(&scd->context, &msg);
+
+	if (st != SEC_E_OK) {
+		/* FIXME */
+	}
+	
+	/* FIXME: call InitializeSecurityContext(Schannel), passing 
+	 * in empty buffers*/
+
+	DeleteSecurityContext(&scd->context);
+
+	FreeCredentialsHandle(&scd->cred);
+
+	closesocket(scd->fd);
+	g_free(scd->host);
+	g_free(scd);
+}
+
+int ssl_getfd(void *conn)
+{
+	return ((struct scd*)conn)->fd;
+}
+
+GaimInputCondition ssl_getdirection( void *conn )
+{
+	return GAIM_INPUT_WRITE; /* FIXME: or GAIM_INPUT_READ */
+}
Index: nick.c
===================================================================
--- nick.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ nick.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -47,4 +47,5 @@
 	
 	store_handle = clean_handle( handle );
+	store_nick[MAX_NICK_LENGTH] = 0;
 	strncpy( store_nick, nick, MAX_NICK_LENGTH );
 	nick_strip( store_nick );
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/jabber.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -33,13 +33,31 @@
 #include "jabber.h"
 #include "md5.h"
-#include "base64.h"
 
 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;
 	
@@ -74,4 +92,5 @@
 	struct ns_srv_reply *srv = NULL;
 	char *connect_to, *s;
+	int i;
 	
 	/* For now this is needed in the _connected() handlers if using
@@ -179,9 +198,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;
@@ -221,22 +242,18 @@
 }
 
+/* This generates an unfinished md5_state_t variable. Every time we generate
+   an ID, we finish the state by adding a sequence number and take the hash. */
 static void jabber_generate_id_hash( struct jabber_data *jd )
 {
-	md5_state_t id_hash;
-	md5_byte_t binbuf[16];
+	md5_byte_t binbuf[4];
 	char *s;
 	
-	md5_init( &id_hash );
-	md5_append( &id_hash, (unsigned char *) jd->username, strlen( jd->username ) );
-	md5_append( &id_hash, (unsigned char *) jd->server, strlen( jd->server ) );
+	md5_init( &jd->cached_id_prefix );
+	md5_append( &jd->cached_id_prefix, (unsigned char *) jd->username, strlen( jd->username ) );
+	md5_append( &jd->cached_id_prefix, (unsigned char *) jd->server, strlen( jd->server ) );
 	s = set_getstr( &jd->ic->acc->set, "resource" );
-	md5_append( &id_hash, (unsigned char *) s, strlen( s ) );
-	random_bytes( binbuf, 16 );
-	md5_append( &id_hash, binbuf, 16 );
-	md5_finish( &id_hash, binbuf );
-	
-	s = base64_encode( binbuf, 9 );
-	jd->cached_id_prefix = g_strdup_printf( "%s%s", JABBER_CACHED_ID, s );
-	g_free( s );
+	md5_append( &jd->cached_id_prefix, (unsigned char *) s, strlen( s ) );
+	random_bytes( binbuf, 4 );
+	md5_append( &jd->cached_id_prefix, binbuf, 4 );
 }
 
@@ -281,5 +298,4 @@
 	xt_free( jd->xt );
 	
-	g_free( jd->cached_id_prefix );
 	g_free( jd->away_message );
 	g_free( jd->username );
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/jabber.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -94,5 +94,5 @@
 	char *away_message;
 	
-	char *cached_id_prefix;
+	md5_state_t cached_id_prefix;
 	GHashTable *node_cache;
 	GHashTable *buddies;
@@ -177,8 +177,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 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/jabber_util.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -23,4 +23,6 @@
 
 #include "jabber.h"
+#include "md5.h"
+#include "base64.h"
 
 static unsigned int next_id = 1;
@@ -138,9 +140,19 @@
 	struct jabber_data *jd = ic->proto_data;
 	struct jabber_cache_entry *entry = g_new0( struct jabber_cache_entry, 1 );
-	char *id;
-	
-	id = g_strdup_printf( "%s%05x", jd->cached_id_prefix, ( next_id++ ) & 0xfffff );
+	md5_state_t id_hash;
+	md5_byte_t id_sum[16];
+	char *id, *asc_hash;
+	
+	next_id ++;
+	
+	id_hash = jd->cached_id_prefix;
+	md5_append( &id_hash, (md5_byte_t*) &next_id, sizeof( next_id ) );
+	md5_finish( &id_hash, id_sum );
+	asc_hash = base64_encode( id_sum, 12 );
+	
+	id = g_strdup_printf( "%s%s", JABBER_CACHED_ID, asc_hash );
 	xt_add_attr( node, "id", id );
 	g_free( id );
+	g_free( asc_hash );
 	
 	entry->node = node;
@@ -188,5 +200,5 @@
 	
 	if( ( s = xt_find_attr( node, "id" ) ) == NULL ||
-	    strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 )
+	    strncmp( s, JABBER_CACHED_ID, strlen( JABBER_CACHED_ID ) ) != 0 )
 	{
 		/* Silently ignore it, without an ID (or a non-cache
@@ -200,6 +212,12 @@
 	if( entry == NULL )
 	{
+		/*
+		There's no longer an easy way to see if we generated this
+		one or someone else, and there's a ten-minute timeout anyway,
+		so meh.
+		
 		imcb_log( ic, "Warning: Received %s-%s packet with unknown/expired ID %s!",
 		              node->name, xt_find_attr( node, "type" ) ? : "(no type)", s );
+		*/
 	}
 	else if( entry->func )
@@ -294,12 +312,10 @@
 	len = strlen( orig );
 	new = g_new( char, len + 1 );
-	for( i = 0; i < len; i ++ )
-	{
-		/* don't normalize the resource */
-		if( orig[i] == '/' )
-			break;
+	
+	/* So it turns out the /resource part is case sensitive. Yeah, and
+	   it's Unicode but feck Unicode. :-P So stop once we see a slash. */
+	for( i = 0; i < len && orig[i] != '/' ; i ++ )
 		new[i] = tolower( orig[i] );
-	}
-	for( ; i < len; i ++ )
+	for( ; orig[i]; i ++ )
 		new[i] = orig[i];
 	
@@ -345,5 +361,5 @@
 		{
 			/* Check for dupes. */
-			if( g_strcasecmp( bi->resource, s + 1 ) == 0 )
+			if( strcmp( bi->resource, s + 1 ) == 0 )
 			{
 				*s = '/';
@@ -398,5 +414,5 @@
 	if( ( s = strchr( jid, '/' ) ) )
 	{
-		int none_found = 0;
+		int bare_exists = 0;
 		
 		*s = 0;
@@ -421,19 +437,17 @@
 			/* See if there's an exact match. */
 			for( ; bud; bud = bud->next )
-				if( g_strcasecmp( bud->resource, s + 1 ) == 0 )
+				if( strcmp( bud->resource, s + 1 ) == 0 )
 					break;
 		}
 		else
 		{
-			/* This hack is there to make sure that O_CREAT will
-			   work if there's already another resouce present
-			   for this JID, even if it's an unknown buddy. This
-			   is done to handle conferences properly. */
-			none_found = 1;
-			/* TODO(wilmer): Find out what I was thinking when I
-			   wrote this??? And then fix it. This makes me sad... */
-		}
-		
-		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) && ( imcb_find_buddy( ic, jid ) || !none_found ) )
+			/* This variable tells the if down here that the bare
+			   JID already exists and we should feel free to add
+			   more resources, if the caller asked for that. */
+			bare_exists = 1;
+		}
+		
+		if( bud == NULL && ( flags & GET_BUDDY_CREAT ) &&
+		    ( !bare_exists || imcb_find_buddy( ic, jid ) ) )
 		{
 			*s = '/';
@@ -460,5 +474,5 @@
 			/* We want an exact match, so in thise case there shouldn't be a /resource. */
 			return NULL;
-		else if( ( bud->resource == NULL || bud->next == NULL ) )
+		else if( bud->resource == NULL || bud->next == NULL )
 			/* No need for selection if there's only one option. */
 			return bud;
@@ -536,5 +550,7 @@
 		   matches), removing it is simple. (And the hash reference
 		   should be removed too!) */
-		if( bud->next == NULL && ( ( s == NULL || bud->resource == NULL ) || g_strcasecmp( bud->resource, s + 1 ) == 0 ) )
+		if( bud->next == NULL &&
+		    ( ( s == NULL && bud->resource == NULL ) ||
+		      ( bud->resource && s && strcmp( bud->resource, s + 1 ) == 0 ) ) )
 		{
 			g_hash_table_remove( jd->buddies, bud->bare_jid );
@@ -559,5 +575,5 @@
 		{
 			for( bi = bud, prev = NULL; bi; bi = (prev=bi)->next )
-				if( g_strcasecmp( bi->resource, s + 1 ) == 0 )
+				if( strcmp( bi->resource, s + 1 ) == 0 )
 					break;
 			
Index: protocols/jabber/message.c
===================================================================
--- protocols/jabber/message.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/jabber/message.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -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/ns.c
===================================================================
--- protocols/msn/ns.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/msn/ns.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -278,9 +278,23 @@
 		if( num_parts == 5 )
 		{
+			int i, groupcount;
+			
+			groupcount = atoi( cmd[4] );
+			if( groupcount > 0 )
+			{
+				/* valgrind says this is leaking memory, I'm guessing
+				   that this happens during server redirects. */
+				if( md->grouplist )
+				{
+					for( i = 0; i < md->groupcount; i ++ )
+						g_free( md->grouplist[i] );
+					g_free( md->grouplist );
+				}
+				
+				md->groupcount = groupcount;
+				md->grouplist = g_new0( char *, md->groupcount );
+			}
+			
 			md->buddycount = atoi( cmd[3] );
-			md->groupcount = atoi( cmd[4] );
-			if( md->groupcount > 0 )
-				md->grouplist = g_new0( char *, md->groupcount );
-			
 			if( !*cmd[3] || md->buddycount == 0 )
 				msn_logged_in( ic );
@@ -665,4 +679,7 @@
 					imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders );
 				}
+				
+				g_free( inbox );
+				g_free( folders );
 			}
 			else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 )
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/nogaim.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -45,9 +45,4 @@
 #include "md5.h"
 #include "ft.h"
-
-#define BUF_LEN MSG_LEN
-#define BUF_LONG ( BUF_LEN * 2 )
-#define MSG_LEN 2048
-#define BUF_LEN MSG_LEN
 
 #define BUDDY_ALIAS_MAXLEN 388   /* because MSN names can be 387 characters */
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/oscar/oscar.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -60,4 +60,7 @@
 
 #define OSCAR_GROUP "Friends"
+
+#define BUF_LEN 2048
+#define BUF_LONG ( BUF_LEN * 2 )
 
 /* Don't know if support for UTF8 is really working. For now it's UTF16 here.
@@ -240,4 +243,30 @@
 };
 static int msgerrreasonlen = 25;
+
+/* Hurray, this function is NOT thread-safe \o/ */
+static char *normalize(const char *s)
+{
+	static char buf[BUF_LEN];
+	char *t, *u;
+	int x = 0;
+
+	g_return_val_if_fail((s != NULL), NULL);
+
+	u = t = g_strdup(s);
+
+	strcpy(t, s);
+	g_strdown(t);
+
+	while (*t && (x < BUF_LEN - 1)) {
+		if (*t != ' ' && *t != '!') {
+			buf[x] = *t;
+			x++;
+		}
+		t++;
+	}
+	buf[x] = '\0';
+	g_free(u);
+	return buf;
+}
 
 static gboolean oscar_callback(gpointer data, gint source,
@@ -1002,11 +1031,11 @@
 	}
 
-	tmp = g_strdup(normalize(ic->acc->user));
-	if (!strcmp(tmp, normalize(info->sn)))
+	if (!aim_sncmp(ic->acc->user, info->sn))
 		g_snprintf(ic->displayname, sizeof(ic->displayname), "%s", info->sn);
-	g_free(tmp);
-
-	imcb_buddy_status(ic, info->sn, flags, state_string, NULL);
-	/* imcb_buddy_times(ic, info->sn, signon, time_idle); */
+
+	tmp = normalize(info->sn);
+	imcb_buddy_status(ic, tmp, flags, state_string, NULL);
+	/* imcb_buddy_times(ic, tmp, signon, time_idle); */
+
 
 	return 1;
@@ -1022,5 +1051,5 @@
 	va_end(ap);
 
-	imcb_buddy_status(ic, info->sn, 0, NULL, NULL );
+	imcb_buddy_status(ic, normalize(info->sn), 0, NULL, NULL );
 
 	return 1;
@@ -1078,5 +1107,5 @@
 	
 	strip_linefeed(tmp);
-	imcb_buddy_msg(ic, userinfo->sn, tmp, flags, 0);
+	imcb_buddy_msg(ic, normalize(userinfo->sn), tmp, flags, 0);
 	g_free(tmp);
 	
@@ -1177,5 +1206,5 @@
 			message = g_strdup(args->msg);
 			strip_linefeed(message);
-			imcb_buddy_msg(ic, uin, message, 0, 0);
+			imcb_buddy_msg(ic, normalize(uin), message, 0, 0);
 			g_free(uin);
 			g_free(message);
@@ -1196,5 +1225,5 @@
 
 			strip_linefeed(message);
-			imcb_buddy_msg(ic, uin, message, 0, 0);
+			imcb_buddy_msg(ic, normalize(uin), message, 0, 0);
 			g_free(uin);
 			g_free(m);
@@ -1471,5 +1500,5 @@
 
 	for (i = 0; i < count; i++)
-		imcb_chat_add_buddy(c->cnv, info[i].sn);
+		imcb_chat_add_buddy(c->cnv, normalize(info[i].sn));
 
 	return 1;
@@ -1494,5 +1523,5 @@
 
 	for (i = 0; i < count; i++)
-		imcb_chat_remove_buddy(c->cnv, info[i].sn, NULL);
+		imcb_chat_remove_buddy(c->cnv, normalize(info[i].sn), NULL);
 
 	return 1;
@@ -1545,5 +1574,5 @@
 	tmp = g_malloc(BUF_LONG);
 	g_snprintf(tmp, BUF_LONG, "%s", msg);
-	imcb_chat_msg(ccon->cnv, info->sn, tmp, 0, 0);
+	imcb_chat_msg(ccon->cnv, normalize(info->sn), tmp, 0, 0);
 	g_free(tmp);
 
@@ -1758,5 +1787,5 @@
 			g_snprintf(sender, sizeof(sender), "%u", msg->sender);
 			strip_linefeed(dialog_msg);
-			imcb_buddy_msg(ic, sender, dialog_msg, 0, t);
+			imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t);
 			g_free(dialog_msg);
 		} break;
@@ -1779,5 +1808,5 @@
 
 			strip_linefeed(dialog_msg);
-			imcb_buddy_msg(ic, sender, dialog_msg, 0, t);
+			imcb_buddy_msg(ic, normalize(sender), dialog_msg, 0, t);
 			g_free(dialog_msg);
 			g_free(m);
@@ -2017,11 +2046,14 @@
 	struct aim_ssi_item *curitem;
 	int tmp;
+	char *nrm;
 
 	/* Add from server list to local list */
 	tmp = 0;
 	for (curitem=sess->ssi.items; curitem; curitem=curitem->next) {
+		nrm = curitem->name ? normalize(curitem->name) : NULL;
+		
 		switch (curitem->type) {
 			case 0x0000: /* Buddy */
-				if ((curitem->name) && (!imcb_find_buddy(ic, curitem->name))) {
+				if ((curitem->name) && (!imcb_find_buddy(ic, nrm))) {
 					char *realname = NULL;
 
@@ -2029,9 +2061,9 @@
 						    realname = aim_gettlv_str(curitem->data, 0x0131, 1);
 						
-					imcb_add_buddy(ic, curitem->name, NULL);
+					imcb_add_buddy(ic, nrm, NULL);
 					
 					if (realname) {
-						imcb_buddy_nick_hint(ic, curitem->name, realname);
-						imcb_rename_buddy(ic, curitem->name, realname);
+						imcb_buddy_nick_hint(ic, nrm, realname);
+						imcb_rename_buddy(ic, nrm, realname);
 						g_free(realname);
 					}
@@ -2045,5 +2077,5 @@
 					if (!list) {
 						char *name;
-						name = g_strdup(normalize(curitem->name));
+						name = g_strdup(nrm);
 						ic->permit = g_slist_append(ic->permit, name);
 						tmp++;
@@ -2058,5 +2090,5 @@
 					if (!list) {
 						char *name;
-						name = g_strdup(normalize(curitem->name));
+						name = g_strdup(nrm);
 						ic->deny = g_slist_append(ic->deny, name);
 						tmp++;
@@ -2120,5 +2152,5 @@
 			if( st == 0x00 )
 			{
-				imcb_add_buddy( sess->aux_data, list, NULL );
+				imcb_add_buddy( sess->aux_data, normalize(list), NULL );
 			}
 			else if( st == 0x0E )
@@ -2450,13 +2482,13 @@
 	if(type2 == 0x0002) {
 		/* User is typing */
-		imcb_buddy_typing(ic, sn, OPT_TYPING);
+		imcb_buddy_typing(ic, normalize(sn), OPT_TYPING);
 	} 
 	else if (type2 == 0x0001) {
 		/* User has typed something, but is not actively typing (stale) */
-		imcb_buddy_typing(ic, sn, OPT_THINKING);
+		imcb_buddy_typing(ic, normalize(sn), OPT_THINKING);
 	}
 	else {
 		/* User has stopped typing */
-		imcb_buddy_typing(ic, sn, 0);
+		imcb_buddy_typing(ic, normalize(sn), 0);
 	}
 	
Index: protocols/yahoo/libyahoo2.c
===================================================================
--- protocols/yahoo/libyahoo2.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/yahoo/libyahoo2.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -69,6 +69,4 @@
 #ifdef __MINGW32__
 # include <winsock2.h>
-# define write(a,b,c) send(a,b,c,0)
-# define read(a,b,c)  recv(a,b,c,0)
 #endif
 
@@ -381,5 +379,4 @@
 
 /* call repeatedly to get the next one */
-/*
 static struct yahoo_input_data * find_input_by_id(int id)
 {
@@ -392,5 +389,4 @@
 	return NULL;
 }
-*/
 
 static struct yahoo_input_data * find_input_by_id_and_webcam_user(int id, const char * who)
@@ -797,4 +793,5 @@
 {
 	struct yahoo_data *yd = find_conn_by_id(id);
+	
 	if(!yd)
 		return;
@@ -3166,5 +3163,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 +3839,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 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/yahoo/yahoo.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -163,8 +163,5 @@
 	g_slist_free( yd->buddygroups );
 	
-	if( yd->logged_in )
-		yahoo_logoff( yd->y2_id );
-	else
-		yahoo_close( yd->y2_id );
+	yahoo_logoff( yd->y2_id );
 	
 	g_free( yd );
@@ -454,8 +451,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 );
 	
@@ -672,7 +665,4 @@
 	
 	imcb_error( ic, "%s", err );
-	
-	if( fatal )
-		imc_logout( ic, TRUE );
 }
 
Index: protocols/yahoo/yahoo_httplib.c
===================================================================
--- protocols/yahoo/yahoo_httplib.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ protocols/yahoo/yahoo_httplib.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -51,6 +51,4 @@
 #ifdef __MINGW32__
 # include <winsock2.h>
-# define write(a,b,c) send(a,b,c,0)
-# define read(a,b,c)  recv(a,b,c,0)
 # define snprintf _snprintf
 #endif
Index: sock.h
===================================================================
--- sock.h	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ sock.h	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -16,15 +16,9 @@
 #else
 # include <winsock2.h>
-# ifndef _MSC_VER
-#  include <ws2tcpip.h>
-# endif
+# include <ws2tcpip.h>
 # if !defined(BITLBEE_CORE) && defined(_MSC_VER)
 #   pragma comment(lib,"bitlbee.lib")
 # endif
 # include <io.h>
-# define read(a,b,c) recv(a,b,c,0)
-# define write(a,b,c) send(a,b,c,0)
-# define umask _umask
-# define mode_t int
 # define sock_make_nonblocking(fd) { int non_block = 1; ioctlsocket(fd, FIONBIO, &non_block); }
 # define sock_make_blocking(fd) { int non_block = 0; ioctlsocket(fd, FIONBIO, &non_block); }
Index: storage_text.c
===================================================================
--- storage_text.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ storage_text.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -27,4 +27,12 @@
 #include "bitlbee.h"
 #include "crypting.h"
+#ifdef _WIN32
+# define umask _umask
+# define mode_t int
+#endif
+
+#ifndef F_OK
+#define F_OK 0
+#endif
 
 static void text_init (void)
Index: storage_xml.c
===================================================================
--- storage_xml.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ storage_xml.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -29,4 +29,10 @@
 #include "arc.h"
 #include "md5.h"
+#include <glib/gstdio.h>
+
+#if !GLIB_CHECK_VERSION(2,8,0)
+/* GLib < 2.8.0 doesn't have g_access, so just use the system access(). */
+#define g_access access
+#endif
 
 typedef enum
@@ -243,7 +249,8 @@
 static void xml_init( void )
 {
-	if( access( global.conf->configdir, F_OK ) != 0 )
+	if( g_access( global.conf->configdir, F_OK ) != 0 )
 		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_access( global.conf->configdir, F_OK ) != 0 || 
+	         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 +379,5 @@
 	g_free( path2 );
 	
-	if( !overwrite && access( path, F_OK ) != -1 )
+	if( !overwrite && g_access( path, F_OK ) == 0 )
 		return STORAGE_ALREADY_EXISTS;
 	
@@ -480,5 +487,5 @@
 static storage_status_t xml_remove( const char *nick, const char *password )
 {
-	char s[512];
+	char s[512], *lc;
 	storage_status_t status;
 
@@ -487,5 +494,9 @@
 		return status;
 
-	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".xml" );
+	lc = g_strdup( nick );
+	nick_lc( lc );
+	g_snprintf( s, 511, "%s%s%s", global.conf->configdir, lc, ".xml" );
+	g_free( lc );
+	
 	if( unlink( s ) == -1 )
 		return STORAGE_OTHER_ERROR;
Index: tests/Makefile
===================================================================
--- tests/Makefile	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ tests/Makefile	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -13,5 +13,5 @@
 main_objs = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o
 
-test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o check_jabber_sasl.o
+test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o check_jabber_sasl.o check_jabber_util.o
 
 check: $(test_objs) $(addprefix ../, $(main_objs)) ../protocols/protocols.o ../lib/lib.o
Index: tests/check.c
===================================================================
--- tests/check.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ tests/check.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -69,4 +69,7 @@
 Suite *jabber_sasl_suite(void);
 
+/* From check_jabber_sasl.c */
+Suite *jabber_util_suite(void);
+
 int main (int argc, char **argv)
 {
@@ -115,4 +118,5 @@
 	srunner_add_suite(sr, set_suite());
 	srunner_add_suite(sr, jabber_sasl_suite());
+	srunner_add_suite(sr, jabber_util_suite());
 	if (no_fork)
 		srunner_set_fork_status(sr, CK_NOFORK);
Index: tests/check_jabber_sasl.c
===================================================================
--- tests/check_jabber_sasl.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ tests/check_jabber_sasl.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -5,5 +5,4 @@
 #include <string.h>
 #include <stdio.h>
-#include "arc.h"
 
 char *sasl_get_part( char *data, char *field );
Index: tests/check_jabber_util.c
===================================================================
--- tests/check_jabber_util.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
+++ tests/check_jabber_util.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -0,0 +1,91 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <check.h>
+#include <string.h>
+#include <stdio.h>
+#include "jabber/jabber.h"
+
+static struct im_connection *ic;
+
+static void check_buddy_add(int l)
+{
+	struct jabber_buddy *budw1, *budw2, *budw3, *budn, *bud;
+	
+	budw1 = jabber_buddy_add( ic, "wilmer@gaast.net/BitlBee" );
+	budw1->last_act = time( NULL ) - 100;
+	budw2 = jabber_buddy_add( ic, "WILMER@gaast.net/Telepathy" );
+	budw2->priority = 2;
+	budw2->last_act = time( NULL );
+	budw3 = jabber_buddy_add( ic, "wilmer@GAAST.NET/bitlbee" );
+	budw3->last_act = time( NULL ) - 200;
+	budw3->priority = 4;
+	/* TODO(wilmer): Shouldn't this just return budw3? */
+	fail_if( jabber_buddy_add( ic, "wilmer@gaast.net/Telepathy" ) != NULL );
+	
+	budn = jabber_buddy_add( ic, "nekkid@lamejab.net" );
+	/* Shouldn't be allowed if there's already a bare JID. */
+	fail_if( jabber_buddy_add( ic, "nekkid@lamejab.net/Illegal" ) );
+	
+	/* Case sensitivity: Case only matters after the / */
+	fail_if( jabber_buddy_by_jid( ic, "wilmer@gaast.net/BitlBee", 0 ) ==
+	         jabber_buddy_by_jid( ic, "wilmer@gaast.net/bitlbee", 0 ) );
+	fail_if( jabber_buddy_by_jid( ic, "wilmer@gaast.net/telepathy", 0 ) );
+	
+	fail_unless( jabber_buddy_by_jid( ic, "wilmer@gaast.net/BitlBee", 0 ) == budw1 );
+	fail_unless( jabber_buddy_by_jid( ic, "WILMER@GAAST.NET/BitlBee", GET_BUDDY_EXACT ) == budw1 );
+	fail_unless( jabber_buddy_by_jid( ic, "wilmer@GAAST.NET/BitlBee", GET_BUDDY_CREAT ) == budw1 );
+
+	fail_if( jabber_buddy_by_jid( ic, "wilmer@gaast.net", GET_BUDDY_EXACT ) );
+	fail_unless( jabber_buddy_by_jid( ic, "WILMER@gaast.net", 0 ) == budw3 );
+
+	/* Check O_FIRST and see if it's indeed the first item from the list. */
+	fail_unless( ( bud = jabber_buddy_by_jid( ic, "wilmer@gaast.net", GET_BUDDY_FIRST ) ) == budw1 );
+	fail_unless( bud->next == budw2 && bud->next->next == budw3 && bud->next->next->next == NULL );
+	
+	/* Change the resource_select setting, now we should get a different resource. */
+	set_setstr( &ic->acc->set, "resource_select", "activity" );
+	fail_unless( jabber_buddy_by_jid( ic, "wilmer@GAAST.NET", 0 ) == budw2 );
+	
+	/* Some testing of bare JID handling (which is horrible). */
+	fail_if( jabber_buddy_by_jid( ic, "nekkid@lamejab.net/Illegal", 0 ) );
+	fail_if( jabber_buddy_by_jid( ic, "NEKKID@LAMEJAB.NET/Illegal", GET_BUDDY_CREAT ) );
+	fail_unless( jabber_buddy_by_jid( ic, "nekkid@lamejab.net", 0 ) == budn );
+	fail_unless( jabber_buddy_by_jid( ic, "NEKKID@lamejab.net", GET_BUDDY_EXACT ) == budn );
+	fail_unless( jabber_buddy_by_jid( ic, "nekkid@LAMEJAB.NET", GET_BUDDY_CREAT ) == budn );
+	
+	/* More case sensitivity testing, and see if remove works properly. */
+	fail_if( jabber_buddy_remove( ic, "wilmer@gaast.net/telepathy" ) );
+	fail_if( jabber_buddy_by_jid( ic, "wilmer@GAAST.NET/telepathy", GET_BUDDY_CREAT ) == budw2 );
+	fail_unless( jabber_buddy_remove( ic, "wilmer@gaast.net/Telepathy" ) );
+	fail_unless( jabber_buddy_remove( ic, "wilmer@gaast.net/telepathy" ) );
+	fail_unless( jabber_buddy_by_jid( ic, "wilmer@gaast.net", 0 ) == budw1 );
+	
+	fail_if( jabber_buddy_remove( ic, "wilmer@gaast.net" ) );
+	fail_unless( jabber_buddy_by_jid( ic, "wilmer@gaast.net", 0 ) == budw1 );
+	
+	/* Check if remove_bare() indeed gets rid of all. */
+	fail_unless( jabber_buddy_remove_bare( ic, "wilmer@gaast.net" ) );
+	fail_if( jabber_buddy_by_jid( ic, "wilmer@gaast.net", 0 ) );
+
+	fail_if( jabber_buddy_remove( ic, "nekkid@lamejab.net/Illegal" ) );
+	fail_unless( jabber_buddy_remove( ic, "nekkid@lamejab.net" ) );
+	fail_if( jabber_buddy_by_jid( ic, "nekkid@lamejab.net", 0 ) );
+}
+
+Suite *jabber_util_suite (void)
+{
+	Suite *s = suite_create("jabber/util");
+	TCase *tc_core = tcase_create("Buddy");
+	struct jabber_data *jd;
+	
+	ic = g_new0( struct im_connection, 1 );
+	ic->acc = g_new0( account_t, 1 );
+	ic->proto_data = jd = g_new0( struct jabber_data, 1 );
+	jd->buddies = g_hash_table_new( g_str_hash, g_str_equal );
+	set_add( &ic->acc->set, "resource_select", "priority", NULL, ic->acc );
+	
+	suite_add_tcase (s, tc_core);
+	tcase_add_test (tc_core, check_buddy_add);
+	return s;
+}
Index: unix.c
===================================================================
--- unix.c	(revision 4ac647dbcef152bebde7209f7c9cbbf8a5e0fc37)
+++ unix.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -40,5 +40,5 @@
 static void sighandler( int signal );
 
-int main( int argc, char *argv[], char **envp )
+int main( int argc, char *argv[] )
 {
 	int i = 0;
@@ -60,4 +60,7 @@
 	if( global.conf->runmode == RUNMODE_INETD )
 	{
+		log_link( LOGLVL_ERROR, LOGOUTPUT_IRC );
+		log_link( LOGLVL_WARNING, LOGOUTPUT_IRC );
+	
 		i = bitlbee_inetd_init();
 		log_message( LOGLVL_INFO, "Bitlbee %s starting in inetd mode.", BITLBEE_VERSION );
@@ -66,4 +69,7 @@
 	else if( global.conf->runmode == RUNMODE_DAEMON )
 	{
+		log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );
+		log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG );
+
 		i = bitlbee_daemon_init();
 		log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION );
@@ -135,28 +141,17 @@
 	{
 		char *fn = ipc_master_save_state();
-		char **args;
-		int n, i;
 		
 		chdir( old_cwd );
 		
-		n = 0;
-		args = g_new0( char *, argc + 3 );
-		args[n++] = argv[0];
-		if( fn )
-		{
-			args[n++] = "-R";
-			args[n++] = fn;
-		}
-		for( i = 1; argv[i] && i < argc; i ++ )
-		{
-			if( strcmp( argv[i], "-R" ) == 0 )
-				i += 2;
-			
-			args[n++] = argv[i];
-		}
+		setenv( "_BITLBEE_RESTART_STATE", fn, 1 );
+		g_free( fn );
 		
 		close( global.listen_socket );
 		
-		execve( args[0], args, envp );
+		if( execv( argv[0], argv ) == -1 )
+			/* Apparently the execve() failed, so let's just
+			   jump back into our own/current main(). */
+			/* Need more cleanup code to make this work. */
+			return 1; /* main( argc, argv ); */
 	}
 	
@@ -219,2 +214,4 @@
 	return( (double) time->tv_sec + (double) time->tv_usec / 1000000 );
 }
+
+
Index: win32.c
===================================================================
--- win32.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
+++ win32.c	(revision 8661caad555f4306cf36ee37979a7637b05d5cd4)
@@ -0,0 +1,332 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway					 *
+  *																	*
+  * Copyright 2002-2004 Wilmer van der Gaast and others				*
+  \********************************************************************/
+
+/* Main file (Windows specific part)								   */
+
+/*
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License with
+  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+  Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#define BITLBEE_CORE
+#include "bitlbee.h"
+#include "commands.h"
+#include "crypting.h"
+#include "protocols/nogaim.h"
+#include "help.h"
+#include <signal.h>
+#include <windows.h>
+
+global_t global;	/* Against global namespace pollution */
+
+static void WINAPI service_ctrl (DWORD dwControl)
+{
+	switch (dwControl)
+	{
+		case SERVICE_CONTROL_STOP:
+			/* FIXME */
+			break;
+
+		case SERVICE_CONTROL_INTERROGATE:
+			break;
+
+		default:
+			break;
+
+	}
+}
+
+static void bitlbee_init(int argc, char **argv)
+{
+	int i = -1;
+	memset( &global, 0, sizeof( global_t ) );
+
+	b_main_init();
+	
+	global.conf = conf_load( argc, argv );
+	if( global.conf == NULL )
+		return;
+	
+	if( global.conf->runmode == RUNMODE_INETD )
+	{
+		i = bitlbee_inetd_init();
+		log_message( LOGLVL_INFO, "Bitlbee %s starting in inetd mode.", BITLBEE_VERSION );
+
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		i = bitlbee_daemon_init();
+		log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION );
+	} 
+	else 
+	{
+		log_message( LOGLVL_INFO, "No bitlbee mode specified...");
+	}
+	
+	if( i != 0 )
+		return;
+ 	
+	if( access( global.conf->configdir, F_OK ) != 0 )
+		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, 06 ) != 0 )
+		log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir );
+	if( help_init( &(global.help), HELP_FILE ) == NULL )
+		log_message( LOGLVL_WARNING, "Error opening helpfile %s.", global.helpfile );
+}
+
+void service_main (DWORD argc, LPTSTR *argv)
+{
+	SERVICE_STATUS_HANDLE handle;
+	SERVICE_STATUS status;
+
+	handle = RegisterServiceCtrlHandler("bitlbee", service_ctrl);
+
+	if (!handle)
+		return;
+
+	status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+	status.dwServiceSpecificExitCode = 0;
+
+	bitlbee_init(argc, argv);
+
+	SetServiceStatus(handle, &status);
+	
+	b_main_run( );
+}
+
+SERVICE_TABLE_ENTRY dispatch_table[] =
+{
+   { TEXT("bitlbee"), (LPSERVICE_MAIN_FUNCTION)service_main },
+   { NULL, NULL }
+};
+
+static int debug = 0;
+
+static void usage()
+{
+	printf("Options:\n");
+	printf("-h   Show this help message\n");
+	printf("-d   Debug mode (simple console program)\n");
+}
+
+int main( int argc, char **argv)
+{	
+	int i;
+	WSADATA WSAData;
+
+	nogaim_init( );
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "-d")) debug = 1;
+		if (!strcmp(argv[i], "-h")) {
+			usage();
+			return 0;
+		}
+	}
+
+	WSAStartup(MAKEWORD(1,1), &WSAData);
+
+	if (!debug) {
+		if (!StartServiceCtrlDispatcher(dispatch_table))
+			log_message( LOGLVL_ERROR, "StartServiceCtrlDispatcher failed.");
+	} else {
+			bitlbee_init(argc, argv);
+ 			b_main_run();
+	}
+	
+	return 0;
+}
+
+double gettime()
+{
+	return (GetTickCount() / 1000);
+}
+
+void conf_get_string(HKEY section, const char *name, const char *def, char **dest)
+{
+	char buf[4096];
+	long x;
+	if (RegQueryValue(section, name, buf, &x) == ERROR_SUCCESS) {
+		*dest = g_strdup(buf);
+	} else if (!def) {
+		*dest = NULL;
+	} else {
+		*dest = g_strdup(def);
+	}
+}
+
+
+void conf_get_int(HKEY section, const char *name, int def, int *dest)
+{
+	char buf[20];
+	long x;
+	DWORD y;
+	if (RegQueryValue(section, name, buf, &x) == ERROR_SUCCESS) {
+		memcpy(&y, buf, sizeof(DWORD));
+		*dest = y;
+	} else {
+		*dest = def;
+	}
+}
+
+conf_t *conf_load( int argc, char *argv[] ) 
+{
+	conf_t *conf;
+	HKEY key, key_main, key_proxy;
+	char *tmp;
+
+	RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Bitlbee", &key);
+	RegOpenKey(key, "main", &key_main);
+	RegOpenKey(key, "proxy", &key_proxy);
+	
+	memset( &global, 0, sizeof( global_t ) );
+	b_main_init();
+
+	conf = g_new0( conf_t,1 );
+	global.conf = conf;
+	conf_get_string(key_main, "interface_in", "0.0.0.0", &global.conf->iface_in);
+	conf_get_string(key_main, "interface_out", "0.0.0.0", &global.conf->iface_out);
+	conf_get_string(key_main, "port", "6667", &global.conf->port);
+	conf_get_int(key_main, "verbose", 0, &global.conf->verbose);
+	conf_get_string(key_main, "auth_pass", "", &global.conf->auth_pass);
+	conf_get_string(key_main, "oper_pass", "", &global.conf->oper_pass);
+	conf_get_int(key_main, "ping_interval_timeout", 60, &global.conf->ping_interval);
+	conf_get_string(key_main, "hostname", "localhost", &global.conf->hostname);
+	conf_get_string(key_main, "configdir", NULL, &global.conf->configdir);
+	conf_get_string(key_main, "motdfile", NULL, &global.conf->motdfile);
+	conf_get_string(key_main, "helpfile", NULL, &global.helpfile);
+	global.conf->runmode = RUNMODE_DAEMON;
+	conf_get_int(key_main, "AuthMode", AUTHMODE_OPEN, (int *)&global.conf->authmode);
+	conf_get_string(key_proxy, "host", "", &tmp); strcpy(proxyhost, tmp);
+	conf_get_string(key_proxy, "user", "", &tmp); strcpy(proxyuser, tmp);
+	conf_get_string(key_proxy, "password", "", &tmp); strcpy(proxypass, tmp);
+	conf_get_int(key_proxy, "type", PROXY_NONE, &proxytype);
+	conf_get_int(key_proxy, "port", 3128, &proxyport);
+
+	RegCloseKey(key);
+	RegCloseKey(key_main);
+	RegCloseKey(key_proxy);
+
+	return conf;
+}
+
+void conf_loaddefaults( irc_t *irc )
+{
+	HKEY key_defaults;
+	int i;
+	char name[4096], data[4096];
+	DWORD namelen = sizeof(name), datalen = sizeof(data);
+	DWORD type;
+	if (RegOpenKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\Bitlbee\\defaults", &key_defaults) != ERROR_SUCCESS) {
+		return;
+	}
+
+	for (i = 0; RegEnumValue(key_defaults, i, name, &namelen, NULL, &type, data, &datalen) == ERROR_SUCCESS; i++) {
+		set_t *s = set_find( &irc->set, name );
+			
+		if( s )
+		{
+			if( s->def ) g_free( s->def );
+			s->def = g_strdup( data );
+		}
+
+		namelen = sizeof(name);
+		datalen = sizeof(data);
+	}
+
+	RegCloseKey(key_defaults);
+}
+
+#ifndef INADDR_NONE
+#define INADDR_NONE 0xffffffff
+#endif
+
+int
+inet_aton(const char *cp, struct in_addr *addr)
+{
+  addr->s_addr = inet_addr(cp);
+  return (addr->s_addr == INADDR_NONE) ? 0 : 1;
+}
+
+void log_error(char *msg)
+{
+	log_message(LOGLVL_ERROR, "%s", msg);
+}
+
+void log_message(int level, char *message, ...)
+{
+	HANDLE  hEventSource;
+	LPTSTR  lpszStrings[2];
+	WORD elevel;
+	va_list ap;
+
+	va_start(ap, message);
+
+	if (debug) {
+		vprintf(message, ap);
+		putchar('\n');
+		va_end(ap);
+		return;
+	}
+
+	hEventSource = RegisterEventSource(NULL, TEXT("bitlbee"));
+
+	lpszStrings[0] = TEXT("bitlbee");
+	lpszStrings[1] = g_strdup_vprintf(message, ap);
+	va_end(ap);
+
+	switch (level) {
+	case LOGLVL_ERROR: elevel = EVENTLOG_ERROR_TYPE; break;
+	case LOGLVL_WARNING: elevel = EVENTLOG_WARNING_TYPE; break;
+	case LOGLVL_INFO: elevel = EVENTLOG_INFORMATION_TYPE; break;
+#ifdef DEBUG
+	case LOGLVL_DEBUG: elevel = EVENTLOG_AUDIT_SUCCESS; break;
+#endif
+	}
+
+	if (hEventSource != NULL) {
+		ReportEvent(hEventSource, 
+		elevel,
+		0,					
+		0,					
+		NULL,				 
+		2,					
+		0,					
+		lpszStrings,		  
+		NULL);				
+
+		DeregisterEventSource(hEventSource);
+	}
+
+	g_free(lpszStrings[1]);
+}
+
+void log_link(int level, int output) { /* FIXME */ }
+
+struct tm *
+gmtime_r (const time_t *timer, struct tm *result)
+{
+	struct tm *local_result;
+	local_result = gmtime (timer);
+
+	if (local_result == NULL || result == NULL)
+		return NULL;
+
+	memcpy (result, local_result, sizeof (result));
+	return result;
+} 
