Index: dcc.c
===================================================================
--- dcc.c	(revision 8076ec04b1b5699f8266fa0e2e17456974ced554)
+++ dcc.c	(revision dc0ba9c85539533349353713162f94077fb27be3)
@@ -125,5 +125,4 @@
 	file = df->ft;
 	file->write = dccs_send_write;
-	file->sending = TRUE;
 
 	/* listen and request */
Index: protocols/jabber/iq.c
===================================================================
--- protocols/jabber/iq.c	(revision 8076ec04b1b5699f8266fa0e2e17456974ced554)
+++ protocols/jabber/iq.c	(revision dc0ba9c85539533349353713162f94077fb27be3)
@@ -81,5 +81,5 @@
 			xt_add_child( reply, xt_new_node( "tz", buf, NULL ) );
 		}
-		else if( strcmp( s, XMLNS_DISCOVER ) == 0 )
+		else if( strcmp( s, XMLNS_DISCO_INFO ) == 0 )
 		{
 			const char *features[] = { XMLNS_VERSION,
@@ -565,2 +565,162 @@
 	return st;
 }
+
+xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+
+xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid )
+{
+	struct xt_node *node, *query;
+	struct jabber_buddy *bud;
+	
+	if( ( bud = jabber_buddy_by_jid( ic, bare_jid , 0 ) ) == NULL )
+	{
+		/* Who cares about the unknown... */
+		imcb_log( ic, "Couldnt find the man: %s", bare_jid);
+		return 0;
+	}
+	
+	if( bud->features ) /* been here already */
+		return XT_HANDLED;
+	
+	node = xt_new_node( "query", NULL, NULL );
+	xt_add_attr( node, "xmlns", XMLNS_DISCO_INFO );
+	
+	if( !( query = jabber_make_packet( "iq", "get", bare_jid, node ) ) )
+	{
+		imcb_log( ic, "WARNING: Couldn't generate feature query" );
+		xt_free_node( node );
+	}
+
+	jabber_cache_add( ic, query, jabber_iq_parse_features );
+
+	return jabber_write_packet( ic, query );
+}
+
+xt_status jabber_iq_parse_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+	struct xt_node *c;
+	struct jabber_buddy *bud;
+	char *feature;
+
+	if( !( c = xt_find_node( node->children, "query" ) ) ||
+	    !( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 ) )
+	{
+		imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
+		return XT_HANDLED;
+	}
+	if( ( bud = jabber_buddy_by_jid( ic, xt_find_attr( node, "from") , 0 ) ) == NULL )
+	{
+		/* Who cares about the unknown... */
+		imcb_log( ic, "Couldnt find the man: %s", xt_find_attr( node, "from"));
+		return 0;
+	}
+	
+	c = c->children;
+	while( ( c = xt_find_node( c, "feature" ) ) ) {
+		feature = xt_find_attr( c, "var" );
+		bud->features = g_slist_append(bud->features, g_strdup(feature) );
+		c = c->next;
+	}
+
+	return XT_HANDLED;
+}
+
+xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+
+xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns )
+{
+	struct xt_node *node, *query;
+	struct jabber_data *jd = ic->proto_data;
+	
+	node = xt_new_node( "query", NULL, NULL );
+	xt_add_attr( node, "xmlns", xmlns );
+	
+	if( !( query = jabber_make_packet( "iq", "get", jid, node ) ) )
+	{
+		imcb_log( ic, "WARNING: Couldn't generate server query" );
+		xt_free_node( node );
+	}
+
+	jd->have_streamhosts--;
+	jabber_cache_add( ic, query, jabber_iq_parse_server_features );
+
+	return jabber_write_packet( ic, query );
+}
+
+/*
+ * Query the server for "items", query each "item" for identities, query each "item" that's a proxy for it's bytestream info
+ */
+xt_status jabber_iq_parse_server_features( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+	struct xt_node *c;
+	struct jabber_data *jd = ic->proto_data;
+
+	if( !( c = xt_find_node( node->children, "query" ) ) ||
+	    !xt_find_attr( node, "from" ) )
+	{
+		imcb_log( ic, "WARNING: Received incomplete IQ-result packet for discover" );
+		return XT_HANDLED;
+	}
+
+	jd->have_streamhosts++;
+
+	if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_ITEMS ) == 0 )
+	{
+		char *item, *itemjid;
+
+		/* answer from server */
+	
+		c = c->children;
+		while( ( c = xt_find_node( c, "item" ) ) )
+		{
+			item = xt_find_attr( c, "name" );
+			itemjid = xt_find_attr( c, "jid" );
+
+			jabber_iq_query_server( ic, itemjid, XMLNS_DISCO_INFO );
+
+			c = c->next;
+		}
+	} else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_DISCO_INFO ) == 0 )
+	{
+		char *category, *type;
+
+		/* answer from potential proxy */
+
+		c = c->children;
+		while( ( c = xt_find_node( c, "identity" ) ) )
+		{
+			category = xt_find_attr( c, "category" );
+			type = xt_find_attr( c, "type" );
+
+			if( type && ( strcmp( type, "bytestreams" ) == 0 ) &&
+			    category && ( strcmp( category, "proxy" ) == 0 ) )
+				jabber_iq_query_server( ic, xt_find_attr( node, "from" ), XMLNS_BYTESTREAMS );
+
+			c = c->next;
+		}
+	} else if( strcmp( xt_find_attr( c, "xmlns" ), XMLNS_BYTESTREAMS ) == 0 )
+	{
+		char *host, *jid;
+		int port;
+
+		/* answer from proxy */
+
+		if( ( c = xt_find_node( c->children, "streamhost" ) ) &&
+		    ( host = xt_find_attr( c, "host" ) ) &&
+		    ( port = atoi( xt_find_attr( c, "port" ) ) ) &&
+		    ( jid = xt_find_attr( c, "jid" ) ) )
+		{
+			jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
+			sh->jid = g_strdup( jid );
+			sh->host = g_strdup( host );
+			sprintf( sh->port, "%u", port );
+
+			imcb_log( ic, "Proxy found: jid %s host %s port %u", jid, host, port );
+			jd->streamhosts = g_slist_append( jd->streamhosts, sh );
+		}
+	}
+
+	if( jd->have_streamhosts == 0 )
+		jd->have_streamhosts++;
+	return XT_HANDLED;
+}
Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 8076ec04b1b5699f8266fa0e2e17456974ced554)
+++ protocols/jabber/jabber.h	(revision dc0ba9c85539533349353713162f94077fb27be3)
@@ -57,4 +57,12 @@
 } jabber_buddy_flags_t;
 
+/* Stores a streamhost's(a.k.a. proxy) data */
+typedef struct
+{
+	char *jid;
+	char *host;
+	char port[6];
+} jabber_streamhost_t;
+
 struct jabber_data
 {
@@ -83,4 +91,6 @@
 
 	GSList *filetransfers;
+	GSList *streamhosts;
+	int have_streamhosts;
 };
 
@@ -111,4 +121,5 @@
 	struct jabber_away_state *away_state;
 	char *away_message;
+	GSList *features;
 	
 	time_t last_act;
@@ -182,5 +193,6 @@
 #define XMLNS_XDATA        "jabber:x:data"                                       /* XEP-0004 */
 #define XMLNS_CHATSTATES   "http://jabber.org/protocol/chatstates"               /* XEP-0085 */
-#define XMLNS_DISCOVER     "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
+#define XMLNS_DISCO_INFO   "http://jabber.org/protocol/disco#info"               /* XEP-0030 */
+#define XMLNS_DISCO_ITEMS  "http://jabber.org/protocol/disco#items"              /* XEP-0030 */
 #define XMLNS_MUC          "http://jabber.org/protocol/muc"                      /* XEP-0045 */
 #define XMLNS_MUC_USER     "http://jabber.org/protocol/muc#user"                 /* XEP-0045 */
@@ -199,4 +211,6 @@
 int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name );
 int jabber_remove_from_roster( struct im_connection *ic, char *handle );
+xt_status jabber_iq_query_features( struct im_connection *ic, char *bare_jid );
+xt_status jabber_iq_query_server( struct im_connection *ic, char *jid, char *xmlns );
 
 /* si.c */
Index: protocols/jabber/s5bytestream.c
===================================================================
--- protocols/jabber/s5bytestream.c	(revision 8076ec04b1b5699f8266fa0e2e17456974ced554)
+++ protocols/jabber/s5bytestream.c	(revision dc0ba9c85539533349353713162f94077fb27be3)
@@ -30,6 +30,6 @@
 	struct jabber_transfer *tf;
 
-	/* <query> element and <streamhost> elements */
-	struct xt_node *qnode, *shnode;
+	jabber_streamhost_t *sh;
+	GSList *streamhosts;
 
 	enum 
@@ -74,5 +74,5 @@
 gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... );
 void jabber_bs_canceled( file_transfer_t *ft , char *reason );
-void jabber_bs_free_transfer( file_transfer_t *ft);
+void jabber_bs_free_transfer( file_transfer_t *ft );
 gboolean jabber_bs_connect_timeout( gpointer data, gint fd, b_input_condition cond );
 gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents );
@@ -84,10 +84,12 @@
 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 );
-int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode);
+int jabber_bs_recv_request( struct im_connection *ic, struct xt_node *node, struct xt_node *qnode );
 
 gboolean jabber_bs_send_handshake_abort( struct bs_transfer *bt, char *error );
-gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *port );
+gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts );
 gboolean jabber_bs_send_handshake( gpointer data, gint fd, b_input_condition cond );
 gboolean jabber_bs_send_listen( struct bs_transfer *bt, struct sockaddr_storage *saddr, char *host, char *port );
+static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig );
+void jabber_bs_send_activate( struct bs_transfer *bt );
 
 /*
@@ -97,4 +99,5 @@
 	struct jabber_transfer *tf = ft->data;
 	struct bs_transfer *bt = tf->streamhandle;
+	jabber_streamhost_t *sh;
 
 	if ( tf->watch_in )
@@ -105,5 +108,14 @@
 	
 	g_free( bt->pseudoadr );
-	xt_free_node( bt->qnode );
+
+	while( bt->streamhosts )
+	{
+		sh = bt->streamhosts->data;
+		bt->streamhosts = g_slist_remove( bt->streamhosts, sh );
+		g_free( sh->jid );
+		g_free( sh->host );
+		g_free( sh );
+	}
+	
 	g_free( bt );
 
@@ -111,4 +123,8 @@
 }
 
+/*
+ * Checks if buflen data is available on the socket and
+ * writes it to buffer if that's the case.
+ */
 gboolean jabber_bs_peek( struct bs_transfer *bt, void *buffer, int buflen )
 {
@@ -147,4 +163,8 @@
 }
 
+/* 
+ * Polls the socket, checks for errors and removes a connect timer
+ * if there is one.
+ */
 gboolean jabber_bs_poll( struct bs_transfer *bt, int fd, short *revents )
 {
@@ -181,4 +201,7 @@
 }
 
+/*
+ * Used for receive and send path.
+ */
 gboolean jabber_bs_abort( struct bs_transfer *bt, char *format, ... )
 {
@@ -191,7 +214,7 @@
 	va_end( params );
 	if( bt->tf->ft->sending )
+		return jabber_bs_send_handshake_abort( bt, error );
+	else
 		return jabber_bs_recv_handshake_abort( bt, error );
-	else
-		return jabber_bs_send_handshake_abort( bt, error );
 }
 
@@ -214,4 +237,6 @@
 	GSList *tflist;
 	struct bs_transfer *bt;
+	GSList *shlist=NULL;
+	struct xt_node *shnode;
 
 	sha1_state_t sha;
@@ -233,4 +258,28 @@
 	{
 		imcb_log( ic, "WARNING: Received SI Request for unsupported bytestream mode %s", xt_find_attr( qnode, "mode" ) );
+		return XT_HANDLED;
+	}
+
+	shnode = qnode->children;
+	while( ( shnode = xt_find_node( shnode, "streamhost" ) ) )
+	{
+		char *jid, *host;
+		int port;
+		if( ( jid = xt_find_attr( shnode, "jid" ) ) &&
+		    ( host = xt_find_attr( shnode, "host" ) ) &&
+		    ( ( port = atoi( xt_find_attr( shnode, "port" ) ) ) ) )
+		{
+			jabber_streamhost_t *sh = g_new0( jabber_streamhost_t, 1 );
+			sh->jid = g_strdup(jid);
+			sh->host = g_strdup(host);
+			sprintf( sh->port, "%u", port );
+			shlist = g_slist_append( shlist, sh );
+		}
+		shnode = shnode->next;
+	}
+	
+	if( !shlist )
+	{
+		imcb_log( ic, "WARNING: Received incomplete SI bytestream request, no parseable streamhost entries");
 		return XT_HANDLED;
 	}
@@ -274,6 +323,6 @@
 	bt = g_new0( struct bs_transfer, 1 );
 	bt->tf = tf;
-	bt->qnode = xt_dup( qnode );
-	bt->shnode = bt->qnode->children;
+	bt->streamhosts = shlist;
+	bt->sh = shlist->data;
 	bt->phase = BS_PHASE_CONNECT;
 	bt->pseudoadr = g_strdup( hash_hex );
@@ -285,4 +334,5 @@
 	return XT_HANDLED;
 }
+
 /*
  * This is what a protocol handshake can look like in cooperative multitasking :)
@@ -305,43 +355,33 @@
 	case BS_PHASE_CONNECT:
 		{
-			struct xt_node *c;
-			char *host, *port;
 			struct addrinfo hints, *rp;
 
-			if( ( c = bt->shnode = xt_find_node( bt->shnode, "streamhost" ) ) &&
-			    ( port = xt_find_attr( c, "port" ) ) &&
-			    ( host = xt_find_attr( c, "host" ) ) &&
-			    xt_find_attr( c, "jid" ) )
-			{
-				memset( &hints, 0, sizeof( struct addrinfo ) );
-				hints.ai_socktype = SOCK_STREAM;
-
-				if ( getaddrinfo( host, port, &hints, &rp ) != 0 )
-					return jabber_bs_abort( bt, "getaddrinfo() failed: %s", strerror( errno ) );
-
-				ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" );
-
-				sock_make_nonblocking( fd );
-
-				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 ) &&
-				    ( errno != EINPROGRESS ) )
-					return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) );
-
-				freeaddrinfo( rp );
-
-				bt->phase = BS_PHASE_CONNECTED;
-				
-				bt->tf->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, jabber_bs_recv_handshake, bt );
-
-				/* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
-				bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt );
-
-				bt->tf->watch_in = 0;
-				return FALSE;
-			} else
-				return jabber_bs_abort( bt, c ? "incomplete streamhost entry: host=%s port=%s jid=%s" : NULL,
-								  host, port, xt_find_attr( c, "jid" ) );
+			memset( &hints, 0, sizeof( struct addrinfo ) );
+			hints.ai_socktype = SOCK_STREAM;
+
+			if ( getaddrinfo( bt->sh->host, bt->sh->port, &hints, &rp ) != 0 )
+				return jabber_bs_abort( bt, "getaddrinfo() failed: %s", strerror( errno ) );
+
+			ASSERTSOCKOP( bt->tf->fd = fd = socket( rp->ai_family, rp->ai_socktype, 0 ), "Opening socket" );
+
+			sock_make_nonblocking( fd );
+
+			imcb_log( bt->tf->ic, "File %s: Connecting to streamhost %s:%s", bt->tf->ft->file_name, bt->sh->host, bt->sh->port );
+
+			if( ( connect( fd, rp->ai_addr, rp->ai_addrlen ) == -1 ) &&
+			    ( errno != EINPROGRESS ) )
+				return jabber_bs_abort( bt , "connect() failed: %s", strerror( errno ) );
+
+			freeaddrinfo( rp );
+
+			bt->phase = BS_PHASE_CONNECTED;
+			
+			bt->tf->watch_out = b_input_add( fd, GAIM_INPUT_WRITE, jabber_bs_recv_handshake, bt );
+
+			/* since it takes forever(3mins?) till connect() fails on itself we schedule a timeout */
+			bt->connect_timeout = b_timeout_add( JABBER_BS_CONTIMEOUT * 1000, jabber_bs_connect_timeout, bt );
+
+			bt->tf->watch_in = 0;
+			return FALSE;
 		}
 	case BS_PHASE_CONNECTED:
@@ -422,5 +462,8 @@
 					socks5_reply.addrlen);
 
-			jabber_bs_recv_answer_request( bt );
+			if( bt->tf->ft->sending )
+				jabber_bs_send_activate( bt );
+			else
+				jabber_bs_recv_answer_request( bt );
 
 			return FALSE;
@@ -447,21 +490,21 @@
 	struct jabber_transfer *tf = bt->tf;
 	struct xt_node *reply, *iqnode;
-
-	if( bt->shnode ) 
-	{
-		imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)", 
-			  tf->ft->file_name, 
-			  xt_find_attr( bt->shnode, "host" ),
-			  xt_find_attr( bt->shnode, "port" ),
-			  error );
-
-		/* Alright, this streamhost failed, let's try the next... */
-		bt->phase = BS_PHASE_CONNECT;
-		bt->shnode = bt->shnode->next;
-		
-		/* the if is not neccessary but saves us one recursion */
-		if( bt->shnode )
-			return jabber_bs_recv_handshake( bt, 0, 0 );
-	}
+	GSList *shlist;
+
+	imcb_log( tf->ic, "Transferring file %s: connection to streamhost %s:%s failed (%s)", 
+		  tf->ft->file_name, 
+		  bt->sh->host,
+		  bt->sh->port,
+		  error );
+
+	/* Alright, this streamhost failed, let's try the next... */
+	bt->phase = BS_PHASE_CONNECT;
+	shlist = g_slist_find( bt->streamhosts, bt->sh );
+	if( shlist && shlist->next )
+	{
+		bt->sh = shlist->next->data;
+		return jabber_bs_recv_handshake( bt, 0, 0 );
+	}
+
 
 	/* out of stream hosts */
@@ -495,14 +538,13 @@
 	imcb_log( tf->ic, "File %s: established SOCKS5 connection to %s:%s", 
 		  tf->ft->file_name, 
-		  xt_find_attr( bt->shnode, "host" ),
-		  xt_find_attr( bt->shnode, "port" ) );
+		  bt->sh->host,
+		  bt->sh->port );
 
 	tf->ft->data = tf;
-	tf->ft->started = time( NULL );
 	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 );
-	xt_add_attr( reply, "jid", xt_find_attr( bt->shnode, "jid" ) );
+	xt_add_attr( reply, "jid", bt->sh->jid );
 
 	reply = xt_new_node( "query", NULL, reply );
@@ -551,4 +593,7 @@
 		return jabber_bs_abort( bt, "Remote end closed connection" );
 	
+	if( tf->bytesread == 0 )
+		tf->ft->started = time( NULL );
+
 	tf->bytesread += ret;
 
@@ -603,5 +648,9 @@
 		return jabber_bs_abort( bt, "BUG: write() called while watching " );
 	
+	/* TODO: catch broken pipe */
 	ASSERTSOCKOP( ret = send( tf->fd, buffer, len, 0 ), "Sending" );
+
+	if( tf->byteswritten == 0 )
+		tf->ft->started = time( NULL );
 
 	tf->byteswritten += ret;
@@ -665,9 +714,28 @@
 	tf->accepted = TRUE;
 
-	if( bt->phase == BS_PHASE_REPLY )
-	{
-		/* handshake went through, let's start transferring */
-		tf->ft->started = time( NULL );
-		tf->ft->write_request( tf->ft );
+	if( strcmp( jid, tf->ini_jid ) == 0 )
+	{
+		/* we're streamhost and target */
+		if( bt->phase == BS_PHASE_REPLY )
+		{
+			/* handshake went through, let's start transferring */
+			tf->ft->write_request( tf->ft );
+		}
+	} else
+	{
+		/* using a proxy */
+		GSList *shlist;
+		for( shlist = jd->streamhosts ; shlist ; shlist = g_slist_next( shlist ) )
+		{
+			jabber_streamhost_t *sh = shlist->data;
+			if( strcmp( sh->jid, jid ) == 0 )
+			{
+				bt->sh = sh;
+				jabber_bs_recv_handshake( bt, 0, 0 );
+				return XT_HANDLED;
+			}
+		}
+
+		imcb_log( ic, "WARNING: Received SOCKS5 bytestream reply with unknown streamhost %s", jid );
 	}
 
@@ -675,12 +743,79 @@
 }
 
+/* 
+ * Tell the proxy to activate the stream. Looks like this:
+ *
+ * <iq type=set>
+ * 	<query xmlns=bs sid=sid>
+ * 		<activate>tgt_jid</activate>
+ * 	</query>
+ * </iq>
+ */
+void jabber_bs_send_activate( struct bs_transfer *bt )
+{
+	struct xt_node *node;
+
+	node = xt_new_node( "activate", bt->tf->tgt_jid, NULL );
+	node = xt_new_node( "query", NULL, node );
+	xt_add_attr( node, "xmlns", XMLNS_BYTESTREAMS );
+	xt_add_attr( node, "sid", bt->tf->sid );
+	node = jabber_make_packet( "iq", "set", bt->sh->jid, node );
+
+	jabber_cache_add( bt->tf->ic, node, jabber_bs_send_handle_activate );
+
+	jabber_write_packet( bt->tf->ic, node );
+}
+
+/*
+ * The proxy has activated the bytestream.
+ * We can finally start pushing some data out.
+ */
+static xt_status jabber_bs_send_handle_activate( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
+{
+	char *sid;
+	GSList *tflist;
+	struct jabber_transfer *tf;
+	struct xt_node *query;
+	struct jabber_data *jd = ic->proto_data;
+
+	query = xt_find_node( orig->children, "query" );
+	sid = xt_find_attr( query, "sid" );
+
+	for( tflist = jd->filetransfers ; tflist; tflist = g_slist_next(tflist) )
+	{
+		struct jabber_transfer *tft = tflist->data;
+		if( ( strcmp( tft->sid, sid ) == 0 ) )
+		{
+		    	tf = tft;
+			break;
+		}
+	}
+
+	if( !tf )
+	{
+		imcb_log( ic, "WARNING: Received SOCKS5 bytestream activation for unknown stream" );
+		return XT_HANDLED;
+	}
+
+	/* handshake went through, let's start transferring */
+	tf->ft->write_request( tf->ft );
+
+	return XT_HANDLED;
+}
+
+/*
+ * Starts a bytestream.
+ */
 gboolean jabber_bs_send_start( struct jabber_transfer *tf )
 {
-	char host[INET6_ADDRSTRLEN], port[6];
+	char host[INET6_ADDRSTRLEN];
 	struct bs_transfer *bt;
 	sha1_state_t sha;
 	char hash_hex[41];
 	unsigned char hash[20];
-	int i;
+	int i,ret;
+	struct jabber_data *jd = tf->ic->proto_data;
+	jabber_streamhost_t sh;
+	GSList *streamhosts = jd->streamhosts;
 
 	/* SHA1( SID + Initiator JID + Target JID ) is given to the streamhost which it will match against the initiator's value */
@@ -702,20 +837,23 @@
 	tf->ft->canceled = jabber_bs_canceled;
 
-	if ( !jabber_bs_send_listen( bt, &tf->saddr, host, port ) )
+	if ( !jabber_bs_send_listen( bt, &tf->saddr, sh.host = host, sh.port ) )
 		return FALSE;
 
 	bt->tf->watch_in = b_input_add( tf->fd, GAIM_INPUT_READ, jabber_bs_send_handshake, bt );
 	bt->connect_timeout = b_timeout_add( JABBER_BS_LISTEN_TIMEOUT * 1000, jabber_bs_connect_timeout, bt );
-	return jabber_bs_send_request( tf, host, port );
-}
-
-gboolean jabber_bs_send_request( struct jabber_transfer *tf, char *host, char *port )
-{
-	struct xt_node *sh, *query, *iq;
-
-	sh = xt_new_node( "streamhost", NULL, NULL );
-	xt_add_attr( sh, "jid", tf->ini_jid );
-	xt_add_attr( sh, "host", host );
-	xt_add_attr( sh, "port", port );
+
+	sh.jid = tf->ini_jid;
+
+	/* temporarily add listen address to streamhosts, send the request and remove it */
+	streamhosts = g_slist_prepend( streamhosts, &sh );
+	ret = jabber_bs_send_request( tf, streamhosts);
+	streamhosts = g_slist_remove( streamhosts, &sh );
+
+	return ret;
+}
+
+gboolean jabber_bs_send_request( struct jabber_transfer *tf, GSList *streamhosts )
+{
+	struct xt_node *shnode, *query, *iq;
 
 	query = xt_new_node( "query", NULL, NULL );
@@ -723,5 +861,17 @@
 	xt_add_attr( query, "sid", tf->sid );
 	xt_add_attr( query, "mode", "tcp" );
-	xt_add_child( query, sh );
+
+	while( streamhosts ) {
+		jabber_streamhost_t *sh = streamhosts->data;
+		shnode = xt_new_node( "streamhost", NULL, NULL );
+		xt_add_attr( shnode, "jid", sh->jid );
+		xt_add_attr( shnode, "host", sh->host );
+		xt_add_attr( shnode, "port", sh->port );
+
+		xt_add_child( query, shnode );
+
+		streamhosts = g_slist_next( streamhosts );
+	}
+
 
 	iq = jabber_make_packet( "iq", "set", tf->tgt_jid, query );
@@ -739,4 +889,5 @@
 	struct jabber_transfer *tf = bt->tf;
 
+	/* TODO: did the receiver get here somehow??? */
 	imcb_log( tf->ic, "Transferring file %s: SOCKS5 handshake failed: %s", 
 		  tf->ft->file_name, 
@@ -901,5 +1052,4 @@
 			{
 				/* streamhost-used message came already in(possible?), let's start sending */
-				tf->ft->started = time( NULL );
 				tf->ft->write_request( tf->ft );
 			}
Index: protocols/jabber/si.c
===================================================================
--- protocols/jabber/si.c	(revision 8076ec04b1b5699f8266fa0e2e17456974ced554)
+++ protocols/jabber/si.c	(revision dc0ba9c85539533349353713162f94077fb27be3)
@@ -83,4 +83,5 @@
 	struct jabber_transfer *tf;
 	struct jabber_data *jd = ic->proto_data;
+	char *server  = jd->server;
 
 	imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );
@@ -97,6 +98,15 @@
 	jd->filetransfers = g_slist_prepend( jd->filetransfers, tf );
 
+	/* query the buddy's features */
+	jabber_iq_query_features( ic, who );
+
+	/* query proxies from the server */
+	if( !jd->have_streamhosts )
+		jabber_iq_query_server( ic, server, XMLNS_DISCO_ITEMS );
+
+	/* send the request to our buddy */
 	jabber_si_send_request( ic, who, tf );
 
+	/* and start the receive logic */
 	imcb_file_recv_start( ft );
 }
