libpurple/protocols/jabber/si.c

branch
cpw.malu.xmpp.ibb_ft
changeset 24372
830701cec96f
parent 24038
5500af38bb9f
child 25986
4fe846f4a8fb
equal deleted inserted replaced
24265:328bde72a844 24372:830701cec96f
33 #include "buddy.h" 33 #include "buddy.h"
34 #include "disco.h" 34 #include "disco.h"
35 #include "jabber.h" 35 #include "jabber.h"
36 #include "iq.h" 36 #include "iq.h"
37 #include "si.h" 37 #include "si.h"
38 #include "ibb.h"
38 39
39 #define STREAMHOST_CONNECT_TIMEOUT 15 40 #define STREAMHOST_CONNECT_TIMEOUT 15
40 41
41 typedef struct _JabberSIXfer { 42 typedef struct _JabberSIXfer {
42 JabberStream *js; 43 JabberStream *js;
62 63
63 char *rxqueue; 64 char *rxqueue;
64 size_t rxlen; 65 size_t rxlen;
65 gsize rxmaxlen; 66 gsize rxmaxlen;
66 int local_streamhost_fd; 67 int local_streamhost_fd;
68
69 JabberIBBSession *ibb_session;
70 FILE *fp;
67 } JabberSIXfer; 71 } JabberSIXfer;
72
73 /* some forward declarations */
74 static void jabber_si_xfer_ibb_send_init(JabberStream *js, PurpleXfer *xfer);
68 75
69 static PurpleXfer* 76 static PurpleXfer*
70 jabber_si_xfer_find(JabberStream *js, const char *sid, const char *from) 77 jabber_si_xfer_find(JabberStream *js, const char *sid, const char *from)
71 { 78 {
72 GList *xfers; 79 GList *xfers;
202 inf = xmlnode_new_child(error, "item-not-found"); 209 inf = xmlnode_new_child(error, "item-not-found");
203 xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas"); 210 xmlnode_set_namespace(inf, "urn:ietf:params:xml:ns:xmpp-stanzas");
204 211
205 jabber_iq_send(iq); 212 jabber_iq_send(iq);
206 213
207 purple_xfer_cancel_local(xfer); 214 /* if IBB is available, revert to that before giving up... */
208 215 if (jsx->stream_method & STREAM_METHOD_IBB) {
216 /* if we are the initializer, init IBB */
217 purple_debug_info("jabber",
218 "jabber_si_bytestreams_attempt_connect: "
219 "no streamhosts found, trying IBB\n");
220 /* if we are the sender, open an IBB session. But not if we already
221 done it, since we could have received the error <iq/> from the
222 receiver already... */
223 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND
224 && !jsx->ibb_session) {
225 jabber_si_xfer_ibb_send_init(jsx->js, xfer);
226 }
227 /* if we are the receiver, just wait for IBB open, callback is
228 already set up... */
229 } else {
230 purple_xfer_cancel_local(xfer);
231 }
232
209 return; 233 return;
210 } 234 }
211 235
212 streamhost = jsx->streamhosts->data; 236 streamhost = jsx->streamhosts->data;
213 237
664 return; 688 return;
665 689
666 jsx = xfer->data; 690 jsx = xfer->data;
667 691
668 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { 692 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) {
669 if (type && !strcmp(type, "error")) 693 purple_debug_info("jabber",
670 purple_xfer_cancel_remote(xfer); 694 "jabber_si_xfer_connect_proxy_cb: type = %s\n",
695 type);
696 if (type && !strcmp(type, "error")) {
697 /* if IBB is available, open IBB session */
698 purple_debug_info("jabber",
699 "jabber_si_xfer_connect_proxy_cb: got error, method: %d\n",
700 jsx->stream_method);
701 if (jsx->stream_method & STREAM_METHOD_IBB) {
702 purple_debug_info("jabber", "IBB is possible, try it\n");
703 /* if we are the sender and haven't already opened an IBB
704 session, do so now (we might already have failed to open
705 the bytestream proxy ourselves when receiving this <iq/> */
706 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND
707 && !jsx->ibb_session) {
708 jabber_si_xfer_ibb_send_init(js, xfer);
709 }
710 /* if we are receiver, just wait for IBB open stanza, callback
711 is already set up */
712 } else {
713 purple_xfer_cancel_remote(xfer);
714 }
715 }
671 return; 716 return;
672 } 717 }
673 718
674 if(!(from = xmlnode_get_attrib(packet, "from"))) 719 if(!(from = xmlnode_get_attrib(packet, "from")))
675 return; 720 return;
692 jsx->js->user->domain, jsx->js->user->resource); 737 jsx->js->user->domain, jsx->js->user->resource);
693 if (!strcmp(jid, my_jid)) { 738 if (!strcmp(jid, my_jid)) {
694 purple_debug_info("jabber", "Got local SOCKS5 streamhost-used.\n"); 739 purple_debug_info("jabber", "Got local SOCKS5 streamhost-used.\n");
695 purple_xfer_start(xfer, xfer->fd, NULL, -1); 740 purple_xfer_start(xfer, xfer->fd, NULL, -1);
696 } else { 741 } else {
697 purple_debug_info("jabber", "streamhost-used does not match any proxy that was offered to target\n"); 742 /* if available, try to revert to IBB... */
698 purple_xfer_cancel_local(xfer); 743 if (jsx->stream_method & STREAM_METHOD_IBB) {
744 purple_debug_info("jabber",
745 "jabber_si_connect_proxy_cb: trying to revert to IBB\n");
746 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
747 jabber_si_xfer_ibb_send_init(jsx->js, xfer);
748 }
749 /* if we are the receiver, we are already set up...*/
750 } else {
751 purple_debug_info("jabber",
752 "streamhost-used does not match any proxy that was offered to target\n");
753 purple_xfer_cancel_local(xfer);
754 }
699 } 755 }
700 g_free(my_jid); 756 g_free(my_jid);
701 return; 757 return;
702 } 758 }
703 759
820 } 876 }
821 877
822 /* We have no way of transferring, cancel the transfer */ 878 /* We have no way of transferring, cancel the transfer */
823 if (streamhost_count == 0) { 879 if (streamhost_count == 0) {
824 jabber_iq_free(iq); 880 jabber_iq_free(iq);
825 /* We should probably notify the target, but this really shouldn't ever happen */ 881
826 purple_xfer_cancel_local(xfer); 882 /* if available, revert to IBB */
883 if (jsx->stream_method & STREAM_METHOD_IBB) {
884 purple_debug_info("jabber",
885 "jabber_si_xfer_bytestreams_listen_cb: trying to revert to IBB\n");
886 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
887 /* if we are the sender, init the IBB session... */
888 jabber_si_xfer_ibb_send_init(jsx->js, xfer);
889 }
890 /* if we are the receiver, we should just wait... the IBB open
891 handler has already been set up... */
892 } else {
893 /* We should probably notify the target,
894 but this really shouldn't ever happen */
895 purple_xfer_cancel_local(xfer);
896 }
897
827 return; 898 return;
828 } 899 }
829 900
830 jabber_iq_set_callback(iq, jabber_si_connect_proxy_cb, xfer); 901 jabber_iq_set_callback(iq, jabber_si_connect_proxy_cb, xfer);
831 902
851 jabber_si_xfer_bytestreams_listen_cb(-1, xfer); 922 jabber_si_xfer_bytestreams_listen_cb(-1, xfer);
852 } 923 }
853 924
854 } 925 }
855 926
927 /* forward declare some functions here... */
928 static void jabber_si_xfer_cancel_recv(PurpleXfer *xfer);
929 static void jabber_si_xfer_cancel_send(PurpleXfer *xfer);
930 static void jabber_si_xfer_free(PurpleXfer *xfer);
931
932 static void
933 jabber_si_xfer_ibb_error_cb(JabberIBBSession *sess)
934 {
935 PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
936 JabberStream *js = jabber_ibb_session_get_js(sess);
937 PurpleConnection *gc = js->gc;
938 PurpleAccount *account = purple_connection_get_account(gc);
939
940 purple_debug_error("jabber", "an error occured during IBB file transfer\n");
941 purple_xfer_error(purple_xfer_get_type(xfer), account,
942 jabber_ibb_session_get_who(sess),
943 _("An error occured on the in-band bytestream transfer\n"));
944 purple_xfer_end(xfer);
945 }
946
947 static void
948 jabber_si_xfer_ibb_closed_cb(JabberIBBSession *sess)
949 {
950 PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
951 JabberStream *js = jabber_ibb_session_get_js(sess);
952 PurpleConnection *gc = js->gc;
953 PurpleAccount *account = purple_connection_get_account(gc);
954
955 purple_debug_info("jabber", "the remote user closed the transfer\n");
956 if (purple_xfer_get_bytes_remaining(xfer) > 0) {
957 purple_xfer_error(purple_xfer_get_type(xfer), account,
958 jabber_ibb_session_get_who(sess), _("Transfer was closed."));
959 purple_xfer_end(xfer);
960 } else {
961 purple_xfer_set_completed(xfer, TRUE);
962 }
963 }
964
965 static void
966 jabber_si_xfer_ibb_recv_data_cb(JabberIBBSession *sess, gpointer data,
967 gsize size)
968 {
969 PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
970 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
971
972 if (size <= purple_xfer_get_bytes_remaining(xfer)) {
973 fwrite(data, size, 1, jsx->fp);
974 purple_xfer_set_bytes_sent(xfer, purple_xfer_get_bytes_sent(xfer) + size);
975 purple_xfer_update_progress(xfer);
976
977 if (purple_xfer_get_bytes_remaining(xfer) == 0) {
978 purple_xfer_set_completed(xfer, TRUE);
979 }
980 } else {
981 /* trying to write past size of file transfers negotiated size,
982 reject transfer to protect against malicious behaviour */
983 purple_debug_error("jabber",
984 "IBB file transfer, trying to write past end of file\n");
985 jabber_si_xfer_cancel_recv(xfer);
986 }
987
988 }
989
990 static gboolean
991 jabber_si_xfer_ibb_open_cb(JabberStream *js, xmlnode *packet)
992 {
993 const gchar *who = xmlnode_get_attrib(packet, "from");
994 xmlnode *open = xmlnode_get_child(packet, "open");
995 const gchar *sid = xmlnode_get_attrib(open, "sid");
996 PurpleXfer *xfer = jabber_si_xfer_find(js, sid, who);
997 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
998 JabberIBBSession *sess =
999 jabber_ibb_session_create_from_xmlnode(js, packet, xfer);
1000
1001 if (sess) {
1002 /* setup callbacks here...*/
1003 jabber_ibb_session_set_data_received_callback(sess,
1004 jabber_si_xfer_ibb_recv_data_cb);
1005 jabber_ibb_session_set_closed_callback(sess,
1006 jabber_si_xfer_ibb_closed_cb);
1007 jabber_ibb_session_set_error_callback(sess,
1008 jabber_si_xfer_ibb_error_cb);
1009
1010 /* open the file to write to */
1011 jsx->fp = g_fopen(purple_xfer_get_local_filename(xfer), "w");
1012
1013 jsx->ibb_session = sess;
1014
1015 /* start the transfer */
1016 purple_xfer_start(xfer, 0, NULL, 0);
1017 return TRUE;
1018 } else {
1019 /* failed to create IBB session */
1020 purple_debug_error("jabber", "failed to create IBB session\n");
1021 jabber_si_xfer_cancel_recv(xfer);
1022 return FALSE;
1023 }
1024 }
1025
1026 static void
1027 jabber_si_xfer_ibb_send_data(JabberIBBSession *sess)
1028 {
1029 PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
1030 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1031 gsize remaining = purple_xfer_get_bytes_remaining(xfer);
1032 gsize packet_size = remaining < jabber_ibb_session_get_block_size(sess) ?
1033 remaining : jabber_ibb_session_get_block_size(sess);
1034 gpointer data = g_malloc(packet_size);
1035 int res;
1036
1037 purple_debug_info("jabber", "IBB: about to read %d bytes from file %lx\n",
1038 packet_size, jsx->fp);
1039 res = fread(data, packet_size, 1, jsx->fp);
1040
1041 if (res == 1) {
1042 jabber_ibb_session_send_data(sess, data, packet_size);
1043 purple_xfer_set_bytes_sent(xfer,
1044 purple_xfer_get_bytes_sent(xfer) + packet_size);
1045 purple_xfer_update_progress(xfer);
1046 } else {
1047 purple_debug_error("jabber",
1048 "jabber_si_xfer_ibb_opened_cb: error reading from file\n");
1049 jabber_si_xfer_cancel_send(xfer);
1050 }
1051 }
1052
1053 static void
1054 jabber_si_xfer_ibb_sent_cb(JabberIBBSession *sess)
1055 {
1056 PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
1057 gsize remaining = purple_xfer_get_bytes_remaining(xfer);
1058
1059 if (remaining == 0) {
1060 /* close the session */
1061 jabber_ibb_session_close(sess);
1062 purple_xfer_set_completed(xfer, TRUE);
1063 } else {
1064 /* send more... */
1065 jabber_si_xfer_ibb_send_data(sess);
1066 }
1067 }
1068
1069 static void
1070 jabber_si_xfer_ibb_opened_cb(JabberIBBSession *sess)
1071 {
1072 PurpleXfer *xfer = (PurpleXfer *) jabber_ibb_session_get_user_data(sess);
1073 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1074
1075 purple_xfer_start(xfer, 0, NULL, 0);
1076 purple_xfer_set_bytes_sent(xfer, 0);
1077 purple_xfer_update_progress(xfer);
1078 jsx->fp = g_fopen(purple_xfer_get_local_filename(xfer), "r");
1079 jabber_si_xfer_ibb_send_data(sess);
1080 }
1081
1082 static void
1083 jabber_si_xfer_ibb_send_init(JabberStream *js, PurpleXfer *xfer)
1084 {
1085 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1086
1087 purple_xfer_ref(xfer);
1088
1089 jsx->ibb_session = jabber_ibb_session_create(js, jsx->stream_id,
1090 purple_xfer_get_remote_user(xfer), xfer);
1091
1092 if (jsx->ibb_session) {
1093 /* should set callbacks here... */
1094 jabber_ibb_session_set_opened_callback(jsx->ibb_session,
1095 jabber_si_xfer_ibb_opened_cb);
1096 jabber_ibb_session_set_data_sent_callback(jsx->ibb_session,
1097 jabber_si_xfer_ibb_sent_cb);
1098 jabber_ibb_session_set_closed_callback(jsx->ibb_session,
1099 jabber_si_xfer_ibb_closed_cb);
1100 jabber_ibb_session_set_error_callback(jsx->ibb_session,
1101 jabber_si_xfer_ibb_error_cb);
1102
1103 /* open the IBB session */
1104 jabber_ibb_session_open(jsx->ibb_session);
1105
1106 } else {
1107 /* failed to create IBB session */
1108 purple_xfer_unref(xfer);
1109 purple_debug_error("jabber",
1110 "failed to initiate IBB session for file transfer\n");
1111 jabber_si_xfer_cancel_send(xfer);
1112 }
1113 }
1114
856 static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet, 1115 static void jabber_si_xfer_send_method_cb(JabberStream *js, xmlnode *packet,
857 gpointer data) 1116 gpointer data)
858 { 1117 {
859 PurpleXfer *xfer = data; 1118 PurpleXfer *xfer = data;
860 xmlnode *si, *feature, *x, *field, *value; 1119 xmlnode *si, *feature, *x, *field, *value;
1120 gboolean found_method = FALSE;
861 1121
862 if(!(si = xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si"))) { 1122 if(!(si = xmlnode_get_child_with_namespace(packet, "si", "http://jabber.org/protocol/si"))) {
863 purple_xfer_cancel_remote(xfer); 1123 purple_xfer_cancel_remote(xfer);
864 return; 1124 return;
865 } 1125 }
874 return; 1134 return;
875 } 1135 }
876 1136
877 for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) { 1137 for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) {
878 const char *var = xmlnode_get_attrib(field, "var"); 1138 const char *var = xmlnode_get_attrib(field, "var");
879 1139 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1140
880 if(var && !strcmp(var, "stream-method")) { 1141 if(var && !strcmp(var, "stream-method")) {
881 if((value = xmlnode_get_child(field, "value"))) { 1142 if((value = xmlnode_get_child(field, "value"))) {
882 char *val = xmlnode_get_data(value); 1143 char *val = xmlnode_get_data(value);
883 if(val && !strcmp(val, "http://jabber.org/protocol/bytestreams")) { 1144 if(val && !strcmp(val, "http://jabber.org/protocol/bytestreams")) {
884 jabber_si_xfer_bytestreams_send_init(xfer); 1145 jabber_si_xfer_bytestreams_send_init(xfer);
885 g_free(val); 1146 jsx->stream_method |= STREAM_METHOD_BYTESTREAMS;
886 return; 1147 found_method = TRUE;
1148 } else if (val && !strcmp(val, XEP_0047_NAMESPACE)) {
1149 jsx->stream_method |= STREAM_METHOD_IBB;
1150 if (!found_method) {
1151 /* we haven't tried to init a bytestream session, yet
1152 start IBB right away... */
1153 jabber_si_xfer_ibb_send_init(js, xfer);
1154 found_method = TRUE;
1155 }
887 } 1156 }
888 g_free(val); 1157 g_free(val);
889 } 1158 }
890 } 1159 }
891 } 1160 }
892 purple_xfer_cancel_remote(xfer); 1161
1162 if (!found_method) {
1163 purple_xfer_cancel_remote(xfer);
1164 }
1165
893 } 1166 }
894 1167
895 static void jabber_si_xfer_send_request(PurpleXfer *xfer) 1168 static void jabber_si_xfer_send_request(PurpleXfer *xfer)
896 { 1169 {
897 JabberSIXfer *jsx = xfer->data; 1170 JabberSIXfer *jsx = xfer->data;
927 xmlnode_set_attrib(field, "var", "stream-method"); 1200 xmlnode_set_attrib(field, "var", "stream-method");
928 xmlnode_set_attrib(field, "type", "list-single"); 1201 xmlnode_set_attrib(field, "type", "list-single");
929 option = xmlnode_new_child(field, "option"); 1202 option = xmlnode_new_child(field, "option");
930 value = xmlnode_new_child(option, "value"); 1203 value = xmlnode_new_child(option, "value");
931 xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1); 1204 xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
932 /*
933 option = xmlnode_new_child(field, "option"); 1205 option = xmlnode_new_child(field, "option");
934 value = xmlnode_new_child(option, "value"); 1206 value = xmlnode_new_child(option, "value");
935 xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1); 1207 xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
936 */
937 1208
938 jabber_iq_set_callback(iq, jabber_si_xfer_send_method_cb, xfer); 1209 jabber_iq_set_callback(iq, jabber_si_xfer_send_method_cb, xfer);
939 1210
940 /* Store the IQ id so that we can cancel the callback */ 1211 /* Store the IQ id so that we can cancel the callback */
941 g_free(jsx->iq_id); 1212 g_free(jsx->iq_id);
965 if (jsx->streamhosts) { 1236 if (jsx->streamhosts) {
966 g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL); 1237 g_list_foreach(jsx->streamhosts, jabber_si_free_streamhost, NULL);
967 g_list_free(jsx->streamhosts); 1238 g_list_free(jsx->streamhosts);
968 } 1239 }
969 1240
1241 if (jsx->ibb_session) {
1242 purple_debug_info("jabber",
1243 "jabber_si_xfer_free: destroying IBB session\n");
1244 jabber_ibb_session_destroy(jsx->ibb_session);
1245 }
1246
1247 if (jsx->fp) {
1248 fclose(jsx->fp);
1249 }
1250
970 g_free(jsx->stream_id); 1251 g_free(jsx->stream_id);
971 g_free(jsx->iq_id); 1252 g_free(jsx->iq_id);
972 /* XXX: free other stuff */ 1253 /* XXX: free other stuff */
973 g_free(jsx->rxqueue); 1254 g_free(jsx->rxqueue);
974 g_free(jsx); 1255 g_free(jsx);
977 purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p", jsx); 1258 purple_debug_info("jabber", "jabber_si_xfer_free(): freeing jsx %p", jsx);
978 } 1259 }
979 1260
980 static void jabber_si_xfer_cancel_send(PurpleXfer *xfer) 1261 static void jabber_si_xfer_cancel_send(PurpleXfer *xfer)
981 { 1262 {
1263 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1264
1265 /* if there is an IBB session active, send close on that */
1266 if (jsx->ibb_session) {
1267 jabber_ibb_session_close(jsx->ibb_session);
1268 }
982 jabber_si_xfer_free(xfer); 1269 jabber_si_xfer_free(xfer);
983 purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_send\n"); 1270 purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_send\n");
984 } 1271 }
985 1272
986 1273
991 } 1278 }
992 1279
993 1280
994 static void jabber_si_xfer_cancel_recv(PurpleXfer *xfer) 1281 static void jabber_si_xfer_cancel_recv(PurpleXfer *xfer)
995 { 1282 {
1283 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1284 /* if there is an IBB session active, send close */
1285 if (jsx->ibb_session) {
1286 jabber_ibb_session_close(jsx->ibb_session);
1287 }
996 jabber_si_xfer_free(xfer); 1288 jabber_si_xfer_free(xfer);
997 purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_recv\n"); 1289 purple_debug(PURPLE_DEBUG_INFO, "jabber", "in jabber_si_xfer_cancel_recv\n");
998 } 1290 }
999 1291
1000 1292
1005 1297
1006 1298
1007 static void jabber_si_xfer_send_disco_cb(JabberStream *js, const char *who, 1299 static void jabber_si_xfer_send_disco_cb(JabberStream *js, const char *who,
1008 JabberCapabilities capabilities, gpointer data) 1300 JabberCapabilities capabilities, gpointer data)
1009 { 1301 {
1010 PurpleXfer *xfer = data; 1302 PurpleXfer *xfer = (PurpleXfer *) data;
1011 1303 JabberSIXfer *jsx = (JabberSIXfer *) xfer->data;
1012 if(capabilities & JABBER_CAP_SI_FILE_XFER) { 1304
1305 if (capabilities & JABBER_CAP_IBB) {
1306 purple_debug_info("jabber",
1307 "jabber_si_xfer_send_disco_cb: remote JID supports IBB\n");
1308 jsx->stream_method |= STREAM_METHOD_IBB;
1309 }
1310
1311 if (capabilities & JABBER_CAP_SI_FILE_XFER) {
1013 jabber_si_xfer_send_request(xfer); 1312 jabber_si_xfer_send_request(xfer);
1014 } else { 1313 } else {
1015 char *msg = g_strdup_printf(_("Unable to send file to %s, user does not support file transfers"), who); 1314 char *msg = g_strdup_printf(_("Unable to send file to %s, user does not support file transfers"), who);
1016 purple_notify_error(js->gc, _("File Send Failed"), 1315 purple_notify_error(js->gc, _("File Send Failed"),
1017 _("File Send Failed"), msg); 1316 _("File Send Failed"), msg);
1134 xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg"); 1433 xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");
1135 1434
1136 x = xmlnode_new_child(feature, "x"); 1435 x = xmlnode_new_child(feature, "x");
1137 xmlnode_set_namespace(x, "jabber:x:data"); 1436 xmlnode_set_namespace(x, "jabber:x:data");
1138 xmlnode_set_attrib(x, "type", "submit"); 1437 xmlnode_set_attrib(x, "type", "submit");
1139
1140 field = xmlnode_new_child(x, "field"); 1438 field = xmlnode_new_child(x, "field");
1141 xmlnode_set_attrib(field, "var", "stream-method"); 1439 xmlnode_set_attrib(field, "var", "stream-method");
1142 1440
1143 value = xmlnode_new_child(field, "value"); 1441 /* we should maybe "remember" if bytestreams has failed before (in the
1144 if(jsx->stream_method & STREAM_METHOD_BYTESTREAMS) 1442 same session) with this JID, and only present IBB as an option to
1443 avoid unnessesary timeout */
1444 if (jsx->stream_method & STREAM_METHOD_BYTESTREAMS) {
1445 value = xmlnode_new_child(field, "value");
1145 xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1); 1446 xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
1146 /* 1447 } else if(jsx->stream_method & STREAM_METHOD_IBB) {
1147 else if(jsx->stream_method & STREAM_METHOD_IBB) 1448 value = xmlnode_new_child(field, "value");
1148 xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1); 1449 xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
1149 */ 1450 }
1150 1451
1151 jabber_iq_send(iq); 1452 jabber_iq_send(iq);
1152 } 1453 }
1153 } 1454 }
1154 1455
1155 PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who) 1456 PurpleXfer *jabber_si_new_xfer(PurpleConnection *gc, const char *who)
1165 if (xfer) 1466 if (xfer)
1166 { 1467 {
1167 xfer->data = jsx = g_new0(JabberSIXfer, 1); 1468 xfer->data = jsx = g_new0(JabberSIXfer, 1);
1168 jsx->js = js; 1469 jsx->js = js;
1169 jsx->local_streamhost_fd = -1; 1470 jsx->local_streamhost_fd = -1;
1471
1472 jsx->ibb_session = NULL;
1473 jsx->fp = NULL;
1170 1474
1171 purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init); 1475 purple_xfer_set_init_fnc(xfer, jabber_si_xfer_init);
1172 purple_xfer_set_cancel_send_fnc(xfer, jabber_si_xfer_cancel_send); 1476 purple_xfer_set_cancel_send_fnc(xfer, jabber_si_xfer_cancel_send);
1173 purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end); 1477 purple_xfer_set_end_fnc(xfer, jabber_si_xfer_end);
1174 1478
1236 if((xfer = jabber_si_xfer_find(js, stream_id, from))) 1540 if((xfer = jabber_si_xfer_find(js, stream_id, from)))
1237 return; 1541 return;
1238 1542
1239 jsx = g_new0(JabberSIXfer, 1); 1543 jsx = g_new0(JabberSIXfer, 1);
1240 jsx->local_streamhost_fd = -1; 1544 jsx->local_streamhost_fd = -1;
1545
1546 jsx->ibb_session = NULL;
1241 1547
1242 for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) { 1548 for(field = xmlnode_get_child(x, "field"); field; field = xmlnode_get_next_twin(field)) {
1243 const char *var = xmlnode_get_attrib(field, "var"); 1549 const char *var = xmlnode_get_attrib(field, "var");
1244 if(var && !strcmp(var, "stream-method")) { 1550 if(var && !strcmp(var, "stream-method")) {
1245 for(option = xmlnode_get_child(field, "option"); option; 1551 for(option = xmlnode_get_child(field, "option"); option;
1247 if((value = xmlnode_get_child(option, "value"))) { 1553 if((value = xmlnode_get_child(option, "value"))) {
1248 char *val; 1554 char *val;
1249 if((val = xmlnode_get_data(value))) { 1555 if((val = xmlnode_get_data(value))) {
1250 if(!strcmp(val, "http://jabber.org/protocol/bytestreams")) { 1556 if(!strcmp(val, "http://jabber.org/protocol/bytestreams")) {
1251 jsx->stream_method |= STREAM_METHOD_BYTESTREAMS; 1557 jsx->stream_method |= STREAM_METHOD_BYTESTREAMS;
1252 /*
1253 } else if(!strcmp(val, "http://jabber.org/protocol/ibb")) { 1558 } else if(!strcmp(val, "http://jabber.org/protocol/ibb")) {
1254 jsx->stream_method |= STREAM_METHOD_IBB; 1559 jsx->stream_method |= STREAM_METHOD_IBB;
1255 */
1256 } 1560 }
1257 g_free(val); 1561 g_free(val);
1258 } 1562 }
1259 } 1563 }
1260 } 1564 }
1288 1592
1289 purple_xfer_request(xfer); 1593 purple_xfer_request(xfer);
1290 } 1594 }
1291 } 1595 }
1292 1596
1293 1597 void
1598 jabber_si_init(void)
1599 {
1600 jabber_ibb_register_open_handler(jabber_si_xfer_ibb_open_cb);
1601 }
1602
1603 void
1604 jabber_si_uninit(void)
1605 {
1606 jabber_ibb_unregister_open_handler(jabber_si_xfer_ibb_open_cb);
1607 }
1608

mercurial