Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ bitlbee.c	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -105,10 +105,17 @@
 		else if( i != 0 ) 
 			exit( 0 );
-		close( 0 );
-		close( 1 );
-		close( 2 );
+		
 		chdir( "/" );
+		
+		/* Sometimes std* are already closed (for example when we're in a RESTARTed
+		   BitlBee process. So let's only close TTY-fds. */
+		if( isatty( 0 ) ) close( 0 );
+		if( isatty( 0 ) ) close( 1 );
+		if( isatty( 0 ) ) close( 2 );
 	}
 #endif
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		ipc_master_load_state();
 	
 	if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
@@ -246,4 +253,10 @@
 	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
 	pid_t client_pid = 0;
+	
+	if( new_socket == -1 )
+	{
+		log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) );
+		return TRUE;
+	}
 	
 	if( global.conf->runmode == RUNMODE_FORKDAEMON )
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ bitlbee.h	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -121,4 +121,5 @@
 	char *helpfile;
 	GMainLoop *loop;
+	int restart;
 } global_t;
 
Index: conf.c
===================================================================
--- conf.c	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ conf.c	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -32,4 +32,5 @@
 #include "ini.h"
 #include "url.h"
+#include "ipc.h"
 
 #include "protocols/proxy.h"
@@ -78,5 +79,5 @@
 	}
 	
-	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:h" ) ) >= 0 )
+	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:" ) ) >= 0 )
 	/*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
 	{
@@ -147,4 +148,12 @@
 			        "  -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 );
 		}
 	}
Index: ipc.c
===================================================================
--- ipc.c	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ ipc.c	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -2,5 +2,5 @@
   * BitlBee -- An IRC to other IM-networks gateway                     *
   *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  * Copyright 2002-2006 Wilmer van der Gaast and others                *
   \********************************************************************/
 
@@ -30,5 +30,5 @@
 
 GSList *child_list = NULL;
-
+static char *statefile = NULL;
 
 static void ipc_master_cmd_client( irc_t *data, char **cmd )
@@ -36,5 +36,5 @@
 	struct bitlbee_child *child = (void*) data;
 	
-	if( child )
+	if( child && cmd[1] )
 	{
 		child->host = g_strdup( cmd[1] );
@@ -43,6 +43,7 @@
 	}
 	
-	ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
-	                     child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
+	if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 )
+		ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
+		                     child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
 }
 
@@ -74,6 +75,21 @@
 }
 
+void ipc_master_cmd_restart( irc_t *data, char **cmd )
+{
+	struct bitlbee_child *child = (void*) data;
+	
+	if( global.conf->runmode != RUNMODE_FORKDAEMON )
+	{
+		/* Tell child that this is unsupported. */
+		return;
+	}
+	
+	global.restart = -1;
+	bitlbee_shutdown( NULL );
+}
+
 static const command_t ipc_master_commands[] = {
 	{ "client",     3, ipc_master_cmd_client,     0 },
+	{ "hello",      0, ipc_master_cmd_client,     0 },
 	{ "die",        0, ipc_master_cmd_die,        0 },
 	{ "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
@@ -82,4 +98,5 @@
 	{ "rehash",     0, ipc_master_cmd_rehash,     0 },
 	{ "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
+	{ "restart",    0, ipc_master_cmd_restart,    0 },
 	{ NULL }
 };
@@ -140,4 +157,12 @@
 	irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
 	irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
+}
+
+static void ipc_child_cmd_hello( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		ipc_to_master_str( "HELLO\r\n" );
+	else
+		ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
 }
 
@@ -149,4 +174,5 @@
 	{ "rehash",     0, ipc_child_cmd_rehash,      0 },
 	{ "kill",       2, ipc_child_cmd_kill,        0 },
+	{ "hello",      0, ipc_child_cmd_hello,       0 },
 	{ NULL }
 };
@@ -385,2 +411,90 @@
 	child_list = NULL;
 }
+
+char *ipc_master_save_state()
+{
+	char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" );
+	int fd = mkstemp( fn );
+	GSList *l;
+	FILE *fp;
+	int i;
+	
+	if( fd == -1 )
+	{
+		log_message( LOGLVL_ERROR, "Could not create temporary file: %s", strerror( errno ) );
+		g_free( fn );
+		return NULL;
+	}
+	
+	/* This is more convenient now. */
+	fp = fdopen( fd, "w" );
+	
+	for( l = child_list, i = 0; l; l = l->next )
+		i ++;
+	
+	/* Number of client processes. */
+	fprintf( fp, "%d\n", i );
+	
+	for( l = child_list; l; l = l->next )
+		fprintf( fp, "%d %d\n", ((struct bitlbee_child*)l->data)->pid,
+		                        ((struct bitlbee_child*)l->data)->ipc_fd );
+	
+	if( fclose( fp ) == 0 )
+	{
+		return fn;
+	}
+	else
+	{
+		unlink( fn );
+		g_free( fn );
+		return NULL;
+	}
+}
+
+void ipc_master_set_statefile( char *fn )
+{
+	statefile = g_strdup( fn );
+}
+
+int ipc_master_load_state()
+{
+	struct bitlbee_child *child;
+	FILE *fp;
+	int i, n;
+	
+	if( statefile == NULL )
+		return 0;
+	fp = fopen( statefile, "r" );
+	unlink( statefile );	/* Why do it later? :-) */
+	if( fp == NULL )
+		return 0;
+	
+	if( fscanf( fp, "%d", &n ) != 1 )
+	{
+		log_message( LOGLVL_WARNING, "Could not import state information for child processes." );
+		fclose( fp );
+		return 0;
+	}
+	
+	log_message( LOGLVL_INFO, "Importing information for %d child processes.", n );
+	for( i = 0; i < n; i ++ )
+	{
+		child = g_new0( struct bitlbee_child, 1 );
+		
+		if( fscanf( fp, "%d %d", &child->pid, &child->ipc_fd ) != 2 )
+		{
+			log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i );
+			g_free( child );
+			fclose( fp );
+			return 0;
+		}
+		child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
+		
+		child_list = g_slist_append( child_list, child );
+	}
+	
+	ipc_to_children_str( "HELLO\r\n" );
+	ipc_to_children_str( "OPERMSG :New BitlBee master process started (version " BITLBEE_VERSION ")\r\n" );
+	
+	return 1;
+}
Index: ipc.h
===================================================================
--- ipc.h	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ ipc.h	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -54,4 +54,8 @@
 void ipc_master_cmd_rehash( irc_t *data, char **cmd );
 
+char *ipc_master_save_state();
+void ipc_master_set_statefile( char *fn );
+int ipc_master_load_state();
+
 
 extern GSList *child_list;
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ irc_commands.c	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -573,4 +573,5 @@
 	{ "lilo",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
 	{ "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
+	{ "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
 	{ "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
 	{ NULL }
Index: unix.c
===================================================================
--- unix.c	(revision 34b17d9b8901b72439167b99d780c481ce420e33)
+++ unix.c	(revision 1d2e3c2ee2fb4c12ad25832b93ae9513d042717a)
@@ -29,4 +29,5 @@
 #include "protocols/nogaim.h"
 #include "help.h"
+#include "ipc.h"
 #include <signal.h>
 #include <unistd.h>
@@ -38,7 +39,8 @@
 static void sighandler( int signal );
 
-int main( int argc, char *argv[] )
+int main( int argc, char *argv[], char **envp )
 {
 	int i = 0;
+	char *old_cwd;
 	struct sigaction sig, old;
 	
@@ -73,4 +75,13 @@
 	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
 	{
+		/* In case the operator requests a restart, we need this. */
+		old_cwd = g_malloc( 256 );
+		if( getcwd( old_cwd, 255 ) == NULL )
+		{
+			log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
+			g_free( old_cwd );
+			old_cwd = NULL;
+		}
+		
 		i = bitlbee_daemon_init();
 		log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );
@@ -108,4 +119,33 @@
 	g_main_run( global.loop );
 	
+	if( global.restart )
+	{
+		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];
+		}
+		
+		close( global.listen_socket );
+		
+		execve( args[0], args, envp );
+	}
+	
 	return( 0 );
 }
