Index: ipc.c
===================================================================
--- ipc.c	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
+++ ipc.c	(revision e92c4f4f63ca0ba9ac6f959f7ff894ad2fc72a04)
@@ -171,4 +171,9 @@
 	struct bitlbee_child *child = (void*) data;
 	char *fwd = NULL;
+	
+	/* Normal daemon mode doesn't keep these and has simplified code for
+	   takeovers. */
+	if( child == NULL )
+		return;
 	
 	if( child->to_child == NULL ||
@@ -359,5 +364,6 @@
 static void ipc_child_cmd_takeover_yes( void *data )
 {
-	irc_t *irc = data;
+	irc_t *irc = data, *old = NULL;
+	char *to_auth[] = { "TAKEOVER", "AUTH", irc->user->nick, irc->password, NULL };
 	
 	/* Master->New connection */
@@ -365,7 +371,38 @@
 	                   irc->user->nick, irc->password );
 	
+	if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		GSList *l;
+		
+		for( l = irc_connection_list; l; l = l->next )
+		{
+			old = l->data;
+			
+			if( irc != old &&
+			    irc->user->nick && old->user->nick &&
+			    irc->password && old->password &&
+			    strcmp( irc->user->nick, old->user->nick ) == 0 &&
+			    strcmp( irc->password, old->password ) == 0 )
+				break;
+		}
+		if( l == NULL )
+		{
+			to_auth[1] = "FAIL";
+			ipc_child_cmd_takeover( irc, to_auth );
+			return;
+		}
+	}
+	
 	/* Drop credentials, we'll shut down soon and shouldn't overwrite
 	   any settings. */
 	irc_usermsg( irc, "Trying to take over existing session" );
+	
+	irc_desync( irc );
+	
+	if( old )
+	{
+		ipc_child_recv_fd = dup( irc->fd );
+		ipc_child_cmd_takeover( old, to_auth );
+	}
 	
 	/* TODO: irc_setpass() should do all of this. */
@@ -374,5 +411,9 @@
 	irc_umode_set( irc, "-R", 1 );
 	
-	irc_desync( irc );
+	if( old )
+	{
+		irc->status |= USTATUS_SHUTDOWN;
+		irc_abort( irc, FALSE, NULL );
+	}
 }
 
@@ -403,4 +444,28 @@
 	
 		ipc_to_master_str( "IDENTIFY %s :%s\r\n", irc->user->nick, irc->password );
+		
+		return TRUE;
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		GSList *l;
+		irc_t *old;
+		char *to_init[] = { "TAKEOVER", "INIT", NULL };
+		
+		for( l = irc_connection_list; l; l = l->next )
+		{
+			old = l->data;
+			
+			if( irc != old &&
+			    irc->user->nick && old->user->nick &&
+			    irc->password && old->password &&
+			    strcmp( irc->user->nick, old->user->nick ) == 0 &&
+			    strcmp( irc->password, old->password ) == 0 )
+				break;
+		}
+		if( l == NULL )
+			return FALSE;
+		
+		ipc_child_cmd_takeover( irc, to_init );
 		
 		return TRUE;
@@ -509,8 +574,12 @@
 				
 				*recv_fd = *(int*) CMSG_DATA( cmsg );
+				/*
 				fprintf( stderr, "pid %d received fd %d\n", (int) getpid(), *recv_fd );
+				*/
 			}
 	
+	/*
 	fprintf( stderr, "pid %d received: %s", (int) getpid(), buf );
+	*/
 	return g_strndup( buf, size - 2 );
 }
Index: root_commands.c
===================================================================
--- root_commands.c	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
+++ root_commands.c	(revision e92c4f4f63ca0ba9ac6f959f7ff894ad2fc72a04)
@@ -155,14 +155,29 @@
 		irc->status |= USTATUS_IDENTIFIED;
 		irc_umode_set( irc, "+R", 1 );
-		irc_channel_auto_joins( irc, NULL );
-		
-		if( ipc_child_identify( irc ) )
-		{
-			if( load && set_getbool( &irc->b->set, "auto_connect" ) )
+		
+		/* The following code is a bit hairy now. With takeover
+		   support, we shouldn't immediately auto_connect in case
+		   we're going to offer taking over an existing session.
+		   Do it in 200ms since that should give the parent process
+		   enough time to come back to us. */
+		if( load )
+		{
+			irc_channel_auto_joins( irc, NULL );
+			if( 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" ) )
+		
+		/* If ipc_child_identify() returns FALSE, it means we're
+		   already sure that there's no takeover target (only
+		   possible in 1-process daemon mode). Start auto_connect
+		   immediately. */
+		if( !ipc_child_identify( irc ) && load &&
+		    set_getbool( &irc->b->set, "auto_connect" ) )
+		{
+			b_event_remove( irc->login_source_id );
+			irc->login_source_id = -1;
 			cmd_identify_finish( irc, 0, 0 );
+		}
 		
 		break;
