Index: ipc.c
===================================================================
--- ipc.c	(revision 534e4069e0cfa8aee82f82603dc3ca05562a85dd)
+++ ipc.c	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
@@ -333,25 +333,8 @@
 		    strcmp( irc->password, cmd[3] ) == 0 )
 		{
-			GSList *l;
-			
-			/* TODO: Move this all into irc_switch_fd() or so and
-			   irc_sync() */
-			b_event_remove( irc->r_watch_source_id );
-			closesocket( irc->fd );
-			irc->fd = ipc_child_recv_fd;
-			irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc );
+			irc_switch_fd( irc, ipc_child_recv_fd );
+			irc_sync( irc );
+			irc_usermsg( irc, "You've successfully taken over your old session" );
 			ipc_child_recv_fd = -1;
-			
-			irc_write( irc, ":%s!%s@%s MODE %s :+%s", irc->user->nick,
-			           irc->user->user, irc->user->host, irc->user->nick,
-			           irc->umode );
-			
-			for( l = irc->channels; l; l = l->next )
-			{
-				irc_channel_t *ic = l->data;
-				if( ic->flags & IRC_CHANNEL_JOINED )
-					irc_send_join( ic, irc->user );
-			}
-			irc_usermsg( irc, "You've successfully taken over your old session" );
 			
 			ipc_to_master_str( "TAKEOVER DONE\r\n" );
@@ -377,5 +360,4 @@
 {
 	irc_t *irc = data;
-	GSList *l;
 	
 	/* Master->New connection */
@@ -392,11 +374,5 @@
 	irc_umode_set( irc, "-R", 1 );
 	
-	for( l = irc->channels; l; l = l->next )
-		irc_channel_del_user( l->data, irc->user, IRC_CDU_KICK,
-		                      "Switching to old session" );
-	
-	irc_write( irc, ":%s!%s@%s MODE %s :-%s", irc->user->nick,
-	           irc->user->user, irc->user->host, irc->user->nick,
-	           irc->umode );
+	irc_desync( irc );
 }
 
Index: ipc.h
===================================================================
--- ipc.h	(revision 534e4069e0cfa8aee82f82603dc3ca05562a85dd)
+++ ipc.h	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
@@ -55,4 +55,6 @@
 void ipc_child_disable();
 
+gboolean ipc_child_identify( irc_t *irc );
+
 void ipc_to_master( char **cmd );
 void ipc_to_master_str( char *format, ... ) G_GNUC_PRINTF( 1, 2 );
Index: irc.c
===================================================================
--- irc.c	(revision 534e4069e0cfa8aee82f82603dc3ca05562a85dd)
+++ irc.c	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
@@ -619,4 +619,83 @@
 }
 
+/* Flush sendbuffer if you can. If it fails, fail silently and let some
+   I/O event handler clean up. */
+void irc_flush( irc_t *irc )
+{
+	ssize_t n;
+	size_t len;
+	
+	if( irc->sendbuffer == NULL )
+		return;
+	
+	len = strlen( irc->sendbuffer );
+	if( ( n = send( irc->fd, irc->sendbuffer, len, 0 ) ) == len )
+	{
+		g_free( irc->sendbuffer );
+		irc->sendbuffer = NULL;
+		
+		b_event_remove( irc->w_watch_source_id );
+		irc->w_watch_source_id = 0;
+	}
+	else if( n > 0 )
+	{
+		char *s = g_strdup( irc->sendbuffer + n );
+		g_free( irc->sendbuffer );
+		irc->sendbuffer = s;
+	}
+	/* Otherwise something went wrong and we don't currently care
+	   what the error was. We may or may not succeed later, we
+	   were just trying to flush the buffer immediately. */
+}
+
+/* Meant for takeover functionality. Transfer an IRC connection to a different
+   socket. */
+void irc_switch_fd( irc_t *irc, int fd )
+{
+	irc_write( irc, "ERROR :Transferring session to a new connection" );
+	irc_flush( irc ); /* Write it now or forget about it forever. */
+	
+	if( irc->sendbuffer )
+	{
+		b_event_remove( irc->w_watch_source_id );
+		g_free( irc->sendbuffer );
+		irc->sendbuffer = irc->w_watch_source_id = 0;
+	}
+	
+	b_event_remove( irc->r_watch_source_id );
+	closesocket( irc->fd );
+	irc->fd = fd;
+	irc->r_watch_source_id = b_input_add( irc->fd, B_EV_IO_READ, bitlbee_io_current_client_read, irc );
+}
+
+void irc_sync( irc_t *irc )
+{
+	GSList *l;
+	
+	irc_write( irc, ":%s!%s@%s MODE %s :+%s", irc->user->nick,
+	           irc->user->user, irc->user->host, irc->user->nick,
+	           irc->umode );
+	
+	for( l = irc->channels; l; l = l->next )
+	{
+		irc_channel_t *ic = l->data;
+		if( ic->flags & IRC_CHANNEL_JOINED )
+			irc_send_join( ic, irc->user );
+	}
+}
+
+void irc_desync( irc_t *irc )
+{
+	GSList *l;
+	
+	for( l = irc->channels; l; l = l->next )
+		irc_channel_del_user( l->data, irc->user, IRC_CDU_KICK,
+		                      "Switching to old session" );
+	
+	irc_write( irc, ":%s!%s@%s MODE %s :-%s", irc->user->nick,
+	           irc->user->user, irc->user->host, irc->user->nick,
+	           irc->umode );
+}
+
 int irc_check_login( irc_t *irc )
 {
Index: irc.h
===================================================================
--- irc.h	(revision 534e4069e0cfa8aee82f82603dc3ca05562a85dd)
+++ irc.h	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
@@ -229,4 +229,9 @@
 void irc_write_all( int now, char *format, ... ) G_GNUC_PRINTF( 2, 3 );
 void irc_vawrite( irc_t *irc, char *format, va_list params );
+
+void irc_flush( irc_t *irc );
+void irc_switch_fd( irc_t *irc, int fd );
+void irc_sync( irc_t *irc );
+void irc_desync( irc_t *irc );
 
 int irc_check_login( irc_t *irc );
Index: root_commands.c
===================================================================
--- root_commands.c	(revision 534e4069e0cfa8aee82f82603dc3ca05562a85dd)
+++ root_commands.c	(revision f1c2b21af3a51796b747ca4dbc2cdec9611efc5d)
@@ -28,6 +28,5 @@
 #include "bitlbee.h"
 #include "help.h"
-
-#include <string.h>
+#include "ipc.h"
 
 void root_command_string( irc_t *irc, char *command )
