Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ bitlbee.c	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -111,4 +111,7 @@
 #endif
 	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		ipc_master_load_state();
+	
 	return( 0 );
 }
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ bitlbee.h	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -121,4 +121,5 @@
 	char *helpfile;
 	GMainLoop *loop;
+	int restart;
 } global_t;
 
Index: conf.c
===================================================================
--- conf.c	(revision f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ conf.c	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -32,4 +32,5 @@
 #include "ini.h"
 #include "url.h"
+#include "ipc.h"
 
 #include "protocols/proxy.h"
@@ -77,5 +78,5 @@
 	}
 	
-	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:h" ) ) >= 0 )
+	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:nvIDFc:d:hR:" ) ) >= 0 )
 	/*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
 	{
@@ -141,4 +142,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 f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ ipc.c	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -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 }
 };
@@ -155,5 +181,5 @@
 static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
 {
-	int i;
+	int i, j;
 	
 	if( !cmd[0] )
@@ -163,4 +189,10 @@
 		if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
 		{
+			/* There is no typo in this line: */
+			for( j = 1; cmd[j]; j ++ ); j --;
+			
+			if( j < commands[i].required_parameters )
+				break;
+			
 			if( commands[i].flags & IPC_CMD_TO_CHILDREN )
 				ipc_to_children( cmd );
@@ -168,5 +200,5 @@
 				commands[i].execute( data, cmd );
 			
-			return;
+			break;
 		}
 }
@@ -379,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 f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ ipc.h	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -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 f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ irc_commands.c	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -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 }
@@ -579,5 +580,5 @@
 void irc_exec( irc_t *irc, char *cmd[] )
 {	
-	int i;
+	int i, n_arg;
 	
 	if( !cmd[0] )
@@ -587,4 +588,7 @@
 		if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
 		{
+			/* There should be no typo in the next line: */
+			for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
+			
 			if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status >= USTATUS_LOGGED_IN )
 			{
@@ -599,5 +603,5 @@
 				irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
 			}
-			else if( !cmd[irc_commands[i].required_parameters] )
+			else if( n_arg < irc_commands[i].required_parameters )
 			{
 				irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
Index: unix.c
===================================================================
--- unix.c	(revision f73b9697f9be18e04ec7458634520f9dd2e2432f)
+++ unix.c	(revision 54879ab3b2cbcaf1c9114bddd85ec5d4dc097915)
@@ -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 );
 }
