Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision 4c266f2d79212e4e0ff4b9b33088685a2ec452e4)
+++ bitlbee.c	(revision 2face6292c693afb45e5e04f87ba080931eb16c3)
@@ -282,4 +282,6 @@
 			
 			close( fds[0] );
+			
+			ipc_master_free_all();
 		}
 	}
Index: ipc.c
===================================================================
--- ipc.c	(revision 4c266f2d79212e4e0ff4b9b33088685a2ec452e4)
+++ ipc.c	(revision 2face6292c693afb45e5e04f87ba080931eb16c3)
@@ -32,5 +32,19 @@
 
 
-static int ipc_master_cmd_die( irc_t *irc, char **cmd )
+static int ipc_master_cmd_client( irc_t *data, char **cmd )
+{
+	struct bitlbee_child *child = (void*) data;
+	
+	child->host = g_strdup( cmd[1] );
+	child->nick = g_strdup( cmd[2] );
+	child->realname = g_strdup( cmd[3] );
+	
+	ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
+	                     child->pid, child->nick, child->host, child->realname );
+	
+	return 1;
+}
+
+static int ipc_master_cmd_die( irc_t *data, char **cmd )
 {
 	if( global.conf->runmode == RUNMODE_FORKDAEMON )
@@ -42,5 +56,5 @@
 }
 
-static int ipc_master_cmd_rehash( irc_t *irc, char **cmd )
+static int ipc_master_cmd_rehash( irc_t *data, char **cmd )
 {
 	runmode_t oldmode;
@@ -64,7 +78,9 @@
 
 static const command_t ipc_master_commands[] = {
+	{ "client",     3, ipc_master_cmd_client,     0 },
 	{ "die",        0, ipc_master_cmd_die,        0 },
 	{ "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
 	{ "lilo",       1, NULL,                      IPC_CMD_TO_CHILDREN },
+	{ "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },
 	{ "rehash",     0, ipc_master_cmd_rehash,     0 },
 	{ "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
@@ -75,5 +91,8 @@
 static int ipc_child_cmd_die( irc_t *irc, char **cmd )
 {
-	bitlbee_shutdown( NULL );
+	if( irc->status >= USTATUS_LOGGED_IN )
+		irc_write( irc, "ERROR :Operator requested server shutdown, bye bye!" );
+	
+	irc_abort( irc );
 	
 	return 1;
@@ -98,4 +117,15 @@
 	if( strchr( irc->umode, 's' ) )
 		irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
+	
+	return 1;
+}
+
+static int ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		return 1;
+	
+	if( strchr( irc->umode, 'o' ) )
+		irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
 	
 	return 1;
@@ -135,4 +165,5 @@
 	{ "wallops",    1, ipc_child_cmd_wallops,     0 },
 	{ "lilo",       1, ipc_child_cmd_lilo,        0 },
+	{ "opermsg",    1, ipc_child_cmd_opermsg,     0 },
 	{ "rehash",     0, ipc_child_cmd_rehash,      0 },
 	{ "kill",       2, ipc_child_cmd_kill,        0 },
@@ -217,10 +248,6 @@
 			if( c->ipc_fd == source )
 			{
-				close( c->ipc_fd );
-				gaim_input_remove( c->ipc_inpa );
-				g_free( c );
-				
-				child_list = g_slist_remove( child_list, l );
-				
+				ipc_master_free_one( c );
+				child_list = g_slist_remove( child_list, c );
 				break;
 			}
@@ -253,5 +280,5 @@
 	{
 		char *s = irc_build_line( cmd );
-		ipc_to_master_str( s );
+		ipc_to_master_str( "%s", s );
 		g_free( s );
 	}
@@ -262,31 +289,39 @@
 }
 
-void ipc_to_master_str( char *msg_buf )
+void ipc_to_master_str( char *format, ... )
+{
+	char *msg_buf;
+	va_list params;
+
+	va_start( params, format );
+	msg_buf = g_strdup_vprintf( format, params );
+	va_end( params );
+	
+	if( strlen( msg_buf ) > 512 )
+	{
+		/* Don't send it, it's too long... */
+	}
+	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		write( global.listen_socket, msg_buf, strlen( msg_buf ) );
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		char **cmd;
+		
+		cmd = irc_parse_line( msg_buf );
+		ipc_command_exec( NULL, cmd, ipc_master_commands );
+		g_free( cmd );
+	}
+	
+	g_free( msg_buf );
+}
+
+void ipc_to_children( char **cmd )
 {
 	if( global.conf->runmode == RUNMODE_FORKDAEMON )
 	{
-		write( global.listen_socket, msg_buf, strlen( msg_buf ) );
-	}
-	else if( global.conf->runmode == RUNMODE_DAEMON )
-	{
-		char *s, **cmd;
-		
-		/* irc_parse_line() wants a read-write string, so get it one: */
-		s = g_strdup( msg_buf );
-		cmd = irc_parse_line( s );
-		
-		ipc_command_exec( NULL, cmd, ipc_master_commands );
-		
-		g_free( cmd );
-		g_free( s );
-	}
-}
-
-void ipc_to_children( char **cmd )
-{
-	if( global.conf->runmode == RUNMODE_FORKDAEMON )
-	{
 		char *msg_buf = irc_build_line( cmd );
-		ipc_to_children_str( msg_buf );
+		ipc_to_children_str( "%s", msg_buf );
 		g_free( msg_buf );
 	}
@@ -300,7 +335,18 @@
 }
 
-void ipc_to_children_str( char *msg_buf )
-{
-	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+void ipc_to_children_str( char *format, ... )
+{
+	char *msg_buf;
+	va_list params;
+
+	va_start( params, format );
+	msg_buf = g_strdup_vprintf( format, params );
+	va_end( params );
+	
+	if( strlen( msg_buf ) > 512 )
+	{
+		/* Don't send it, it's too long... */
+	}
+	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
 	{
 		int msg_len = strlen( msg_buf );
@@ -315,14 +361,33 @@
 	else if( global.conf->runmode == RUNMODE_DAEMON )
 	{
-		char *s, **cmd;
-		
-		/* irc_parse_line() wants a read-write string, so get it one: */
-		s = g_strdup( msg_buf );
-		cmd = irc_parse_line( s );
-		
+		char **cmd;
+		
+		cmd = irc_parse_line( msg_buf );
 		ipc_to_children( cmd );
-		
 		g_free( cmd );
-		g_free( s );
-	}
-}
+	}
+	
+	g_free( msg_buf );
+}
+
+void ipc_master_free_one( struct bitlbee_child *c )
+{
+	gaim_input_remove( c->ipc_inpa );
+	closesocket( c->ipc_fd );
+	
+	g_free( c->host );
+	g_free( c->nick );
+	g_free( c->realname );
+	g_free( c );
+}
+
+void ipc_master_free_all()
+{
+	GSList *l;
+	
+	for( l = child_list; l; l = l->next )
+		ipc_master_free_one( l->data );
+	
+	g_slist_free( child_list );
+	child_list = NULL;
+}
Index: ipc.h
===================================================================
--- ipc.h	(revision 4c266f2d79212e4e0ff4b9b33088685a2ec452e4)
+++ ipc.h	(revision 2face6292c693afb45e5e04f87ba080931eb16c3)
@@ -27,12 +27,4 @@
 #include "bitlbee.h"
 
-void ipc_master_read( gpointer data, gint source, GaimInputCondition cond );
-void ipc_child_read( gpointer data, gint source, GaimInputCondition cond );
-
-void ipc_to_master( char **cmd );
-void ipc_to_master_str( char *msg_buf );
-void ipc_to_children( char **cmd );
-void ipc_to_children_str( char *msg_buf );
-
 struct bitlbee_child
 {
@@ -40,5 +32,20 @@
 	int ipc_fd;
 	gint ipc_inpa;
+	
+	char *host;
+	char *nick;
+	char *realname;
 };
 
+void ipc_master_read( gpointer data, gint source, GaimInputCondition cond );
+void ipc_child_read( gpointer data, gint source, GaimInputCondition cond );
+
+void ipc_master_free_one( struct bitlbee_child *child );
+void ipc_master_free_all();
+
+void ipc_to_master( char **cmd );
+void ipc_to_master_str( char *format, ... );
+void ipc_to_children( char **cmd );
+void ipc_to_children_str( char *format, ... );
+
 extern GSList *child_list;
Index: irc.c
===================================================================
--- irc.c	(revision 4c266f2d79212e4e0ff4b9b33088685a2ec452e4)
+++ irc.c	(revision 2face6292c693afb45e5e04f87ba080931eb16c3)
@@ -27,4 +27,5 @@
 #include "bitlbee.h"
 #include "crypting.h"
+#include "ipc.h"
 
 static gboolean irc_userping( gpointer _irc );
@@ -689,8 +690,10 @@
 	u->realname = g_strdup( irc->realname );
 	u->online = 1;
-//	u->send_handler = msg_echo;
 	irc_spawn( irc, u );
 	
 	irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQ's are answered there." );
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
 	
 	irc->status = USTATUS_LOGGED_IN;
