Index: .bzrignore
===================================================================
--- .bzrignore	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ .bzrignore	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -12,2 +12,3 @@
 bitlbee.pc
 .gdb_history
+tests/check
Index: Makefile
===================================================================
--- Makefile	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ Makefile	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -46,4 +46,7 @@
 	rm -f Makefile.settings config.h
 	find . -name 'DEADJOE' -o -name '*.orig' -o -name '*.rej' -o -name '*~' -exec rm -f {} \;
+
+check:
+	$(MAKE) -C tests
 
 install-doc:
Index: configure
===================================================================
--- configure	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ configure	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -207,4 +207,27 @@
 echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings
 
+if [ "$events" = "libevent" ]; then
+	if ! [ -e "${libevent}include/event.h" ]; then
+		echo
+		echo 'Warning: Could not find event.h, you might have to install it and/or specify'
+		echo 'its location using the --libevent= argument. (Example: If event.h is in'
+		echo '/usr/local/include and binaries are in /usr/local/lib: --libevent=/usr/local)'
+	fi
+	
+	echo '#define EVENTS_LIBEVENT' >> config.h
+	cat <<EOF>>Makefile.settings
+EFLAGS+=-levent -L${libevent}lib
+CFLAGS+=-I${libevent}include
+EOF
+elif [ "$events" = "glib" ]; then
+	## We already use glib anyway, so this is all we need (and in fact not even this, but just to be sure...):
+	echo '#define EVENTS_GLIB' >> config.h
+else
+	echo
+	echo 'ERROR: Unknown event handler specified.'
+	exit 1
+fi
+echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings
+
 detect_gnutls()
 {
Index: lib/proxy.c
===================================================================
--- lib/proxy.c	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ lib/proxy.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -539,8 +539,4 @@
 	phb->data = data;
 	
-#ifndef _WIN32
-	sethostent(1);
-#endif
-	
 	if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || !proxyport || (proxyport == -1))
 		return proxy_connect_none(host, port, phb);
Index: nick.c
===================================================================
--- nick.c	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ nick.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -163,5 +163,5 @@
 	int i, j;
 	
-	for( i = j = 0; nick[i] && i < MAX_NICK_LENGTH; i++ )
+	for( i = j = 0; nick[i] && j < MAX_NICK_LENGTH; i++ )
 	{
 		if( strchr( nick_lc_chars, nick[i] ) || 
@@ -172,5 +172,5 @@
 		}
 	}
-	while( j < MAX_NICK_LENGTH )
+	while( j <= MAX_NICK_LENGTH )
 		nick[j++] = '\0';
 }
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ protocols/msn/msn.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -94,4 +94,6 @@
 			g_slist_free( md->msgq );
 		}
+		
+		g_free( md->grouplist );
 		
 		g_free( md );
Index: protocols/nogaim.c
===================================================================
--- protocols/nogaim.c	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ protocols/nogaim.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -294,7 +294,8 @@
 	
 	serv_got_crap( gc, "Signing off.." );
+	
+	b_event_remove( gc->keepalive );
 	gc->flags |= OPT_LOGGING_OUT;
 	
-	b_event_remove( gc->keepalive );
 	gc->keepalive = 0;
 	gc->prpl->close( gc );
Index: tests/Makefile
===================================================================
--- tests/Makefile	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
+++ tests/Makefile	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -0,0 +1,16 @@
+include ../Makefile.settings
+
+LFLAGS +=-lcheck
+
+all: check
+	./check
+
+main_objs = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o url.o user.o util.o 
+
+check: check.o check_util.o check_nick.o $(addprefix ../, $(main_objs)) ../protocols/protocols.o
+	@echo '*' Linking $@
+	@$(CC) $(CFLAGS) -o $@ $^ $(LFLAGS) $(EFLAGS)
+
+%.o: %.c
+	@echo '*' Compiling $<
+	@$(CC) -c $(CFLAGS) $< -o $@
Index: tests/check.c
===================================================================
--- tests/check.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
+++ tests/check.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -0,0 +1,32 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <check.h>
+#include "bitlbee.h"
+
+global_t global;	/* Against global namespace pollution */
+
+double gettime()
+{
+	struct timeval time[1];
+
+	gettimeofday( time, 0 );
+	return( (double) time->tv_sec + (double) time->tv_usec / 1000000 );
+}
+
+/* From check_util.c */
+Suite *util_suite(void);
+
+/* From check_nick.c */
+Suite *nick_suite(void);
+
+int main (void)
+{
+	int nf;
+	SRunner *sr = srunner_create(util_suite());
+	srunner_add_suite(sr, nick_suite());
+	srunner_run_all (sr, CK_NORMAL);
+	nf = srunner_ntests_failed(sr);
+	srunner_free(sr);
+	return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
Index: tests/check_nick.c
===================================================================
--- tests/check_nick.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
+++ tests/check_nick.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -0,0 +1,70 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <check.h>
+#include <string.h>
+#include "irc.h"
+#include "set.h"
+#include "util.h"
+
+START_TEST(test_nick_strip)
+{
+	int i;
+	const char *get[] = { "test:", "test", "test\n", 
+		"thisisaveryveryveryverylongnick", 
+		"thisisave:ryveryveryverylongnick",
+		"t::::est",
+		NULL };
+	const char *expected[] = { "test", "test", "test", 
+		"thisisaveryveryveryveryl", 
+		"thisisaveryveryveryveryl", 
+		"test",
+		NULL };
+
+	for (i = 0; get[i]; i++) {
+		char copy[30];
+		strcpy(copy, get[i]);
+		nick_strip(copy);
+		fail_unless (strcmp(copy, expected[i]) == 0, 
+					 "(%d) nick_strip broken: %s -> %s (expected: %s)", 
+					 i, get[i], copy, expected[i]);
+	}
+}
+END_TEST
+
+START_TEST(test_nick_ok_ok)
+{
+	const char *nicks[] = { "foo", "bar", "bla[", "blie]", 
+		                    "BreEZaH", "\\od^~", NULL };
+	int i;
+
+	for (i = 0; nicks[i]; i++) {
+		fail_unless (nick_ok(nicks[i]) == 1,
+					 "nick_ok() failed: %s", nicks[i]);
+	}
+}
+END_TEST
+
+START_TEST(test_nick_ok_notok)
+{
+	const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnick",
+		                    "\nillegalchar", "", "nick%", NULL };
+	int i;
+
+	for (i = 0; nicks[i]; i++) {
+		fail_unless (nick_ok(nicks[i]) == 0,
+					 "nick_ok() succeeded for invalid: %s", nicks[i]);
+	}
+}
+END_TEST
+
+Suite *nick_suite (void)
+{
+	Suite *s = suite_create("Nick");
+	TCase *tc_core = tcase_create("Core");
+	suite_add_tcase (s, tc_core);
+	tcase_add_test (tc_core, test_nick_ok_ok);
+	tcase_add_test (tc_core, test_nick_ok_notok);
+	tcase_add_test (tc_core, test_nick_strip);
+	return s;
+}
Index: tests/check_util.c
===================================================================
--- tests/check_util.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
+++ tests/check_util.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include <glib.h>
+#include <gmodule.h>
+#include <check.h>
+#include <string.h>
+#include "irc.h"
+#include "set.h"
+#include "util.h"
+
+START_TEST(test_strip_linefeed)
+{
+	int i;
+	const char *get[] = { "Test", "Test\r", "Test\rX\r", NULL };
+	const char *expected[] = { "Test", "Test", "TestX", NULL };
+
+	for (i = 0; get[i]; i++) {
+		char copy[20];
+		strcpy(copy, get[i]);
+		strip_linefeed(copy);
+		fail_unless (strcmp(copy, expected[i]) == 0, 
+					 "(%d) strip_linefeed broken: %s -> %s (expected: %s)", 
+					 i, get[i], copy, expected[i]);
+	}
+}
+END_TEST
+
+START_TEST(test_strip_newlines)
+{
+	int i;
+	const char *get[] = { "Test", "Test\r\n", "Test\nX\n", NULL };
+	const char *expected[] = { "Test", "Test  ", "Test X ", NULL };
+
+	for (i = 0; get[i]; i++) {
+		char copy[20], *ret;
+		strcpy(copy, get[i]);
+		ret = strip_newlines(copy);
+		fail_unless (strcmp(copy, expected[i]) == 0, 
+					 "(%d) strip_newlines broken: %s -> %s (expected: %s)", 
+					 i, get[i], copy, expected[i]);
+		fail_unless (copy == ret, "Original string not returned"); 
+	}
+}
+END_TEST
+
+Suite *util_suite (void)
+{
+	Suite *s = suite_create("Util");
+	TCase *tc_core = tcase_create("Core");
+	suite_add_tcase (s, tc_core);
+	tcase_add_test (tc_core, test_strip_linefeed);
+	tcase_add_test (tc_core, test_strip_newlines);
+	return s;
+}
Index: user.c
===================================================================
--- user.c	(revision 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9)
+++ user.c	(revision fd037705664ea03d7a0574c44161ae03b000fb2c)
@@ -106,7 +106,8 @@
 			if( u->nick != u->host ) g_free( u->host );
 			if( u->nick != u->realname ) g_free( u->realname );
-			if( u->away ) g_free( u->away );
-			if( u->handle ) g_free( u->handle );
-			if( u->sendbuf ) g_free( u->sendbuf );
+			g_free( u->group );
+			g_free( u->away );
+			g_free( u->handle );
+			g_free( u->sendbuf );
 			if( u->sendbuf_timer ) b_event_remove( u->sendbuf_timer );
 			g_free( u );
