diff -r 0ca56c346a33 -r ffc583ea14cc libpurple/protocols/jabber/si.c
--- a/libpurple/protocols/jabber/si.c Thu Feb 05 06:25:18 2009 +0000
+++ b/libpurple/protocols/jabber/si.c Fri Feb 06 22:48:37 2009 +0000
@@ -32,6 +32,7 @@
#include "buddy.h"
#include "disco.h"
#include "jabber.h"
+#include "ibb.h"
#include "iq.h"
#include "si.h"
@@ -63,8 +64,15 @@
size_t rxlen;
gsize rxmaxlen;
int local_streamhost_fd;
+
+ JabberIBBSession *ibb_session;
+ guint ibb_timeout_handle;
+ FILE *fp;
} JabberSIXfer;
+/* some forward declarations */
+static void jabber_si_xfer_ibb_send_init(JabberStream *js, PurpleXfer *xfer);
+
static PurpleXfer*
jabber_si_xfer_find(JabberStream *js, const char *sid, const char *from)
{
@@ -178,6 +186,32 @@
return FALSE;
}
+static void
+jabber_si_bytestreams_ibb_timeout_remove(JabberSIXfer *jsx)
+{
+ if (jsx->ibb_timeout_handle) {
+ purple_timeout_remove(jsx->ibb_timeout_handle);
+ jsx->ibb_timeout_handle = 0;
+ }
+}
+
+static gboolean
+jabber_si_bytestreams_ibb_timeout_cb(gpointer data)
+{
+ PurpleXfer *xfer = (PurpleXfer *) data;
+ JabberSIXfer *jsx = xfer->data;
+
+ if (jsx && !jsx->ibb_session) {
+ purple_debug_info("jabber",
+ "jabber_si_bytestreams_ibb_timeout called and IBB session not set "
+ " up yet, cancel transfer");
+ jabber_si_bytestreams_ibb_timeout_remove(jsx);
+ purple_xfer_cancel_local(xfer);
+ }
+
+ return FALSE;
+}
+
static void jabber_si_bytestreams_attempt_connect(PurpleXfer *xfer)
{
JabberSIXfer *jsx = xfer->data;
@@ -200,8 +234,29 @@
jabber_iq_send(iq);
- purple_xfer_cancel_local(xfer);
-
+ /* if IBB is available, revert to that before giving up... */
+ if (jsx->stream_method & STREAM_METHOD_IBB) {
+ /* if we are the initializer, init IBB */
+ purple_debug_info("jabber",
+ "jabber_si_bytestreams_attempt_connect: "
+ "no streamhosts found, trying IBB\n");
+ /* if we are the sender, open an IBB session, but not if we already
+ did it, since we could have received the error from the
+ receiver already... */
+ if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND
+ && !jsx->ibb_session) {
+ jabber_si_xfer_ibb_send_init(jsx->js, xfer);
+ } else {
+ /* setup a timeout to cancel waiting for IBB open */
+ jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
+ jabber_si_bytestreams_ibb_timeout_cb, xfer);
+ }
+ /* if we are the receiver, just wait for IBB open, callback is
+ already set up... */
+ } else {
+ purple_xfer_cancel_local(xfer);
+ }
+
return;
}
@@ -654,8 +709,32 @@
jsx = xfer->data;
if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) {
- if (type && !strcmp(type, "error"))
- purple_xfer_cancel_remote(xfer);
+ purple_debug_info("jabber",
+ "jabber_si_xfer_connect_proxy_cb: type = %s\n",
+ type);
+ if (type && !strcmp(type, "error")) {
+ /* if IBB is available, open IBB session */
+ purple_debug_info("jabber",
+ "jabber_si_xfer_connect_proxy_cb: got error, method: %d\n",
+ jsx->stream_method);
+ if (jsx->stream_method & STREAM_METHOD_IBB) {
+ purple_debug_info("jabber", "IBB is possible, try it\n");
+ /* if we are the sender and haven't already opened an IBB
+ session, do so now (we might already have failed to open
+ the bytestream proxy ourselves when receiving this */
+ if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND
+ && !jsx->ibb_session) {
+ jabber_si_xfer_ibb_send_init(js, xfer);
+ } else {
+ jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
+ jabber_si_bytestreams_ibb_timeout_cb, xfer);
+ }
+ /* if we are receiver, just wait for IBB open stanza, callback
+ is already set up */
+ } else {
+ purple_xfer_cancel_remote(xfer);
+ }
+ }
return;
}
@@ -682,8 +761,22 @@
purple_debug_info("jabber", "Got local SOCKS5 streamhost-used.\n");
purple_xfer_start(xfer, xfer->fd, NULL, -1);
} else {
- purple_debug_info("jabber", "streamhost-used does not match any proxy that was offered to target\n");
- purple_xfer_cancel_local(xfer);
+ /* if available, try to revert to IBB... */
+ if (jsx->stream_method & STREAM_METHOD_IBB) {
+ purple_debug_info("jabber",
+ "jabber_si_connect_proxy_cb: trying to revert to IBB\n");
+ if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
+ jabber_si_xfer_ibb_send_init(jsx->js, xfer);
+ } else {
+ jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
+ jabber_si_bytestreams_ibb_timeout_cb, xfer);
+ }
+ /* if we are the receiver, we are already set up...*/
+ } else {
+ purple_debug_info("jabber",
+ "streamhost-used does not match any proxy that was offered to target\n");
+ purple_xfer_cancel_local(xfer);
+ }
}
g_free(my_jid);
return;
@@ -810,8 +903,26 @@
/* We have no way of transferring, cancel the transfer */
if (streamhost_count == 0) {
jabber_iq_free(iq);
- /* We should probably notify the target, but this really shouldn't ever happen */
- purple_xfer_cancel_local(xfer);
+
+ /* if available, revert to IBB */
+ if (jsx->stream_method & STREAM_METHOD_IBB) {
+ purple_debug_info("jabber",
+ "jabber_si_xfer_bytestreams_listen_cb: trying to revert to IBB\n");
+ if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
+ /* if we are the sender, init the IBB session... */
+ jabber_si_xfer_ibb_send_init(jsx->js, xfer);
+ } else {
+ jsx->ibb_timeout_handle = purple_timeout_add_seconds(30,
+ jabber_si_bytestreams_ibb_timeout_cb, xfer);
+ }
+ /* if we are the receiver, we should just wait... the IBB open
+ handler has already been set up... */
+ } else {
+ /* We should probably notify the target,
+ but this really shouldn't ever happen */
+ purple_xfer_cancel_local(xfer);
+ }
+
return;
}
@@ -841,11 +952,242 @@
}
+static void
+jabber_si_xfer_ibb_error_cb(JabberIBBSession *sess)
+{
+ PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
+ JabberStream *js = jabber_ibb_session_get_js(sess);
+ PurpleConnection *gc = js->gc;
+ PurpleAccount *account = purple_connection_get_account(gc);
+
+ purple_debug_error("jabber", "an error occured during IBB file transfer\n");
+ purple_xfer_error(purple_xfer_get_type(xfer), account,
+ jabber_ibb_session_get_who(sess),
+ _("An error occured on the in-band bytestream transfer\n"));
+ purple_xfer_cancel_remote(xfer);
+}
+
+static void
+jabber_si_xfer_ibb_closed_cb(JabberIBBSession *sess)
+{
+ PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
+ JabberStream *js = jabber_ibb_session_get_js(sess);
+ PurpleConnection *gc = js->gc;
+ PurpleAccount *account = purple_connection_get_account(gc);
+
+ purple_debug_info("jabber", "the remote user closed the transfer\n");
+ if (purple_xfer_get_bytes_remaining(xfer) > 0) {
+ purple_xfer_error(purple_xfer_get_type(xfer), account,
+ jabber_ibb_session_get_who(sess), _("Transfer was closed."));
+ purple_xfer_cancel_remote(xfer);
+ } else {
+ purple_xfer_set_completed(xfer, TRUE);
+ purple_xfer_end(xfer);
+ }
+}
+
+static void
+jabber_si_xfer_ibb_recv_data_cb(JabberIBBSession *sess, gpointer data,
+ gsize size)
+{
+ PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+
+ if (size <= purple_xfer_get_bytes_remaining(xfer)) {
+ purple_debug_info("jabber", "about to write %" G_GSIZE_FORMAT " bytes from IBB stream\n",
+ size);
+ if(!fwrite(data, size, 1, jsx->fp)) {
+ purple_debug_error("jabber", "error writing to file\n");
+ purple_xfer_cancel_remote(xfer);
+ return;
+ }
+ purple_xfer_set_bytes_sent(xfer, purple_xfer_get_bytes_sent(xfer) + size);
+ purple_xfer_update_progress(xfer);
+
+ if (purple_xfer_get_bytes_remaining(xfer) == 0) {
+ purple_xfer_set_completed(xfer, TRUE);
+ purple_xfer_end(xfer);
+ }
+ } else {
+ /* trying to write past size of file transfers negotiated size,
+ reject transfer to protect against malicious behaviour */
+ purple_debug_error("jabber",
+ "IBB file transfer send more data than expected\n");
+ purple_xfer_cancel_remote(xfer);
+ }
+
+}
+
+static gboolean
+jabber_si_xfer_ibb_open_cb(JabberStream *js, xmlnode *packet)
+{
+ const gchar *who = xmlnode_get_attrib(packet, "from");
+ xmlnode *open = xmlnode_get_child(packet, "open");
+ const gchar *sid = xmlnode_get_attrib(open, "sid");
+ PurpleXfer *xfer = jabber_si_xfer_find(js, sid, who);
+ if (xfer) {
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+ JabberIBBSession *sess =
+ jabber_ibb_session_create_from_xmlnode(js, packet, xfer);
+ const char *filename;
+
+ jabber_si_bytestreams_ibb_timeout_remove(jsx);
+
+ if (sess) {
+ /* open the file to write to */
+ filename = purple_xfer_get_local_filename(xfer);
+ jsx->fp = g_fopen(filename, "wb");
+ if (jsx->fp == NULL) {
+ purple_debug_error("jabber", "failed to open file %s for writing: %s\n",
+ filename, g_strerror(errno));
+ purple_xfer_cancel_remote(xfer);
+ return FALSE;
+ }
+
+ /* setup callbacks here...*/
+ jabber_ibb_session_set_data_received_callback(sess,
+ jabber_si_xfer_ibb_recv_data_cb);
+ jabber_ibb_session_set_closed_callback(sess,
+ jabber_si_xfer_ibb_closed_cb);
+ jabber_ibb_session_set_error_callback(sess,
+ jabber_si_xfer_ibb_error_cb);
+
+ jsx->ibb_session = sess;
+
+ /* start the transfer */
+ purple_xfer_start(xfer, 0, NULL, 0);
+ return TRUE;
+ } else {
+ /* failed to create IBB session */
+ purple_debug_error("jabber", "failed to create IBB session\n");
+ purple_xfer_cancel_remote(xfer);
+ return FALSE;
+ }
+ } else {
+ /* we got an IBB for an unknown file transfer, pass along... */
+ purple_debug_info("jabber",
+ "IBB open did not match any SI file transfer\n");
+ return FALSE;
+ }
+}
+
+static void
+jabber_si_xfer_ibb_send_data(JabberIBBSession *sess)
+{
+ PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+ gsize remaining = purple_xfer_get_bytes_remaining(xfer);
+ gsize packet_size = remaining < jabber_ibb_session_get_block_size(sess) ?
+ remaining : jabber_ibb_session_get_block_size(sess);
+ gpointer data = g_malloc(packet_size);
+ int res;
+
+ purple_debug_info("jabber", "IBB: about to read %" G_GSIZE_FORMAT " bytes from file %p\n",
+ packet_size, jsx->fp);
+ res = fread(data, packet_size, 1, jsx->fp);
+
+ if (res == 1) {
+ jabber_ibb_session_send_data(sess, data, packet_size);
+ purple_xfer_set_bytes_sent(xfer,
+ purple_xfer_get_bytes_sent(xfer) + packet_size);
+ purple_xfer_update_progress(xfer);
+ } else {
+ purple_debug_error("jabber",
+ "jabber_si_xfer_ibb_send_data: error reading from file\n");
+ purple_xfer_cancel_local(xfer);
+ }
+}
+
+static void
+jabber_si_xfer_ibb_sent_cb(JabberIBBSession *sess)
+{
+ PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
+ gsize remaining = purple_xfer_get_bytes_remaining(xfer);
+
+ if (remaining == 0) {
+ /* close the session */
+ jabber_ibb_session_close(sess);
+ purple_xfer_set_completed(xfer, TRUE);
+ purple_xfer_end(xfer);
+ } else {
+ /* send more... */
+ jabber_si_xfer_ibb_send_data(sess);
+ }
+}
+
+static void
+jabber_si_xfer_ibb_opened_cb(JabberIBBSession *sess)
+{
+ PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+ JabberStream *js = jabber_ibb_session_get_js(sess);
+ PurpleConnection *gc = js->gc;
+ PurpleAccount *account = purple_connection_get_account(gc);
+
+ if (jabber_ibb_session_get_state(sess) == JABBER_IBB_SESSION_OPENED) {
+ const char *filename = purple_xfer_get_local_filename(xfer);
+ jsx->fp = g_fopen(filename, "rb");
+ if (jsx->fp == NULL) {
+ purple_debug_error("jabber", "Failed to open file %s for reading: %s\n",
+ filename, g_strerror(errno));
+ purple_xfer_error(purple_xfer_get_type(xfer), account,
+ jabber_ibb_session_get_who(sess),
+ _("Failed to open the file"));
+ purple_xfer_cancel_local(xfer);
+ return;
+ }
+
+ purple_xfer_start(xfer, 0, NULL, 0);
+ purple_xfer_set_bytes_sent(xfer, 0);
+ purple_xfer_update_progress(xfer);
+ jabber_si_xfer_ibb_send_data(sess);
+ } else {
+ /* error */
+ purple_xfer_error(purple_xfer_get_type(xfer), account,
+ jabber_ibb_session_get_who(sess),
+ _("Failed to open in-band bytestream"));
+ purple_xfer_end(xfer);
+ }
+}
+
+static void
+jabber_si_xfer_ibb_send_init(JabberStream *js, PurpleXfer *xfer)
+{
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+
+ purple_xfer_ref(xfer);
+
+ jsx->ibb_session = jabber_ibb_session_create(js, jsx->stream_id,
+ purple_xfer_get_remote_user(xfer), xfer);
+
+ if (jsx->ibb_session) {
+ /* should set callbacks here... */
+ jabber_ibb_session_set_opened_callback(jsx->ibb_session,
+ jabber_si_xfer_ibb_opened_cb);
+ jabber_ibb_session_set_data_sent_callback(jsx->ibb_session,
+ jabber_si_xfer_ibb_sent_cb);
+ jabber_ibb_session_set_closed_callback(jsx->ibb_session,
+ jabber_si_xfer_ibb_closed_cb);
+ jabber_ibb_session_set_error_callback(jsx->ibb_session,
+ jabber_si_xfer_ibb_error_cb);
+
+ /* open the IBB session */
+ jabber_ibb_session_open(jsx->ibb_session);
+
+ } else {
+ /* failed to create IBB session */
+ purple_debug_error("jabber",
+ "failed to initiate IBB session for file transfer\n");
+ purple_xfer_cancel_local(xfer);
+ }
+}
+
static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet,
gpointer data)
{
PurpleXfer *xfer = data;
xmlnode *si, *feature, *x, *field, *value;
+ gboolean found_method = FALSE;
if(!(si = xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si"))) {
purple_xfer_cancel_remote(xfer);
@@ -864,20 +1206,33 @@
for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) {
const char *var = xmlnode_get_attrib(field, "var");
-
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+
if(var && !strcmp(var, "stream-method")) {
if((value = xmlnode_get_child(field, "value"))) {
char *val = xmlnode_get_data(value);
if(val && !strcmp(val, "http://jabber.org/protocol/bytestreams")) {
jabber_si_xfer_bytestreams_send_init(xfer);
- g_free(val);
- return;
+ jsx->stream_method |= STREAM_METHOD_BYTESTREAMS;
+ found_method = TRUE;
+ } else if (val && !strcmp(val, XEP_0047_NAMESPACE)) {
+ jsx->stream_method |= STREAM_METHOD_IBB;
+ if (!found_method) {
+ /* we haven't tried to init a bytestream session, yet
+ start IBB right away... */
+ jabber_si_xfer_ibb_send_init(js, xfer);
+ found_method = TRUE;
+ }
}
g_free(val);
}
}
}
- purple_xfer_cancel_remote(xfer);
+
+ if (!found_method) {
+ purple_xfer_cancel_remote(xfer);
+ }
+
}
static void jabber_si_xfer_send_request(PurpleXfer *xfer)
@@ -914,14 +1269,14 @@
field = xmlnode_new_child(x, "field");
xmlnode_set_attrib(field, "var", "stream-method");
xmlnode_set_attrib(field, "type", "list-single");
+ /* maybe we should add an option to always skip bytestreams for people
+ behind troublesome firewalls */
option = xmlnode_new_child(field, "option");
value = xmlnode_new_child(option, "value");
xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
- /*
option = xmlnode_new_child(field, "option");
value = xmlnode_new_child(option, "value");
xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
- */
jabber_iq_set_callback(iq, jabber_si_xfer_send_method_cb, xfer);
@@ -935,38 +1290,66 @@
static void jabber_si_xfer_free(PurpleXfer *xfer)
{
JabberSIXfer *jsx = xfer->data;
- JabberStream *js = jsx->js;
-
- js->file_transfers = g_list_remove(js->file_transfers, xfer);
-
- if (jsx->connect_data != NULL)
- purple_proxy_connect_cancel(jsx->connect_data);
- if (jsx->listen_data != NULL)
- purple_network_listen_cancel(jsx->listen_data);
- if (jsx->iq_id != NULL)
- jabber_iq_remove_callback_by_id(js, jsx->iq_id);
- if (jsx->local_streamhost_fd >= 0)
- close(jsx->local_streamhost_fd);
- if (jsx->connect_timeout > 0)
- purple_timeout_remove(jsx->connect_timeout);
+
+ if (jsx) {
+ JabberStream *js = jsx->js;
+
+ js->file_transfers = g_list_remove(js->file_transfers, xfer);
+
+ if (jsx->connect_data != NULL)
+ purple_proxy_connect_cancel(jsx->connect_data);
+ if (jsx->listen_data != NULL)
+ purple_network_listen_cancel(jsx->listen_data);
+ if (jsx->iq_id != NULL)
+ jabber_iq_remove_callback_by_id(js, jsx->iq_id);
+ if (jsx->local_streamhost_fd >= 0)
+ close(jsx->local_streamhost_fd);
+ if (jsx->connect_timeout > 0)
+ purple_timeout_remove(jsx->connect_timeout);
+ if (jsx->ibb_timeout_handle > 0)
+ purple_timeout_remove(jsx->ibb_timeout_handle);
+
+ if (jsx->streamhosts) {
+ g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL);
+ g_list_free(jsx->streamhosts);
+ }
+
+ if (jsx->ibb_session) {
+ purple_debug_info("jabber",
+ "jabber_si_xfer_free: destroying IBB session\n");
+ jabber_ibb_session_destroy(jsx->ibb_session);
+ }
+
+ if (jsx->fp) {
+ purple_debug_info("jabber",
+ "jabber_si_xfer_free: closing file for IBB transfer\n");
+ fclose(jsx->fp);
+ }
+
+ g_free(jsx->stream_id);
+ g_free(jsx->iq_id);
+ /* XXX: free other stuff */
+ g_free(jsx->rxqueue);
+ g_free(jsx);
+ xfer->data = NULL;
- if (jsx->streamhosts) {
- g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL);
- g_list_free(jsx->streamhosts);
+ purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p\n", jsx);
}
-
- g_free(jsx->stream_id);
- g_free(jsx->iq_id);
- /* XXX: free other stuff */
- g_free(jsx->rxqueue);
- g_free(jsx);
- xfer->data = NULL;
-
- purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p", jsx);
}
-
+
+/*
+ * These four functions should only be called from the PurpleXfer functions
+ * (typically purple_xfer_cancel_(remote|local), purple_xfer_end, or
+ * purple_xfer_request_denied.
+ */
static void jabber_si_xfer_cancel_send(PurpleXfer *xfer)
{
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+
+ /* if there is an IBB session active, send close on that */
+ if (jsx->ibb_session) {
+ jabber_ibb_session_close(jsx->ibb_session);
+ }
jabber_si_xfer_free(xfer);
purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_send\n");
}
@@ -981,6 +1364,11 @@
static void jabber_si_xfer_cancel_recv(PurpleXfer *xfer)
{
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+ /* if there is an IBB session active, send close */
+ if (jsx->ibb_session) {
+ jabber_ibb_session_close(jsx->ibb_session);
+ }
jabber_si_xfer_free(xfer);
purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_recv\n");
}
@@ -995,9 +1383,16 @@
static void jabber_si_xfer_send_disco_cb(JabberStream *js, const char *who,
JabberCapabilities capabilities, gpointer data)
{
- PurpleXfer *xfer = data;
+ PurpleXfer *xfer = (PurpleXfer *) data;
+ JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
+
+ if (capabilities & JABBER_CAP_IBB) {
+ purple_debug_info("jabber",
+ "jabber_si_xfer_send_disco_cb: remote JID supports IBB\n");
+ jsx->stream_method |= STREAM_METHOD_IBB;
+ }
- if(capabilities & JABBER_CAP_SI_FILE_XFER) {
+ if (capabilities & JABBER_CAP_SI_FILE_XFER) {
jabber_si_xfer_send_request(xfer);
} else {
char *msg = g_strdup_printf(_("Unable to send file to %s, user does not support file transfers"), who);
@@ -1124,18 +1519,22 @@
x = xmlnode_new_child(feature, "x");
xmlnode_set_namespace(x, "jabber:x:data");
xmlnode_set_attrib(x, "type", "submit");
-
field = xmlnode_new_child(x, "field");
xmlnode_set_attrib(field, "var", "stream-method");
-
- value = xmlnode_new_child(field, "value");
- if(jsx->stream_method & STREAM_METHOD_BYTESTREAMS)
+
+ /* we should maybe "remember" if bytestreams has failed before (in the
+ same session) with this JID, and only present IBB as an option to
+ avoid unnessesary timeout */
+ /* maybe we should have an account option to always just try IBB
+ for people who know their firewalls are very restrictive */
+ if (jsx->stream_method & STREAM_METHOD_BYTESTREAMS) {
+ value = xmlnode_new_child(field, "value");
xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
- /*
- else if(jsx->stream_method & STREAM_METHOD_IBB)
- xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
- */
-
+ } else if(jsx->stream_method & STREAM_METHOD_IBB) {
+ value = xmlnode_new_child(field, "value");
+ xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
+ }
+
jabber_iq_send(iq);
}
}
@@ -1155,6 +1554,9 @@
xfer->data = jsx = g_new0(JabberSIXfer, 1);
jsx->js = js;
jsx->local_streamhost_fd = -1;
+
+ jsx->ibb_session = NULL;
+ jsx->fp = NULL;
purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init);
purple_xfer_set_cancel_send_fnc(xfer, jabber_si_xfer_cancel_send);
@@ -1223,6 +1625,8 @@
jsx = g_new0(JabberSIXfer, 1);
jsx->local_streamhost_fd = -1;
+
+ jsx->ibb_session = NULL;
for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) {
const char *var = xmlnode_get_attrib(field, "var");
@@ -1234,10 +1638,8 @@
if((val = xmlnode_get_data(value))) {
if(!strcmp(val, "http://jabber.org/protocol/bytestreams")) {
jsx->stream_method |= STREAM_METHOD_BYTESTREAMS;
- /*
} else if(!strcmp(val, "http://jabber.org/protocol/ibb")) {
jsx->stream_method |= STREAM_METHOD_IBB;
- */
}
g_free(val);
}
@@ -1275,4 +1677,15 @@
}
}
+void
+jabber_si_init(void)
+{
+ jabber_ibb_register_open_handler(jabber_si_xfer_ibb_open_cb);
+}
+void
+jabber_si_uninit(void)
+{
+ jabber_ibb_unregister_open_handler(jabber_si_xfer_ibb_open_cb);
+}
+