Index: protocols/jabber/jabber.h
===================================================================
--- protocols/jabber/jabber.h	(revision 44961cb326fde3cb681a79eb28becb74a921a29d)
+++ protocols/jabber/jabber.h	(revision b5cfc2bdad8a68011bf9215c63293299e4e8dc5c)
@@ -154,5 +154,11 @@
 	gpointer streamhandle;
 
+	/* timeout for discover queries */
+	gint disco_timeout;
+	gint disco_timeout_fired;
+
 	struct im_connection *ic;
+
+	struct jabber_buddy *bud;
 
 	int watch_in;
Index: protocols/jabber/si.c
===================================================================
--- protocols/jabber/si.c	(revision 44961cb326fde3cb681a79eb28becb74a921a29d)
+++ protocols/jabber/si.c	(revision b5cfc2bdad8a68011bf9215c63293299e4e8dc5c)
@@ -45,4 +45,7 @@
 	}
 
+	if( tf->disco_timeout )
+		b_event_remove( tf->disco_timeout );
+	
 	g_free( tf->ini_jid );
 	g_free( tf->tgt_jid );
@@ -80,10 +83,88 @@
 }
 
+int jabber_si_check_features( struct jabber_transfer *tf, GSList *features ) {
+	int foundft = FALSE, foundbt = FALSE, foundsi = FALSE;
+
+	while ( features )
+	{
+		if( !strcmp( features->data, XMLNS_FILETRANSFER ) )
+			foundft = TRUE;
+		if( !strcmp( features->data, XMLNS_BYTESTREAMS ) )
+			foundbt = TRUE;
+		if( !strcmp( features->data, XMLNS_SI ) )
+			foundsi = TRUE;
+
+		features = g_slist_next(features);
+	}
+
+	if( !foundft )
+		imcb_file_canceled( tf->ft, "Buddy's client doesn't feature file transfers" );
+	else if( !foundbt )
+		imcb_file_canceled( tf->ft, "Buddy's client doesn't feature byte streams (required)" );
+	else if( !foundsi )
+		imcb_file_canceled( tf->ft, "Buddy's client doesn't feature stream initiation (required)" );
+		
+	return foundft && foundbt && foundsi;
+}
+
+void jabber_si_transfer_start( struct jabber_transfer *tf ) {
+
+	if( !jabber_si_check_features( tf, tf->bud->features ) )
+		return;
+		
+	/* send the request to our buddy */
+	jabber_si_send_request( tf->ic, tf->bud->full_jid, tf );
+
+	/* and start the receive logic */
+	imcb_file_recv_start( tf->ft );
+
+}
+
+gboolean jabber_si_waitfor_disco( gpointer data, gint fd, b_input_condition cond )
+{
+	struct jabber_transfer *tf = data;
+	struct jabber_data *jd = tf->ic->proto_data;
+
+	tf->disco_timeout_fired++;
+
+	if( tf->bud->features && jd->have_streamhosts==1 ) {
+		jabber_si_transfer_start( tf );
+		tf->disco_timeout = 0;
+		return FALSE;
+	}
+
+	/* 8 seconds should be enough for server and buddy to respond */
+	if ( tf->disco_timeout_fired < 16 )
+		return TRUE;
+	
+	if( !tf->bud->features && jd->have_streamhosts!=1 )
+		imcb_file_canceled( tf->ft, "Couldn't get buddy's features or the server's" );
+	else if( !tf->bud->features )
+		imcb_file_canceled( tf->ft, "Couldn't get buddy's features" );
+	else
+		imcb_file_canceled( tf->ft, "Couldn't get server's features" );
+	
+	tf->disco_timeout = 0;
+	return FALSE;
+}
+
 void jabber_si_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who ) 
 {
 	struct jabber_transfer *tf;
 	struct jabber_data *jd = ic->proto_data;
-	char *server  = jd->server;
-
+	struct jabber_buddy *bud;
+	char *server = jd->server, *s;
+
+	if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )
+		bud = jabber_buddy_by_ext_jid( ic, who, 0 );
+	else
+		bud = jabber_buddy_by_jid( ic, who, 0 );
+
+	if( bud == NULL )
+	{
+		imcb_file_canceled( tf->ft, "Couldn't find buddy (BUG?)" );
+		return;
+	}
+		
 	imcb_log( ic, "Trying to send %s(%zd bytes) to %s", ft->file_name, ft->file_size, who );
 
@@ -95,20 +176,25 @@
 	tf->ft->free = jabber_si_free_transfer;
 	tf->ft->finished = jabber_si_finished;
+	tf->bud = bud;
 	ft->write = jabber_bs_send_write;
 
 	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 )
+	/* query buddy's features and server's streaming proxies if neccessary */
+
+	if( !tf->bud->features )
+		jabber_iq_query_features( ic, bud->full_jid );
+
+	if( jd->have_streamhosts!=1 ) {
+		jd->have_streamhosts = 0;
 		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 );
+	}
+
+	/* if we had to do a query, wait for the result. 
+	 * Otherwise fire away. */
+	if( !tf->bud->features || jd->have_streamhosts!=1 )
+		tf->disco_timeout = b_timeout_add( 500, jabber_si_waitfor_disco, tf );
+	else
+		jabber_si_transfer_start( tf );
 }
 
