Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ bitlbee.c	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -37,10 +37,28 @@
 	size_t size = sizeof( struct sockaddr_in );
 	struct sockaddr_in conn_info;
-	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, 
-		                     &size );
-	
-	log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
-	irc_new( new_socket );
-
+	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
+	pid_t client_pid = 0;
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		client_pid = fork();
+	
+	if( client_pid == 0 )
+	{
+		log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
+		irc_new( new_socket );
+		
+		if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		{
+			/* Close the listening socket, we're a client. */
+			close( global.listen_socket );
+			g_source_remove( global.listen_watch_source_id );
+		}
+	}
+	else
+	{
+		/* We don't need this one, only the client does. */
+		close( new_socket );
+	}
+	
 	return TRUE;
 }
@@ -66,5 +84,5 @@
 	listen_addr.sin_port = htons( global.conf->port );
 	listen_addr.sin_addr.s_addr = inet_addr( global.conf->iface );
-
+	
 	i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( struct sockaddr ) );
 	if( i == -1 )
@@ -73,5 +91,5 @@
 		return( -1 );
 	}
-
+	
 	i = listen( global.listen_socket, 10 );
 	if( i == -1 )
@@ -80,8 +98,8 @@
 		return( -1 );
 	}
-
+	
 	ch = g_io_channel_unix_new( global.listen_socket );
-	g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL );
-
+	global.listen_watch_source_id = g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL );
+	
 #ifndef _WIN32
 	if( !global.conf->nofork )
@@ -164,4 +182,6 @@
 		return FALSE;
 	} 
+	
+	return TRUE;
 	
 	/* Very naughty, go read the RFCs! >:) */
Index: bitlbee.conf
===================================================================
--- bitlbee.conf	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ bitlbee.conf	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -14,4 +14,7 @@
 ##    and other reasons, the use of daemon-mode is *STRONGLY* discouraged,
 ##    don't even *think* of reporting bugs when you use this.
+##  ForkDaemon -- Run as a stand-alone daemon, but keep all clients in separate
+##    child processes. This should be pretty safe and reliable to use instead
+##    of inetd mode.
 ##
 # RunMode = Inetd
@@ -41,4 +44,10 @@
 ##
 # AuthPassword = ItllBeBitlBee   ## Heh.. Our slogan. ;-)
+
+## OperPassword
+##
+## Password that unlocks access to special operator commands.
+##
+# OperPassword = ChangeMe!
 
 ## HostName
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ bitlbee.h	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -114,4 +114,5 @@
 typedef struct global_t {
 	int listen_socket;
+	gint listen_watch_source_id;
 	help_t *help;
 	conf_t *conf;
Index: conf.c
===================================================================
--- conf.c	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ conf.c	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -53,5 +53,6 @@
 	conf->runmode = RUNMODE_INETD;
 	conf->authmode = AUTHMODE_OPEN;
-	conf->password = NULL;
+	conf->auth_pass = NULL;
+	conf->oper_pass = NULL;
 	conf->configdir = g_strdup( CONFIG );
 	conf->plugindir = g_strdup( PLUGINDIR );
@@ -71,5 +72,5 @@
 	}
 	
-	while( ( opt = getopt( argc, argv, "i:p:nvIDc:d:h" ) ) >= 0 )
+	while( ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 )
 	{
 		if( opt == 'i' )
@@ -94,4 +95,6 @@
 		else if( opt == 'D' )
 			conf->runmode=RUNMODE_DAEMON;
+		else if( opt == 'F' )
+			conf->runmode=RUNMODE_FORKDAEMON;
 		else if( opt == 'c' )
 		{
@@ -118,4 +121,5 @@
 			        "  -I  Classic/InetD mode. (Default)\n"
 			        "  -D  Daemon mode. (Still EXPERIMENTAL!)\n"
+			        "  -F  Forking daemon. (one process per client)\n"
 			        "  -i  Specify the interface (by IP address) to listen on.\n"
 			        "      (Default: 0.0.0.0 (any interface))\n"
@@ -157,4 +161,6 @@
 				if( g_strcasecmp( ini->value, "daemon" ) == 0 )
 					conf->runmode = RUNMODE_DAEMON;
+				else if( g_strcasecmp( ini->value, "forkdaemon" ) == 0 )
+					conf->runmode = RUNMODE_FORKDAEMON;
 				else
 					conf->runmode = RUNMODE_INETD;
@@ -184,5 +190,9 @@
 			else if( g_strcasecmp( ini->key, "authpassword" ) == 0 )
 			{
-				conf->password = g_strdup( ini->value );
+				conf->auth_pass = g_strdup( ini->value );
+			}
+			else if( g_strcasecmp( ini->key, "operpassword" ) == 0 )
+			{
+				conf->oper_pass = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "hostname" ) == 0 )
Index: conf.h
===================================================================
--- conf.h	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ conf.h	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -27,5 +27,5 @@
 #define __CONF_H
 
-typedef enum runmode { RUNMODE_DAEMON, RUNMODE_INETD } runmode_t;
+typedef enum runmode { RUNMODE_DAEMON, RUNMODE_FORKDAEMON, RUNMODE_INETD } runmode_t;
 typedef enum authmode { AUTHMODE_OPEN, AUTHMODE_CLOSED, AUTHMODE_REGISTERED } authmode_t;
 
@@ -38,5 +38,6 @@
 	runmode_t runmode;
 	authmode_t authmode;
-	char *password;
+	char *auth_pass;
+	char *oper_pass;
 	char *hostname;
 	char *configdir;
Index: irc.c
===================================================================
--- irc.c	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ irc.c	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -264,5 +264,5 @@
 	g_free(irc);
 	
-	if( global.conf->runmode == RUNMODE_INETD )
+	if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
 		g_main_quit( global.loop );
 }
@@ -422,5 +422,5 @@
 				irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
 			}
-			else if( strcmp( cmd[1], (global.conf)->password ) == 0 )
+			else if( strcmp( cmd[1], (global.conf)->auth_pass ) == 0 )
 			{
 				irc->status = USTATUS_AUTHORIZED;
@@ -500,4 +500,13 @@
 	{
 		irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
+	}
+	else if( g_strcasecmp( cmd[0], "OPER" ) == 0 )
+	{
+		if( !cmd[2] )
+			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
+		else if( strcmp( cmd[2], global.conf->oper_pass ) == 0 )
+			irc_umode_set( irc, irc->nick, "+o" );
+		// else
+			/* FIXME/TODO: Find out which reply to send now. */
 	}
 	else if( g_strcasecmp( cmd[0], "MODE" ) == 0 )
Index: irc.h
===================================================================
--- irc.h	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ irc.h	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -40,5 +40,5 @@
 #define FLOOD_SEND_MAXBUFFER (1024*20)
 
-#define UMODES "ais"
+#define UMODES "aiso"
 #define CMODES "nt"
 #define CMODE "t"
Index: storage_text.c
===================================================================
--- storage_text.c	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ storage_text.c	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -71,5 +71,5 @@
 	user_t *ru = user_find( irc, ROOT_NICK );
 	
-	if( irc->status == USTATUS_IDENTIFIED )
+	if( irc->status >= USTATUS_IDENTIFIED )
 		return( 1 );
 	
Index: unix.c
===================================================================
--- unix.c	(revision ffea9b950b183dd54952b56703506508b0984d4b)
+++ unix.c	(revision d25f6fcbe8e291dd858bf734fa85cde176dc8415)
@@ -32,4 +32,5 @@
 #include <unistd.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 
 global_t global;	/* Against global namespace pollution */
@@ -46,5 +47,5 @@
 	global.loop = g_main_new( FALSE );
 	
-	log_init( );
+	log_init();
 
 	nogaim_init();
@@ -70,9 +71,13 @@
 		log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION );
 	}
+	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		i = bitlbee_daemon_init();
+		log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );
+	}
 	if( i != 0 )
 		return( i );
 
-	global.storage = storage_init( global.conf->primary_storage, 
-								   global.conf->migrate_storage );
+	global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
 	if ( global.storage == NULL) {
 		log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
@@ -84,4 +89,5 @@
 	memset( &sig, 0, sizeof( sig ) );
 	sig.sa_handler = sighandler;
+	sigaction( SIGCHLD, &sig, &old );
 	sigaction( SIGPIPE, &sig, &old );
 	sig.sa_flags = SA_RESETHAND;
@@ -107,5 +113,5 @@
 static void sighandler( int signal )
 {
-	/* FIXME: In fact, calling log_message() here can be dangerous. But well, let's take the risk for now. */
+	/* FIXME: Calling log_message() here is not a very good idea! */
 	
 	if( signal == SIGTERM )
@@ -133,4 +139,17 @@
 		}
 	}
+	else if( signal == SIGCHLD )
+	{
+		pid_t pid;
+		int st;
+		
+		while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 )
+		{
+			if( WIFSIGNALED( st ) )
+				log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", pid, WEXITSTATUS( st ) );
+			else if( WIFEXITED( st ) )
+				log_message( LOGLVL_INFO, "Client %d killed by signal %d.", pid, WTERMSIG( st ) );
+		}
+	}
 	else if( signal != SIGPIPE )
 	{
