Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ bitlbee.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -293,4 +293,6 @@
 			srand( time( NULL ) ^ getpid() );
 			
+			b_main_init();
+			
 			/* Close the listening socket, we're a client. */
 			close( global.listen_socket );
Index: bitlbee.conf
===================================================================
--- bitlbee.conf	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ bitlbee.conf	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -19,4 +19,11 @@
 ##
 # RunMode = Inetd
+
+## User:
+## 
+## If BitlBee is started by root as a daemon, it can drop root privileges,
+## and change to the specified user.
+##
+# User = bitlbee
 
 ## DaemonPort/DaemonInterface:
Index: conf.c
===================================================================
--- conf.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ conf.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -63,4 +63,5 @@
 	conf->ping_interval = 180;
 	conf->ping_timeout = 300;
+	conf->user = NULL;
 	conf->max_filetransfer_size = G_MAXUINT;
 	proxytype = 0;
@@ -77,5 +78,5 @@
 	}
 	
-	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:" ) ) >= 0 )
+	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:u:" ) ) >= 0 )
 	/*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
 	{
@@ -133,4 +134,5 @@
 			        "  -D  Daemon mode. (Still EXPERIMENTAL!)\n"
 			        "  -F  Forking daemon. (one process per client)\n"
+				"  -u  Run daemon as specified user.\n"
 			        "  -P  Specify PID-file (not for inetd mode)\n"
 			        "  -i  Specify the interface (by IP address) to listen on.\n"
@@ -152,4 +154,9 @@
 			ipc_master_set_statefile( optarg );
 		}
+		else if( opt == 'u' )
+		{
+			g_free( conf->user );
+			conf->user = g_strdup( optarg );
+		}
 	}
 	
@@ -193,8 +200,10 @@
 			else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 )
 			{
+				g_free( conf->iface );
 				conf->iface = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "daemonport" ) == 0 )
 			{
+				g_free( conf->port );
 				conf->port = g_strdup( ini->value );
 			}
@@ -210,12 +219,15 @@
 			else if( g_strcasecmp( ini->key, "authpassword" ) == 0 )
 			{
+				g_free( conf->auth_pass );
 				conf->auth_pass = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "operpassword" ) == 0 )
 			{
+				g_free( conf->oper_pass );
 				conf->oper_pass = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "hostname" ) == 0 )
 			{
+				g_free( conf->hostname );
 				conf->hostname = g_strdup( ini->value );
 			}
@@ -282,4 +294,9 @@
 				g_free( url );
 			}
+			else if( g_strcasecmp( ini->key, "user" ) == 0 )
+			{
+				g_free( conf->user );
+				conf->user = g_strdup( ini->value );
+			}
 			else
 			{
Index: conf.h
===================================================================
--- conf.h	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ conf.h	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -49,4 +49,5 @@
 	int ping_interval;
 	int ping_timeout;
+	char *user;
 	size_t max_filetransfer_size;
 } conf_t;
Index: configure
===================================================================
--- configure	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ configure	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -135,5 +135,5 @@
 	[ -z "$CFLAGS" ] && CFLAGS=-g
 	echo 'DEBUG=1' >> Makefile.settings
-	echo '#define DEBUG' >> config.h
+	CFLAGS="$CFLAGS -DDEBUG"
 else
 	[ -z "$CFLAGS" ] && CFLAGS="-O2 -fno-strict-aliasing"
Index: irc.c
===================================================================
--- irc.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ irc.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -324,9 +324,20 @@
 			}
 			
-			if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) )
+			if( ( cs = set_getstr( &irc->set, "charset" ) ) )
 			{
 				conv[IRC_MAX_LINE] = 0;
-				if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) != -1 )
-					lines[i] = conv;
+				if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 )
+				{
+					if( irc->status & USTATUS_LOGGED_IN )
+						irc_usermsg( irc, "ERROR: Charset mismatch detected. The charset "
+						                  "setting is currently set to %s, so please make "
+						                  "sure your IRC client will send and accept text in "
+						                  "that charset, or tell BitlBee which charset to "
+						                  "expect by changing the charset setting. See "
+						                  "`help set charset' for more information. Your "
+						                  "message was ignored.", cs );
+					*conv = 0;
+				}
+				lines[i] = conv;
 			}
 			
Index: lib/events.h
===================================================================
--- lib/events.h	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ lib/events.h	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -45,5 +45,5 @@
 #include <gmodule.h>
 
-/* The conditions you can pass to gaim_input_add()/that will be passed to
+/* The conditions you can pass to b_input_add()/that will be passed to
    the given callback function. */
 typedef enum {
@@ -58,5 +58,5 @@
 #define GAIM_ERR_COND   (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
 
-// #define event_debug( x... ) printf( x )
+/* #define event_debug( x... ) printf( x ) */
 #define event_debug( x... )
 
Index: lib/events_libevent.c
===================================================================
--- lib/events_libevent.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ lib/events_libevent.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -32,10 +32,10 @@
 #include <unistd.h>
 #include <sys/types.h>
-#include "proxy.h"
-
 #include <sys/time.h>
 #include <event.h>
-
-static guint id_next;
+#include "proxy.h"
+
+static void b_main_restart();
+static guint id_next = 1;
 static GHashTable *id_hash;
 static int quitting = 0;
@@ -48,4 +48,7 @@
 static GHashTable *write_hash;
 
+struct event_base *leh;
+struct event_base *old_leh;
+
 struct b_event_data
 {
@@ -59,7 +62,14 @@
 void b_main_init()
 {
-	event_init();
-	
-	id_next = 1;
+	if( leh != NULL )
+	{
+		/* Clean up the hash tables? */
+		
+		b_main_restart();
+		old_leh = leh;
+	}
+	
+	leh = event_init();
+	
 	id_hash = g_hash_table_new( g_int_hash, g_int_equal );
 	read_hash = g_hash_table_new( g_int_hash, g_int_equal );
@@ -69,17 +79,38 @@
 void b_main_run()
 {
-	event_dispatch();
+	/* This while loop is necessary to exit the event loop and start a
+	   different one (necessary for ForkDaemon mode). */
+	while( event_base_dispatch( leh ) == 0 && !quitting )
+	{
+		if( old_leh != NULL )
+		{
+			/* For some reason this just isn't allowed...
+			   Possibly a bug in older versions, will see later.
+			event_base_free( old_leh ); */
+			old_leh = NULL;
+		}
+		
+		event_debug( "New event loop.\n" );
+	}
+}
+
+static void b_main_restart()
+{
+	struct timeval tv;
+	
+	memset( &tv, 0, sizeof( struct timeval ) );
+	event_base_loopexit( leh, &tv );
+	
+	event_debug( "b_main_restart()\n" );
 }
 
 void b_main_quit()
 {
-	struct timeval tv;
-	
-	/* libevent sometimes generates events before really quitting,
+	/* Tell b_main_run() that it shouldn't restart the loop. Also,
+	   libevent sometimes generates events before really quitting,
 	   we want to stop them. */
 	quitting = 1;
 	
-	memset( &tv, 0, sizeof( struct timeval ) );
-	event_loopexit( &tv );
+	b_main_restart();
 }
 
Index: protocols/jabber/conference.c
===================================================================
--- protocols/jabber/conference.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/jabber/conference.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -24,4 +24,6 @@
 #include "jabber.h"
 
+static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+
 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password )
 {
@@ -35,12 +37,11 @@
 	xt_add_attr( node, "xmlns", XMLNS_MUC );
 	node = jabber_make_packet( "presence", NULL, roomjid, node );
+	jabber_cache_add( ic, node, jabber_chat_join_failed );
 	
 	if( !jabber_write_packet( ic, node ) )
 	{
 		g_free( roomjid );
-		xt_free_node( node );
 		return NULL;
 	}
-	xt_free_node( node );
 	
 	jc = g_new0( struct jabber_chat, 1 );
@@ -63,4 +64,43 @@
 	
 	return c;
+}
+
+static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+	struct jabber_error *err;
+	struct jabber_buddy *bud;
+	char *room;
+	
+	room = xt_find_attr( orig, "to" );
+	if( ( bud = jabber_buddy_by_jid( ic, room, 0 ) ) )
+		jabber_chat_free( jabber_chat_by_jid( ic, bud->bare_jid ) );
+	
+	err = jabber_error_parse( xt_find_node( node->children, "error" ), XMLNS_STANZA_ERROR );
+	if( err )
+	{
+		imcb_error( ic, "Error joining groupchat %s: %s%s%s",
+		            bud->bare_jid, err->code, err->text ? ": " : "",
+		            err->text ? err->text : "" );
+		jabber_error_free( err );
+	}
+	
+	return XT_HANDLED;
+}
+
+struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name )
+{
+	char *normalized = jabber_normalize( name );
+	struct groupchat *ret;
+	struct jabber_chat *jc;
+	
+	for( ret = ic->groupchats; ret; ret = ret->next )
+	{
+		jc = ret->data;
+		if( strcmp( normalized, jc->name ) == 0 )
+			break;
+	}
+	g_free( normalized );
+	
+	return ret;
 }
 
@@ -148,5 +188,5 @@
 	char *s;
 	
-	if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL )
+	if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL )
 	{
 		/* How could this happen?? We could do kill( self, 11 )
@@ -250,5 +290,5 @@
 		return;
 	}
-	else if( ( chat = jabber_chat_by_name( ic, bud->bare_jid ) ) == NULL )
+	else if( ( chat = jabber_chat_by_jid( ic, bud->bare_jid ) ) == NULL )
 	{
 		/* How could this happen?? We could do kill( self, 11 )
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/jabber/iq.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -31,5 +31,4 @@
 {
 	struct im_connection *ic = data;
-	struct jabber_data *jd = ic->proto_data;
 	struct xt_node *c, *reply = NULL;
 	char *type, *s;
@@ -47,21 +46,5 @@
 	if( strcmp( type, "result" ) == 0 || strcmp( type, "error" ) == 0 )
 	{
-		struct jabber_cache_entry *entry;
-		
-		if( ( s = xt_find_attr( node, "id" ) ) == NULL ||
-		    strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 )
-		{
-			/* Silently ignore it, without an ID (or a non-cache
-			   ID) we don't know how to handle the packet and we
-			   probably don't have to. */
-			return XT_HANDLED;
-		}
-		
-		entry = g_hash_table_lookup( jd->node_cache, s );
-		
-		if( entry == NULL )
-			imcb_log( ic, "WARNING: Received IQ-%s packet with unknown/expired ID %s!", type, s );
-		else if( entry->func )
-			return entry->func( ic, node, entry->node );
+		return jabber_cache_handle_packet( ic, node );
 	}
 	else if( strcmp( type, "get" ) == 0 )
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/jabber/jabber.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -226,6 +226,4 @@
 	jd->cached_id_prefix = g_strdup_printf( "%s%s", JABBER_CACHED_ID, s );
 	g_free( s );
-	
-	printf( "%s\n", jd->cached_id_prefix );
 }
 
@@ -272,5 +270,5 @@
 		return jabber_write( ic, message, strlen( message ) );
 	
-	if( ( s = strchr( who, '=' ) ) && jabber_chat_by_name( ic, s + 1 ) )
+	if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )
 		bud = jabber_buddy_by_ext_jid( ic, who, 0 );
 	else
@@ -399,5 +397,5 @@
 	if( strchr( room, '@' ) == NULL )
 		imcb_error( ic, "Invalid room name: %s", room );
-	else if( jabber_chat_by_name( ic, room ) )
+	else if( jabber_chat_by_jid( ic, room ) )
 		imcb_error( ic, "Already present in chat `%s'", room );
 	else
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/jabber/jabber.h	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -227,4 +227,5 @@
 void jabber_cache_entry_free( gpointer entry );
 void jabber_cache_clean( struct im_connection *ic );
+xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node );
 const struct jabber_away_state *jabber_away_state_by_code( char *code );
 const struct jabber_away_state *jabber_away_state_by_name( char *name );
@@ -249,5 +250,4 @@
 int jabber_buddy_remove( struct im_connection *ic, char *full_jid );
 int jabber_buddy_remove_bare( struct im_connection *ic, char *bare_jid );
-struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name );
 time_t jabber_get_timestamp( struct xt_node *xt );
 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns );
@@ -272,4 +272,5 @@
 /* conference.c */
 struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password );
+struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name );
 void jabber_chat_free( struct groupchat *c );
 int jabber_chat_msg( struct groupchat *ic, char *message, int flags );
Index: protocols/jabber/jabber_util.c
===================================================================
--- protocols/jabber/jabber_util.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/jabber/jabber_util.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -183,4 +183,34 @@
 		return FALSE;
 	}
+}
+
+xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node *node )
+{
+	struct jabber_data *jd = ic->proto_data;
+	struct jabber_cache_entry *entry;
+	char *s;
+	
+	if( ( s = xt_find_attr( node, "id" ) ) == NULL ||
+	    strncmp( s, jd->cached_id_prefix, strlen( jd->cached_id_prefix ) ) != 0 )
+	{
+		/* Silently ignore it, without an ID (or a non-cache
+		   ID) we don't know how to handle the packet and we
+		   probably don't have to. */
+		return XT_HANDLED;
+	}
+	
+	entry = g_hash_table_lookup( jd->node_cache, s );
+	
+	if( entry == NULL )
+	{
+		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 )
+	{
+		return entry->func( ic, node, entry->node );
+	}
+	
+	return XT_HANDLED;
 }
 
@@ -595,21 +625,4 @@
 }
 
-struct groupchat *jabber_chat_by_name( struct im_connection *ic, const char *name )
-{
-	char *normalized = jabber_normalize( name );
-	struct groupchat *ret;
-	struct jabber_chat *jc;
-	
-	for( ret = ic->groupchats; ret; ret = ret->next )
-	{
-		jc = ret->data;
-		if( strcmp( normalized, jc->name ) == 0 )
-			break;
-	}
-	g_free( normalized );
-	
-	return ret;
-}
-
 time_t jabber_get_timestamp( struct xt_node *xt )
 {
@@ -663,8 +676,12 @@
 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns )
 {
-	struct jabber_error *err = g_new0( struct jabber_error, 1 );
+	struct jabber_error *err;
 	struct xt_node *c;
 	char *s;
 	
+	if( node == NULL )
+		return NULL;
+	
+	err = g_new0( struct jabber_error, 1 );
 	err->type = xt_find_attr( node, "type" );
 	
Index: protocols/jabber/presence.c
===================================================================
--- protocols/jabber/presence.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/jabber/presence.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -40,5 +40,5 @@
 	{
 		*s = 0;
-		if( jabber_chat_by_name( ic, from ) )
+		if( jabber_chat_by_jid( ic, from ) )
 			is_chat = 1;
 		*s = '/';
@@ -164,6 +164,8 @@
 	else if( strcmp( type, "error" ) == 0 )
 	{
+		return jabber_cache_handle_packet( ic, node );
+		
+		/*
 		struct jabber_error *err;
-		
 		if( ( c = xt_find_node( node->children, "error" ) ) )
 		{
@@ -173,6 +175,5 @@
 			            err->text ? err->text : "" );
 			jabber_error_free( err );
-		}
-		/* What else to do with it? */
+		} */
 	}
 	
Index: protocols/oscar/msgcookie.c
===================================================================
--- protocols/oscar/msgcookie.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ protocols/oscar/msgcookie.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -131,19 +131,4 @@
 }
 
-#if 0 /* debugging feature */
-int aim_dumpcookie(aim_msgcookie_t *cookie) 
-{
-
-	if (!cookie)
-		return -EINVAL;
-
-	printf("\tCookie at %p: %d/%s with %p, next %p\n", 
-			cookie, cookie->type, cookie->cookie, 
-			cookie->data, cookie->next);
-
-	return 0;
-}
-#endif
-
 /**
  * aim_cookie_free - free an aim_msgcookie_t struct
Index: unix.c
===================================================================
--- unix.c	(revision fa30fa598d2e77c998f9156d0f31ccf99b0c781f)
+++ unix.c	(revision 08135dff0e668622fc858d2ad8a7d0bdbdb8cb24)
@@ -34,4 +34,5 @@
 #include <sys/time.h>
 #include <sys/wait.h>
+#include <pwd.h>
 
 global_t global;	/* Against global namespace pollution */
@@ -45,6 +46,4 @@
 	struct sigaction sig, old;
 	
-	memset( &global, 0, sizeof( global_t ) );
-	
 	log_init();
 	CONF_FILE = g_strdup( CONF_FILE_DEF );
@@ -87,10 +86,24 @@
 		return( i );
 	
+	if( ( global.conf->user && *global.conf->user ) &&
+	    ( global.conf->runmode == RUNMODE_DAEMON || 
+	      global.conf->runmode == RUNMODE_FORKDAEMON ) &&
+	    ( !getuid() || !geteuid() ) )
+	{
+		struct passwd *pw = NULL;
+		pw = getpwnam( global.conf->user );
+		if( pw )
+		{
+			setgid( pw->pw_gid );
+			setuid( pw->pw_uid );
+		}
+	}
+
 	global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
-	if ( global.storage == NULL) {
+	if( global.storage == NULL )
+	{
 		log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
 		return( 1 );
 	}
-	
  	
 	/* Catch some signals to tell the user what's happening before quitting */
