Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 2ff20765990c756533957e8da9c7c29dd3102e79)
+++ protocols/jabber/jabber.h	(revision dce390357114e30a424106c99e49cef1e682e1af)
@@ -146,5 +146,4 @@
 
 	size_t bytesread, byteswritten;
-	int receiver_overflow;
 	int fd;
 	struct sockaddr_storage saddr;
@@ -209,5 +208,5 @@
 int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
 gboolean jabber_bs_send_start( struct jabber_transfer *tf );
-gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, int len );
+gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len );
 
 /* message.c */
Index: protocols/jabber/s5bytestream.c
===================================================================
--- protocols/jabber/s5bytestream.c	(revision 2ff20765990c756533957e8da9c7c29dd3102e79)
+++ protocols/jabber/s5bytestream.c	(revision dce390357114e30a424106c99e49cef1e682e1af)
@@ -72,6 +72,4 @@
 		return jabber_bs_abort( bt , msg ": %s", strerror( errno ) );
 
-#define JABBER_BS_BUFSIZE 65536
-
 gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... );
 void jabber_bs_canceled( file_transfer_t *ft , char *reason );
@@ -83,5 +81,5 @@
 void jabber_bs_recv_answer_request( struct bs_transfer *bt );
 gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond );
-void jabber_bs_recv_out_of_data( file_transfer_t *ft );
+gboolean jabber_bs_recv_write_request( file_transfer_t *ft );
 gboolean jabber_bs_recv_handshake( gpointer data, gint fd, b_input_condition cond );
 gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error );
@@ -109,5 +107,5 @@
 	xt_free_node( bt->qnode );
 	g_free( bt );
-//iq_id
+
 	jabber_si_free_transfer( ft );
 }
@@ -326,5 +324,5 @@
 				sock_make_nonblocking( fd );
 
-				imcb_log( bt->tf->ic, "Transferring file %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, host, port );
+				imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, host, port );
 
 				if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&
@@ -426,5 +424,4 @@
 			jabber_bs_recv_answer_request( bt );
 
-			// reset in answer_request bt->tf->watch_in = 0;
 			return FALSE;
 		}
@@ -441,6 +438,8 @@
  * If the handshake failed we can try the next streamhost, if there is one.
  * An intelligent sender would probably specify himself as the first streamhost and
- * a proxy as the second (Kopete is an example here). That way, a (potentially) 
- * slow proxy is only used if neccessary.
+ * a proxy as the second (Kopete and PSI are examples here). That way, a (potentially) 
+ * slow proxy is only used if neccessary. This of course also means, that the timeout
+ * per streamhost should be kept short. If one or two firewalled adresses are specified,
+ * they have to timeout first before a proxy is tried.
  */
 gboolean jabber_bs_recv_handshake_abort( struct bs_transfer *bt, char *error )
@@ -494,5 +493,5 @@
 	struct xt_node *reply;
 
-	imcb_log( tf->ic, "Transferring file %s: established SOCKS5 connection to %s:%s", 
+	imcb_log( tf->ic, "File %s: established SOCKS5 connection to %s:%s", 
 		  tf->ft->file_name, 
 		  xt_find_attr( bt->shnode, "host" ),
@@ -501,6 +500,6 @@
 	tf->ft->data = tf;
 	tf->ft->started = time( NULL );
-	tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, tf );
-	tf->ft->out_of_data = jabber_bs_recv_out_of_data;
+	tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, bt );
+	tf->ft->write_request = jabber_bs_recv_write_request;
 
 	reply = xt_new_node( "streamhost-used", NULL, NULL );
@@ -519,67 +518,81 @@
 }
 
-/* Reads till it is unscheduled or the receiver signifies an overflow. */
+/* 
+ * This function is called from write_request directly. If no data is available, it will install itself
+ * as a watcher for input on fd and once that happens, deliver the data and unschedule itself again.
+ */
 gboolean jabber_bs_recv_read( gpointer data, gint fd, b_input_condition cond )
 {
 	int ret;
-	struct jabber_transfer *tf = data;
-	struct bs_transfer *bt = tf->streamhandle;
-	char *buffer = g_malloc( JABBER_BS_BUFSIZE );
-
-	if (tf->receiver_overflow)
-	{
-		if( tf->watch_in )
+	struct bs_transfer *bt = data;
+	struct jabber_transfer *tf = bt->tf;
+
+	if( fd != 0 ) /* called via event thread */
+	{
+		tf->watch_in = 0;
+		ASSERTSOCKOP( ret = recv( fd, tf->ft->buffer, sizeof( tf->ft->buffer ), 0 ) , "Receiving" );
+	}
+	else
+	{
+		/* called directly. There might not be any data available. */
+		if( ( ( ret = recv( tf->fd, tf->ft->buffer, sizeof( tf->ft->buffer ), 0 ) ) == -1 ) &&
+		    ( errno != EAGAIN ) )
+		    return jabber_bs_abort( bt, "Receiving: %s", strerror( errno ) );
+
+		if( ( ret == -1 ) && ( errno == EAGAIN ) )
 		{
-			/* should never happen, BUG */
-			imcb_file_canceled( tf->ft, "Bug in jabber file transfer code: read while overflow is true. Please report" );
+			tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, bt );
 			return FALSE;
 		}
 	}
 
-	ASSERTSOCKOP( ret = recv( fd, buffer, JABBER_BS_BUFSIZE, 0 ) , "Receiving" );
-
-	/* that should be all */
+	/* shouldn't happen since we know the file size */
 	if( ret == 0 )
+		return jabber_bs_abort( bt, "Remote end closed connection" );
+	
+	tf->bytesread += ret;
+
+	tf->ft->write( tf->ft, tf->ft->buffer, ret );	
+
+	return FALSE;
+}
+
+/* 
+ * imc callback that is invoked when it is ready to receive some data.
+ */
+gboolean jabber_bs_recv_write_request( file_transfer_t *ft )
+{
+	struct jabber_transfer *tf = ft->data;
+
+	if( tf->watch_in )
+	{
+		imcb_file_canceled( ft, "BUG in jabber file transfer: write_request called when already watching for input" );
 		return FALSE;
-	
-	tf->bytesread += ret;
-
-	buffer = g_realloc( buffer, ret );
-
-	if ( ( tf->receiver_overflow = imcb_file_write( tf->ft, buffer, ret ) ) )
-	{
-		/* wait for imcb to run out of data */
-		tf->watch_in = 0;
-		return FALSE;
-	}
-		
+	}
+	
+	jabber_bs_recv_read( tf->streamhandle, 0 , 0 );
+
 	return TRUE;
 }
 
-/* imcb callback that is invoked when it runs out of data.
- * We reschedule jabber_bs_read here if neccessary. */
-void jabber_bs_recv_out_of_data( file_transfer_t *ft )
-{
-	struct jabber_transfer *tf = ft->data;
-
-	tf->receiver_overflow = FALSE;
-
-	if ( !tf->watch_in )
-		tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_recv_read, tf );
-}
-
-/* signal ood and be done */
+/* 
+ * Issues a write_request to imc.
+ * */
 gboolean jabber_bs_send_can_write( gpointer data, gint fd, b_input_condition cond )
 {
 	struct bs_transfer *bt = data;
 
-	bt->tf->ft->out_of_data( bt->tf->ft );
-
 	bt->tf->watch_out = 0;
+
+	bt->tf->ft->write_request( bt->tf->ft );
+
 	return FALSE;
 }
 
-/* try to send the stuff. If you can't return false and wait for writable */
-gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, int len )
+/*
+ * This should only be called if we can write, so just do it.
+ * Add a write watch so we can write more during the next cycle (if possible).
+ */
+gboolean jabber_bs_send_write( file_transfer_t *ft, char *buffer, unsigned int len )
 {
 	struct jabber_transfer *tf = ft->data;
@@ -587,20 +600,23 @@
 	int ret;
 
-	if ( ( ( ret = send( tf->fd, buffer, len, 0 ) ) == -1 ) &&
-	     ( errno != EAGAIN ) )
-		return jabber_bs_abort( bt, "send failed on socket with: %s", strerror( errno ) );
-	
-	if( ret == 0 )
-		return jabber_bs_abort( bt, "Remote end closed connection" );
-	
-	if( ret == -1 )
-	{
-		bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_can_write, bt );
-		return FALSE;
-	}
+	if( tf->watch_out )
+		return jabber_bs_abort( bt, "BUG: write() called while watching " );
+	
+	ASSERTSOCKOP( ret = send( tf->fd, buffer, len, 0 ), "Sending" );
+
+	tf->byteswritten += ret;
+	
+	/* TODO: this should really not be fatal */
+	if( ret < len )
+		return jabber_bs_abort( bt, "send() sent %d instead of %d (send buffer too big!)", ret, len );
+
+	bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_can_write, bt );
 		
 	return TRUE;
 }
 
+/*
+ * Handles the reply by the receiver containing the used streamhost.
+ */
 static xt_status jabber_bs_send_handle_reply(struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) {
 	struct jabber_transfer *tf = NULL;
@@ -651,9 +667,8 @@
 	if( bt->phase == BS_PHASE_REPLY )
 	{
+		/* handshake went through, let's start transferring */
 		tf->ft->started = time( NULL );
-		tf->ft->out_of_data( tf->ft );
-	}
-
-	//bt->tf->watch_out = b_input_add( tf->fd, GAIM_INPUT_WRITE, jabber_bs_send_write, tf );
+		tf->ft->write_request( tf->ft );
+	}
 
 	return XT_HANDLED;
@@ -681,6 +696,4 @@
 	bt = g_new0( struct bs_transfer, 1 );
 	bt->tf = tf;
-	//bt->qnode = xt_dup( qnode );
-	//bt->shnode = bt->qnode->children;
 	bt->phase = BS_PHASE_CONNECT;
 	bt->pseudoadr = g_strdup( hash_hex );
@@ -714,6 +727,4 @@
 	iq = jabber_make_packet( "iq", "set", tf->tgt_jid, query );
 	xt_add_attr( iq, "from", tf->ini_jid );
-
-	//xt_free_node( query );
 
 	jabber_cache_add( tf->ic, iq, jabber_bs_send_handle_reply );
@@ -885,9 +896,11 @@
 			bt->phase = BS_PHASE_REPLY;
 
-			/* don't start sending till the streamhost-used message comes in */
+			imcb_log( tf->ic, "File %s: SOCKS5 handshake successful! Transfer about to start...", tf->ft->file_name );
+
 			if( tf->accepted )
 			{
+				/* streamhost-used message came already in(possible?), let's start sending */
 				tf->ft->started = time( NULL );
-				tf->ft->out_of_data( tf->ft );
+				tf->ft->write_request( tf->ft );
 			}
 
Index: protocols/jabber/si.c
===================================================================
--- protocols/jabber/si.c	(revision 2ff20765990c756533957e8da9c7c29dd3102e79)
+++ protocols/jabber/si.c	(revision dce390357114e30a424106c99e49cef1e682e1af)
@@ -84,5 +84,5 @@
 	struct jabber_data *jd = ic->proto_data;
 
-	imcb_log( ic, "Incoming file from %s : %s %zd bytes", ic->irc->nick, ft->file_name, ft->file_size );
+	imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );
 
 	tf = g_new0( struct jabber_transfer, 1 );
@@ -224,5 +224,5 @@
 
 /*
- * imcb called the accept callback which probably means that the user accepted this file transfer.
+ * imc called the accept callback which probably means that the user accepted this file transfer.
  * We send our response to the initiator.
  * In the next step, the initiator will send us a request for the given stream type.
@@ -275,9 +275,8 @@
 {
 	struct xt_node *c, *d;
-	char *ini_jid, *tgt_jid;
+	char *ini_jid, *tgt_jid, *iq_id;
 	GSList *tflist;
 	struct jabber_transfer *tf=NULL;
 	struct jabber_data *jd = ic->proto_data;
-	char *sid;
 
 	if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||
@@ -288,9 +287,8 @@
 	}
 	
-	imcb_log( ic, "GOT RESPONSE TO FILE" );
 	/* All this means we expect something like this: ( I think )
-	 * <iq from=... to=...>
+	 * <iq from=... to=... id=...>
 	 * 	<si xmlns=si>
-	 * 		<file xmlns=ft/>
+	 * 	[	<file xmlns=ft/>    ] <-- not neccessary
 	 * 		<feature xmlns=feature>
 	 * 			<x xmlns=xdata type=submit>
@@ -300,9 +298,9 @@
 	if( !( tgt_jid = xt_find_attr( node, "from" ) ) ||
 	    !( ini_jid = xt_find_attr( node, "to" ) ) ||
+	    !( iq_id   = xt_find_attr( node, "id" ) ) ||
 	    !( c = xt_find_node( node->children, "si" ) ) ||
 	    !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_SI ) == 0 ) ||
-	    !( sid = xt_find_attr( c, "id" ) )||
-	    !( d = xt_find_node( c->children, "file" ) ) ||
-	    !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) ||
+/*	    !( d = xt_find_node( c->children, "file" ) ) ||
+	    !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FILETRANSFER ) == 0 ) || */
 	    !( d = xt_find_node( c->children, "feature" ) ) ||
 	    !( strcmp( xt_find_attr( d, "xmlns" ), XMLNS_FEATURE ) == 0 ) ||
@@ -331,5 +329,5 @@
 	{
 		struct jabber_transfer *tft = tflist->data;
-		if( ( strcmp( tft->sid, sid ) == 0 ) )
+		if( ( strcmp( tft->iq_id, iq_id ) == 0 ) )
 		{
 		    	tf = tft;
@@ -346,4 +344,6 @@
 	tf->ini_jid = g_strdup( ini_jid );
 	tf->tgt_jid = g_strdup( tgt_jid );
+
+	imcb_log( ic, "File %s: %s accepted the transfer!", tf->ft->file_name, tgt_jid );
 
 	jabber_bs_send_start( tf );
@@ -423,4 +423,5 @@
 	node = jabber_make_packet( "iq", "set", bud ? bud->full_jid : who, sinode );
 	jabber_cache_add( ic, node, jabber_si_handle_response );
+	tf->iq_id = g_strdup( xt_find_attr( node, "id" ) );
 	
 	return jabber_write_packet( ic, node );
