Index: protocols/purple/ft.c
===================================================================
--- protocols/purple/ft.c	(revision 5d1b3a9529f7aadab62026be0eb9f4ca0f6311ce)
+++ protocols/purple/ft.c	(revision c96c72f16ea48ca769400ff91bd2eb434da19f6e)
@@ -46,4 +46,80 @@
 
 struct im_connection *purple_ic_by_pa( PurpleAccount *pa );
+static gboolean prplcb_xfer_new_send_cb( gpointer data, gint fd, b_input_condition cond );
+static gboolean prpl_xfer_write_request( struct file_transfer *ft );
+
+
+/* Receiving files (IM->UI): */
+static void prpl_xfer_accept( struct file_transfer *ft )
+{
+	struct prpl_xfer_data *px = ft->data;
+	purple_xfer_request_accepted( px->xfer, NULL );
+	prpl_xfer_write_request( ft );
+}
+
+static void prpl_xfer_canceled( struct file_transfer *ft, char *reason )
+{
+	struct prpl_xfer_data *px = ft->data;
+	purple_xfer_request_denied( px->xfer );
+}
+
+static void prplcb_xfer_new( PurpleXfer *xfer )
+{
+	if( purple_xfer_get_type( xfer ) == PURPLE_XFER_RECEIVE )
+	{
+		struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1 );
+		
+		xfer->ui_data = px;
+		px->xfer = xfer;
+		px->fn = mktemp( g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ) );
+		px->fd = -1;
+		
+		purple_xfer_set_local_filename( xfer, px->fn );
+		
+		/* Sadly the xfer struct is still empty ATM so come back after
+		   the caller is done. */
+		b_timeout_add( 0, prplcb_xfer_new_send_cb, xfer );
+	}
+	else
+	{
+		/*
+		struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1 );
+		
+		px->fd = -1;
+		px->ft = next_ft;
+		px->ft->data = px;
+		px->xfer = xfer;
+		px->xfer->ui_data = px;
+		
+		purple_xfer_set_filename( xfer, px->ft->file_name );
+		purple_xfer_set_size( xfer, px->ft->file_size );
+		
+		next_ft = NULL;
+		*/
+	}
+}
+
+static gboolean prplcb_xfer_new_send_cb( gpointer data, gint fd, b_input_condition cond )
+{
+	PurpleXfer *xfer = data;
+	struct im_connection *ic = purple_ic_by_pa( xfer->account );
+	struct prpl_xfer_data *px = xfer->ui_data;
+	PurpleBuddy *buddy;
+	const char *who;
+	
+	buddy = purple_find_buddy( xfer->account, xfer->who );
+	who = buddy ? purple_buddy_get_name( buddy ) : xfer->who;
+	
+	/* TODO(wilmer): After spreading some more const goodness in BitlBee,
+	   remove the evil cast below. */
+	px->ft = imcb_file_send_start( ic, (char*) who, xfer->filename, xfer->size );
+	px->ft->data = px;
+	
+	px->ft->accept = prpl_xfer_accept;
+	px->ft->canceled = prpl_xfer_canceled;
+	px->ft->write_request = prpl_xfer_write_request;
+	
+	return FALSE;
+}
 
 gboolean try_write_to_ui( gpointer data, gint fd, b_input_condition cond )
@@ -53,6 +129,4 @@
 	struct stat fs;
 	off_t tx_bytes;
-	
-	fprintf( stderr, "write_to_ui\n" );
 	
 	/* If we don't have the file opened yet, there's no data so wait. */
@@ -63,6 +137,4 @@
 	fstat( px->fd, &fs );
 	
-	fprintf( stderr, "write_to_ui %zd %zd %zd\n", fs.st_size, tx_bytes, px->xfer->size );
-	
 	if( fs.st_size > tx_bytes )
 	{
@@ -72,5 +144,4 @@
 		if( read( px->fd, buf, n ) == n && ft->write( ft, buf, n ) )
 		{
-			fprintf( stderr, "Wrote %zd bytes\n", n );
 			px->ui_wants_data = FALSE;
 		}
@@ -96,6 +167,4 @@
 	struct prpl_xfer_data *px = ft->data;
 	
-	fprintf( stderr, "wrq\n" );
-	
 	px->ui_wants_data = TRUE;
 	try_write_to_ui( ft, 0, 0 );
@@ -104,83 +173,6 @@
 }
 
-static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigned int len )
-{
-	return FALSE;
-}
-
-static void prpl_xfer_accept( struct file_transfer *ft )
-{
-	struct prpl_xfer_data *px = ft->data;
-	purple_xfer_request_accepted( px->xfer, NULL );
-	prpl_xfer_write_request( ft );
-}
-
-static void prpl_xfer_canceled( struct file_transfer *ft, char *reason )
-{
-	struct prpl_xfer_data *px = ft->data;
-	purple_xfer_request_denied( px->xfer );
-}
-
-static gboolean prplcb_xfer_new_send_cb( gpointer data, gint fd, b_input_condition cond );
-
-static void prplcb_xfer_new( PurpleXfer *xfer )
-{
-	if( purple_xfer_get_type( xfer ) == PURPLE_XFER_RECEIVE )
-	{
-		struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1 );
-		
-		xfer->ui_data = px;
-		px->xfer = xfer;
-		px->fn = mktemp( g_strdup( "/tmp/bitlbee-purple-ft.XXXXXX" ) );
-		px->fd = -1;
-		
-		purple_xfer_set_local_filename( xfer, px->fn );
-		
-		/* Sadly the xfer struct is still empty ATM so come back after
-		   the caller is done. */
-		b_timeout_add( 0, prplcb_xfer_new_send_cb, xfer );
-	}
-	else
-	{
-		/*
-		struct prpl_xfer_data *px = g_new0( struct prpl_xfer_data, 1 );
-		
-		px->fd = -1;
-		px->ft = next_ft;
-		px->ft->data = px;
-		px->xfer = xfer;
-		px->xfer->ui_data = px;
-		
-		purple_xfer_set_filename( xfer, px->ft->file_name );
-		purple_xfer_set_size( xfer, px->ft->file_size );
-		
-		next_ft = NULL;
-		*/
-	}
-}
-
-static gboolean prplcb_xfer_new_send_cb( gpointer data, gint fd, b_input_condition cond )
-{
-	PurpleXfer *xfer = data;
-	struct im_connection *ic = purple_ic_by_pa( xfer->account );
-	struct prpl_xfer_data *px = xfer->ui_data;
-	PurpleBuddy *buddy;
-	const char *who;
-	
-	buddy = purple_find_buddy( xfer->account, xfer->who );
-	who = buddy ? purple_buddy_get_name( buddy ) : xfer->who;
-	
-	/* TODO(wilmer): After spreading some more const goodness in BitlBee,
-	   remove the evil cast below. */
-	px->ft = imcb_file_send_start( ic, (char*) who, xfer->filename, xfer->size );
-	px->ft->data = px;
-	
-	px->ft->accept = prpl_xfer_accept;
-	px->ft->canceled = prpl_xfer_canceled;
-	px->ft->write_request = prpl_xfer_write_request;
-	
-	return FALSE;
-}
-
+
+/* Generic (IM<>UI): */
 static void prplcb_xfer_destroy( PurpleXfer *xfer )
 {
@@ -197,6 +189,4 @@
 	struct prpl_xfer_data *px = xfer->ui_data;
 	
-	fprintf( stderr, "prplcb_xfer_progress 0x%p %f\n", xfer, percent );
-	
 	if( px->fd == -1 && percent > 0 )
 	{
@@ -206,5 +196,5 @@
 		
 		/* Unlink it now, because we don't need it after this. */
-		//unlink( px->fn );
+		unlink( px->fn );
 	}
 	
@@ -212,4 +202,8 @@
 		try_write_to_ui( px->ft, 0, 0 );
 	else
+		/* Another nice problem: If we have the whole file, it only
+		   gets closed when we return. Problem: There may still be
+		   stuff buffered and not written, we'll only see it after
+		   the caller close()s the file. So poll the file after that. */
 		b_timeout_add( 0, try_write_to_ui, px->ft );
 }
@@ -226,4 +220,30 @@
 	fprintf( stderr, "prplcb_xfer_dbg 0x%p\n", xfer );
 }
+
+
+/* Sending files (UI->IM): */
+static gboolean prpl_xfer_write( struct file_transfer *ft, char *buffer, unsigned int len )
+{
+	return FALSE;
+}
+
+void purple_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *handle )
+{
+	PurpleAccount *pa = ic->proto_data;
+	struct prpl_xfer_data *px;
+	
+	/* xfer_new() will pick up this variable. It's a hack but we're not
+	   multi-threaded anyway. */
+	next_ft = ft;
+	serv_send_file( purple_account_get_connection( pa ), handle, ft->file_name );
+	
+	ft->write = prpl_xfer_write;
+	
+	px = ft->data;
+	imcb_file_recv_start( ft );
+}
+
+
+
 
 PurpleXferUiOps bee_xfer_uiops =
@@ -239,18 +259,2 @@
 	prplcb_xfer_dbg,
 };
-
-void purple_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *handle )
-{
-	PurpleAccount *pa = ic->proto_data;
-	struct prpl_xfer_data *px;
-	
-	/* xfer_new() will pick up this variable. It's a hack but we're not
-	   multi-threaded anyway. */
-	next_ft = ft;
-	serv_send_file( purple_account_get_connection( pa ), handle, ft->file_name );
-	
-	ft->write = prpl_xfer_write;
-	
-	px = ft->data;
-	imcb_file_recv_start( ft );
-}
Index: protocols/purple/purple.c
===================================================================
--- protocols/purple/purple.c	(revision 5d1b3a9529f7aadab62026be0eb9f4ca0f6311ce)
+++ protocols/purple/purple.c	(revision c96c72f16ea48ca769400ff91bd2eb434da19f6e)
@@ -142,8 +142,9 @@
 				PurpleKeyValuePair *kv = io->data;
 				opts = g_slist_append( opts, kv->value );
+				/* TODO: kv->value is not a char*, WTF? */
 				if( strcmp( kv->value, kv->key ) != 0 )
-					g_string_append_printf( help, "%s (%s), ", kv->value, kv->key );
+					g_string_append_printf( help, "%s (%s), ", (char*) kv->value, kv->key );
 				else
-					g_string_append_printf( help, "%s, ", kv->value );
+					g_string_append_printf( help, "%s, ", (char*) kv->value );
 			}
 			g_string_truncate( help, help->len - 2 );
@@ -455,5 +456,5 @@
 }
 
-void purple_chat_leave( struct groupchat *gc, char *who )
+void purple_chat_leave( struct groupchat *gc )
 {
 	PurpleConversation *pc = gc->data;
