Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision 006a84f999248d1bc1c1e36fa3437765d4bd1142)
+++ bitlbee.c	(revision 6c2404e051cb6a235f985797c149af0791f44bbd)
@@ -318,8 +318,10 @@
 			struct bitlbee_child *child;
 			
+			/* TODO: Stuff like this belongs in ipc.c. */
 			child = g_new0( struct bitlbee_child, 1 );
 			child->pid = client_pid;
 			child->ipc_fd = fds[0];
 			child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
+			child->to_fd = -1;
 			child_list = g_slist_append( child_list, child );
 			
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision 006a84f999248d1bc1c1e36fa3437765d4bd1142)
+++ bitlbee.h	(revision 6c2404e051cb6a235f985797c149af0791f44bbd)
@@ -163,4 +163,5 @@
 void root_command_string( irc_t *irc, char *command );
 void root_command( irc_t *irc, char *command[] );
+gboolean cmd_identify_finish( gpointer data, gint fd, b_input_condition cond );
 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond );
 
Index: ipc.c
===================================================================
--- ipc.c	(revision 006a84f999248d1bc1c1e36fa3437765d4bd1142)
+++ ipc.c	(revision 6c2404e051cb6a235f985797c149af0791f44bbd)
@@ -110,4 +110,29 @@
 	global.restart = -1;
 	bitlbee_shutdown( NULL, -1, 0 );
+}
+
+void ipc_master_cmd_identify( irc_t *data, char **cmd )
+{
+	struct bitlbee_child *child = (void*) data, *old = NULL;
+	GSList *l;
+	
+	if( strcmp( child->nick, cmd[1] ) != 0 )
+		return;
+	
+	g_free( child->password );
+	child->password = g_strdup( cmd[2] );
+	
+	for( l = child_list; l; l = l->next )
+	{
+		old = l->data;
+		if( nick_cmp( old->nick, child->nick ) == 0 && child != old &&
+		    old->password && strcmp( old->password, child->password ) )
+			break;
+	}
+	
+	if( old == NULL )
+		return;
+	
+	child->to_child = old;
 }
 
@@ -123,4 +148,5 @@
 	{ "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
 	{ "restart",    0, ipc_master_cmd_restart,    0 },
+	{ "identify",   2, ipc_master_cmd_identify,   0 },
 	{ NULL }
 };
@@ -202,4 +228,20 @@
 };
 
+static gboolean ipc_send_fd( int fd, int send_fd );
+
+gboolean ipc_child_identify( irc_t *irc )
+{
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		if( !ipc_send_fd( global.listen_socket, irc->fd ) )
+			ipc_child_disable();
+	
+		ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password );
+		
+		return TRUE;
+	}
+	else
+		return FALSE;
+}
 
 static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
@@ -230,6 +272,10 @@
 /* Return just one line. Returns NULL if something broke, an empty string
    on temporary "errors" (EAGAIN and friends). */
-static char *ipc_readline( int fd )
-{
+static char *ipc_readline( int fd, int *recv_fd )
+{
+	struct msghdr msg;
+	struct iovec iov;
+	char ccmsg[CMSG_SPACE(sizeof(recv_fd))];
+	struct cmsghdr *cmsg;
 	char buf[513], *eol;
 	int size;
@@ -253,20 +299,42 @@
 		size = eol - buf + 2;
 	
-	if( recv( fd, buf, size, 0 ) != size )
+	iov.iov_base = buf;
+	iov.iov_len = size;
+	
+	memset( &msg, 0, sizeof( msg ) );
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = ccmsg;
+	msg.msg_controllen = sizeof( ccmsg );
+	
+	if( recvmsg( fd, &msg, 0 ) != size )
 		return NULL;
-	else
-		return g_strndup( buf, size - 2 );
+	
+	if( recv_fd )
+		for( cmsg = CMSG_FIRSTHDR( &msg ); cmsg; cmsg = CMSG_NXTHDR( &msg, cmsg ) )
+			if( cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS )
+			{
+				/* Getting more than one shouldn't happen but if it does,
+				   make sure we don't leave them around. */
+				if( *recv_fd != -1 )
+					close( *recv_fd );
+				
+				*recv_fd = *(int*) CMSG_DATA( cmsg );
+			}
+	
+	return g_strndup( buf, size - 2 );
 }
 
 gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond )
 {
+	struct bitlbee_child *child = data;
 	char *buf, **cmd;
 	
-	if( ( buf = ipc_readline( source ) ) )
+	if( ( buf = ipc_readline( source, &child->to_fd ) ) )
 	{
 		cmd = irc_parse_line( buf );
 		if( cmd )
 		{
-			ipc_command_exec( data, cmd, ipc_master_commands );
+			ipc_command_exec( child, cmd, ipc_master_commands );
 			g_free( cmd );
 		}
@@ -284,6 +352,7 @@
 {
 	char *buf, **cmd;
-	
-	if( ( buf = ipc_readline( source ) ) )
+	int recv_fd = -1;
+	
+	if( ( buf = ipc_readline( source, &recv_fd ) ) )
 	{
 		cmd = irc_parse_line( buf );
@@ -413,12 +482,41 @@
 }
 
+static gboolean ipc_send_fd( int fd, int send_fd )
+{
+	struct msghdr msg;
+	struct iovec iov;
+	char ccmsg[CMSG_SPACE(sizeof(fd))];
+	struct cmsghdr *cmsg;
+	
+	memset( &msg, 0, sizeof( msg ) );
+	iov.iov_base = "0x90\r\n";
+	iov.iov_len = 6;
+	msg.msg_iov = &iov;
+	msg.msg_iovlen = 1;
+	
+	msg.msg_control = ccmsg;
+	msg.msg_controllen = sizeof( ccmsg );
+	cmsg = CMSG_FIRSTHDR( &msg );
+	cmsg->cmsg_level = SOL_SOCKET;
+	cmsg->cmsg_type = SCM_RIGHTS;
+	cmsg->cmsg_len = CMSG_LEN( sizeof( send_fd ) );
+	*(int*)CMSG_DATA( cmsg ) = send_fd;
+	msg.msg_controllen = cmsg->cmsg_len;
+	
+	return sendmsg( fd, &msg, 0 ) == 6;
+}
+
 void ipc_master_free_one( struct bitlbee_child *c )
 {
 	b_event_remove( c->ipc_inpa );
 	closesocket( c->ipc_fd );
+	
+	if( c->to_fd != -1 )
+		close( c->to_fd );
 	
 	g_free( c->host );
 	g_free( c->nick );
 	g_free( c->realname );
+	g_free( c->password );
 	g_free( c );
 }
@@ -506,6 +604,6 @@
 	struct bitlbee_child *child = g_new0( struct bitlbee_child, 1 );
 	
+	child->to_fd = -1;
 	child->ipc_fd = accept( serversock, NULL, 0 );
-	
 	if( child->ipc_fd == -1 )
 	{
@@ -516,5 +614,5 @@
 	child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
 	
-	child_list = g_slist_append( child_list, child );
+	child_list = g_slist_prepend( child_list, child );
 	
 	return TRUE;
@@ -598,6 +696,7 @@
 		}
 		child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
-		
-		child_list = g_slist_append( child_list, child );
+		child->to_fd = -1;
+		
+		child_list = g_slist_prepend( child_list, child );
 	}
 	
Index: ipc.h
===================================================================
--- ipc.h	(revision 006a84f999248d1bc1c1e36fa3437765d4bd1142)
+++ ipc.h	(revision 6c2404e051cb6a235f985797c149af0791f44bbd)
@@ -37,4 +37,10 @@
 	char *nick;
 	char *realname;
+	
+	char *password;
+	
+	/* For takeovers: */
+	struct bitlbee_child *to_child;
+	int to_fd;
 };
 
Index: irc.h
===================================================================
--- irc.h	(revision 006a84f999248d1bc1c1e36fa3437765d4bd1142)
+++ irc.h	(revision 6c2404e051cb6a235f985797c149af0791f44bbd)
@@ -87,4 +87,5 @@
 	gint w_watch_source_id;
 	gint ping_source_id;
+	gint login_source_id; /* To slightly delay some events at login time. */
 	
 	struct bee *b;
Index: root_commands.c
===================================================================
--- root_commands.c	(revision 006a84f999248d1bc1c1e36fa3437765d4bd1142)
+++ root_commands.c	(revision 6c2404e051cb6a235f985797c149af0791f44bbd)
@@ -105,5 +105,4 @@
 {
 	storage_status_t status;
-	char *account_on[] = { "account", "on", NULL };
 	gboolean load = TRUE;
 	char *password = cmd[1];
@@ -158,6 +157,14 @@
 		irc_umode_set( irc, "+R", 1 );
 		irc_channel_auto_joins( irc, NULL );
-		if( load && set_getbool( &irc->b->set, "auto_connect" ) )
-			cmd_account( irc, account_on );
+		
+		if( ipc_child_identify( irc ) )
+		{
+			if( load && set_getbool( &irc->b->set, "auto_connect" ) )
+				irc->login_source_id = b_timeout_add( 200,
+					cmd_identify_finish, irc );
+		}
+		else if( load && set_getbool( &irc->b->set, "auto_connect" ) )
+			cmd_identify_finish( irc, 0, 0 );
+		
 		break;
 	case STORAGE_OTHER_ERROR:
@@ -166,4 +173,14 @@
 		break;
 	}
+}
+
+gboolean cmd_identify_finish( gpointer data, gint fd, b_input_condition cond )
+{
+	char *account_on[] = { "account", "on", NULL };
+	irc_t *irc = data;
+	
+	cmd_account( irc, account_on );
+	
+	return FALSE;
 }
 
@@ -672,5 +689,5 @@
 	else if( iu == irc->user )
 	{
-		irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
+		irc_usermsg( irc, "Use /nick to change your own nickname" );
 	}
 	else if( !nick_ok( cmd[2] ) )
