Mercurial > pidgin.yaz
comparison libpurple/protocols/bonjour/bonjour_ft.c @ 21522:dc703f13449a
Fix a couple bugs in the Bonjour XEP-0065 implementation, mainly related to error handling, but also send a <streamhost-used /> result. Also fix a XEP-0096 bug where the SI profile wasn't being specified. These bring ft with gajim closer to working, but we aren't there yet.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 15 Nov 2007 14:53:53 +0000 |
parents | 3d70e3ec8a47 |
children | 5b9da9db7e81 |
comparison
equal
deleted
inserted
replaced
21521:287ee978db2e | 21522:dc703f13449a |
---|---|
43 | 43 |
44 /* Look for specific xfer handle */ | 44 /* Look for specific xfer handle */ |
45 static unsigned int next_id = 0; | 45 static unsigned int next_id = 0; |
46 | 46 |
47 static void | 47 static void |
48 xep_ft_si_reject(PurpleXfer *xfer, char *to) | 48 xep_ft_si_reject(BonjourData *bd, const char *id, const char *to, const char *error_code, const char *error_type) |
49 { | 49 { |
50 xmlnode *error_node = NULL; | 50 xmlnode *error_node = NULL; |
51 xmlnode *tmp_node = NULL; | 51 xmlnode *tmp_node = NULL; |
52 XepIq *iq = NULL; | 52 XepIq *iq = NULL; |
53 XepXfer *xf = NULL; | 53 |
54 | 54 g_return_if_fail(error_code != NULL); |
55 if(!to || !xfer) | 55 g_return_if_fail(error_type != NULL); |
56 return; | 56 |
57 xf = xfer->data; | 57 if(!to || !id) |
58 if(!xf) | |
59 return; | 58 return; |
60 | 59 |
61 purple_debug_info("bonjour", "xep file transfer stream initialization error.\n"); | 60 purple_debug_info("bonjour", "xep file transfer stream initialization error.\n"); |
62 iq = xep_iq_new(xf->data, XEP_IQ_ERROR, to, xf->sid); | 61 iq = xep_iq_new(bd, XEP_IQ_ERROR, to, purple_account_get_username(bd->jabber_data->account), id); |
63 if(iq == NULL) | 62 if(iq == NULL) |
64 return; | 63 return; |
65 | 64 |
66 error_node = xmlnode_new_child(iq->node, "error"); | 65 error_node = xmlnode_new_child(iq->node, "error"); |
67 xmlnode_set_attrib(error_node, "code", "403"); | 66 xmlnode_set_attrib(error_node, "code", error_code); |
68 xmlnode_set_attrib(error_node, "type", "cancel"); | 67 xmlnode_set_attrib(error_node, "type", error_type); |
69 | 68 |
70 tmp_node = xmlnode_new_child(error_node, "forbidden"); | 69 /* TODO: Make this better */ |
71 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); | 70 if (!strcmp(error_code, "403")) { |
72 | 71 tmp_node = xmlnode_new_child(error_node, "forbidden"); |
73 tmp_node = xmlnode_new_child(error_node, "text"); | 72 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); |
74 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); | 73 |
75 xmlnode_insert_data(tmp_node, "Offer Declined", -1); | 74 tmp_node = xmlnode_new_child(error_node, "text"); |
75 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
76 xmlnode_insert_data(tmp_node, "Offer Declined", -1); | |
77 } else if (!strcmp(error_code, "404")) { | |
78 tmp_node = xmlnode_new_child(error_node, "item-not-found"); | |
79 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
80 } | |
76 | 81 |
77 xep_iq_send_and_free(iq); | 82 xep_iq_send_and_free(iq); |
78 } | 83 } |
79 | 84 |
80 static void bonjour_xfer_cancel_send(PurpleXfer *xfer) | 85 static void bonjour_xfer_cancel_send(PurpleXfer *xfer) |
83 bonjour_free_xfer(xfer); | 88 bonjour_free_xfer(xfer); |
84 } | 89 } |
85 | 90 |
86 static void bonjour_xfer_request_denied(PurpleXfer *xfer) | 91 static void bonjour_xfer_request_denied(PurpleXfer *xfer) |
87 { | 92 { |
93 XepXfer *xf = NULL; | |
94 | |
88 purple_debug_info("bonjour", "Bonjour-xfer-request-denied.\n"); | 95 purple_debug_info("bonjour", "Bonjour-xfer-request-denied.\n"); |
89 xep_ft_si_reject(xfer, xfer->who); | 96 |
97 xf = xfer->data; | |
98 if(xf) | |
99 xep_ft_si_reject(xf->data, xf->sid, xfer->who, "403", "cancel"); | |
100 | |
90 bonjour_free_xfer(xfer); | 101 bonjour_free_xfer(xfer); |
91 } | 102 } |
92 | 103 |
93 static void bonjour_xfer_cancel_recv(PurpleXfer *xfer) | 104 static void bonjour_xfer_cancel_recv(PurpleXfer *xfer) |
94 { | 105 { |
191 purple_debug_info("bonjour", "xep file transfer stream initialization offer-id=%d.\n", next_id); | 202 purple_debug_info("bonjour", "xep file transfer stream initialization offer-id=%d.\n", next_id); |
192 | 203 |
193 /* Assign stream id. */ | 204 /* Assign stream id. */ |
194 memset(buf, 0, 32); | 205 memset(buf, 0, 32); |
195 g_snprintf(buf, sizeof(buf), "%u", next_id++); | 206 g_snprintf(buf, sizeof(buf), "%u", next_id++); |
196 iq = xep_iq_new(xf->data, XEP_IQ_SET, to, buf); | 207 iq = xep_iq_new(xf->data, XEP_IQ_SET, to, purple_account_get_username(bd->jabber_data->account), buf); |
197 if(iq == NULL) | 208 if(iq == NULL) |
198 return; | 209 return; |
199 | 210 |
200 g_free(xf->sid); | 211 g_free(xf->sid); |
201 xf->sid = g_strdup(buf); | 212 xf->sid = g_strdup(buf); |
202 /*Construct Stream initialization offer message.*/ | 213 /*Construct Stream initialization offer message.*/ |
203 si_node = xmlnode_new_child(iq->node, "si"); | 214 si_node = xmlnode_new_child(iq->node, "si"); |
204 xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si"); | 215 xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si"); |
216 xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer"); | |
205 | 217 |
206 file = xmlnode_new_child(si_node, "file"); | 218 file = xmlnode_new_child(si_node, "file"); |
207 xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer"); | 219 xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer"); |
208 xmlnode_set_attrib(file, "name", xfer->filename); | 220 xmlnode_set_attrib(file, "name", xfer->filename); |
209 memset(buf, 0, 32); | 221 memset(buf, 0, 32); |
234 | 246 |
235 xep_iq_send_and_free(iq); | 247 xep_iq_send_and_free(iq); |
236 } | 248 } |
237 | 249 |
238 static void | 250 static void |
239 xep_ft_si_reject2(BonjourData *bd, const char *to, const char *sid) | |
240 { | |
241 xmlnode *error_node = NULL; | |
242 xmlnode *tmp_node = NULL; | |
243 XepIq *iq = NULL; | |
244 | |
245 g_return_if_fail(bd != NULL); | |
246 | |
247 if(!to || !sid) | |
248 return; | |
249 | |
250 purple_debug_info("bonjour", "xep file transfer stream initialization error.\n"); | |
251 iq = xep_iq_new(bd, XEP_IQ_ERROR, to, sid); | |
252 if(iq == NULL) | |
253 return; | |
254 | |
255 error_node = xmlnode_new_child(iq->node, "error"); | |
256 xmlnode_set_attrib(error_node, "code", "403"); | |
257 xmlnode_set_attrib(error_node, "type", "cancel"); | |
258 | |
259 tmp_node = xmlnode_new_child(error_node, "forbidden"); | |
260 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
261 | |
262 tmp_node = xmlnode_new_child(error_node, "text"); | |
263 xmlnode_set_namespace(tmp_node, "urn:ietf:params:xml:ns:xmpp-stanzas"); | |
264 xmlnode_insert_data(tmp_node, "Offer Declined", -1); | |
265 | |
266 xep_iq_send_and_free(iq); | |
267 } | |
268 | |
269 static void | |
270 xep_ft_si_result(PurpleXfer *xfer, char *to) | 251 xep_ft_si_result(PurpleXfer *xfer, char *to) |
271 { | 252 { |
272 xmlnode *si_node = NULL; | 253 xmlnode *si_node = NULL; |
273 xmlnode *feature = NULL; | 254 xmlnode *feature = NULL; |
274 xmlnode *field = NULL; | 255 xmlnode *field = NULL; |
275 xmlnode *value = NULL; | 256 xmlnode *value = NULL; |
276 xmlnode *x = NULL; | 257 xmlnode *x = NULL; |
277 XepIq *iq = NULL; | 258 XepIq *iq = NULL; |
278 XepXfer *xf = NULL; | 259 XepXfer *xf = NULL; |
260 BonjourData *bd; | |
279 | 261 |
280 if(!to || !xfer) | 262 if(!to || !xfer) |
281 return; | 263 return; |
282 xf = xfer->data; | 264 xf = xfer->data; |
283 if(!xf) | 265 if(!xf) |
284 return; | 266 return; |
285 | 267 |
268 bd = xf->data; | |
269 | |
286 purple_debug_info("bonjour", "xep file transfer stream initialization result.\n"); | 270 purple_debug_info("bonjour", "xep file transfer stream initialization result.\n"); |
287 iq = xep_iq_new(xf->data, XEP_IQ_RESULT, to, xf->sid); | 271 iq = xep_iq_new(bd, XEP_IQ_RESULT, to, purple_account_get_username(bd->jabber_data->account), xf->sid); |
288 if(iq == NULL) | 272 if(iq == NULL) |
289 return; | 273 return; |
290 | 274 |
291 si_node = xmlnode_new_child(iq->node, "si"); | 275 si_node = xmlnode_new_child(iq->node, "si"); |
292 xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si"); | 276 xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si"); |
277 /*xmlnode_set_attrib(si_node, "profile", "http://jabber.org/protocol/si/profile/file-transfer");*/ | |
293 | 278 |
294 feature = xmlnode_new_child(si_node, "feature"); | 279 feature = xmlnode_new_child(si_node, "feature"); |
295 xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg"); | 280 xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg"); |
296 | 281 |
297 x = xmlnode_new_child(feature, "x"); | 282 x = xmlnode_new_child(feature, "x"); |
329 } | 314 } |
330 if (xf->proxy_connection != NULL) | 315 if (xf->proxy_connection != NULL) |
331 purple_proxy_connect_cancel(xf->proxy_connection); | 316 purple_proxy_connect_cancel(xf->proxy_connection); |
332 if (xf->listen_data != NULL) | 317 if (xf->listen_data != NULL) |
333 purple_network_listen_cancel(xf->listen_data); | 318 purple_network_listen_cancel(xf->listen_data); |
319 g_free(xf->iq_id); | |
334 g_free(xf->jid); | 320 g_free(xf->jid); |
335 g_free(xf->proxy_host); | 321 g_free(xf->proxy_host); |
336 g_free(xf->buddy_ip); | 322 g_free(xf->buddy_ip); |
337 g_free(xf->sid); | 323 g_free(xf->sid); |
338 g_free(xf); | 324 g_free(xf); |
362 xfer->data = xep_xfer = g_new0(XepXfer, 1); | 348 xfer->data = xep_xfer = g_new0(XepXfer, 1); |
363 xep_xfer->data = bd; | 349 xep_xfer->data = bd; |
364 | 350 |
365 purple_debug_info("bonjour", "Bonjour-new-xfer bd=%p data=%p.\n", bd, xep_xfer->data); | 351 purple_debug_info("bonjour", "Bonjour-new-xfer bd=%p data=%p.\n", bd, xep_xfer->data); |
366 | 352 |
367 xep_xfer->mode = XEP_BYTESTREAMS | XEP_IBB; | 353 /* We don't support IBB yet */ |
354 /*xep_xfer->mode = XEP_BYTESTREAMS | XEP_IBB;*/ | |
355 xep_xfer->mode = XEP_BYTESTREAMS; | |
368 xep_xfer->sid = NULL; | 356 xep_xfer->sid = NULL; |
369 | 357 |
370 purple_xfer_set_init_fnc(xfer, bonjour_xfer_init); | 358 purple_xfer_set_init_fnc(xfer, bonjour_xfer_init); |
371 purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send); | 359 purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send); |
372 purple_xfer_set_end_fnc(xfer, bonjour_xfer_end); | 360 purple_xfer_set_end_fnc(xfer, bonjour_xfer_end); |
377 } | 365 } |
378 | 366 |
379 void | 367 void |
380 bonjour_send_file(PurpleConnection *gc, const char *who, const char *file) | 368 bonjour_send_file(PurpleConnection *gc, const char *who, const char *file) |
381 { | 369 { |
382 | |
383 PurpleXfer *xfer = NULL; | 370 PurpleXfer *xfer = NULL; |
384 if(gc == NULL || who == NULL) | 371 |
385 return; | 372 g_return_if_fail(gc != NULL); |
373 g_return_if_fail(who != NULL); | |
374 | |
386 purple_debug_info("bonjour", "Bonjour-send-file to=%s.\n", who); | 375 purple_debug_info("bonjour", "Bonjour-send-file to=%s.\n", who); |
376 | |
387 xfer = bonjour_new_xfer(gc, who); | 377 xfer = bonjour_new_xfer(gc, who); |
388 if(xfer == NULL) | 378 |
389 return; | |
390 if (file) | 379 if (file) |
391 purple_xfer_request_accepted(xfer, file); | 380 purple_xfer_request_accepted(xfer, file); |
392 else | 381 else |
393 purple_xfer_request(xfer); | 382 purple_xfer_request(xfer); |
394 | 383 |
399 { | 388 { |
400 PurpleBuddy *buddy = NULL; | 389 PurpleBuddy *buddy = NULL; |
401 BonjourBuddy *bd = NULL; | 390 BonjourBuddy *bd = NULL; |
402 XepXfer *xf = NULL; | 391 XepXfer *xf = NULL; |
403 | 392 |
404 if(xfer == NULL) | |
405 return; | |
406 xf = (XepXfer*)xfer->data; | 393 xf = (XepXfer*)xfer->data; |
407 if(xf == NULL) | 394 if(xf == NULL) |
408 return; | 395 return; |
396 | |
409 purple_debug_info("bonjour", "Bonjour-xfer-init.\n"); | 397 purple_debug_info("bonjour", "Bonjour-xfer-init.\n"); |
410 | 398 |
411 buddy = purple_find_buddy(xfer->account, xfer->who); | 399 buddy = purple_find_buddy(xfer->account, xfer->who); |
412 /* this buddy is offline. */ | 400 /* this buddy is offline. */ |
413 if (buddy == NULL) | 401 if (buddy == NULL) |
417 xf->buddy_ip = g_strdup(bd->ip); | 405 xf->buddy_ip = g_strdup(bd->ip); |
418 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) { | 406 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) { |
419 /* initiate file transfer, send SI offer. */ | 407 /* initiate file transfer, send SI offer. */ |
420 purple_debug_info("bonjour", "Bonjour xfer type is PURPLE_XFER_SEND.\n"); | 408 purple_debug_info("bonjour", "Bonjour xfer type is PURPLE_XFER_SEND.\n"); |
421 xep_ft_si_offer(xfer, xfer->who); | 409 xep_ft_si_offer(xfer, xfer->who); |
422 | |
423 } else { | 410 } else { |
424 /* accept file transfer request, send SI result. */ | 411 /* accept file transfer request, send SI result. */ |
425 xep_ft_si_result(xfer, xfer->who); | 412 xep_ft_si_result(xfer, xfer->who); |
426 purple_debug_info("bonjour", "Bonjour xfer type is PURPLE_XFER_RECEIVE.\n"); | 413 purple_debug_info("bonjour", "Bonjour xfer type is PURPLE_XFER_RECEIVE.\n"); |
427 } | 414 } |
428 return; | 415 } |
429 } | |
430 | |
431 | 416 |
432 void | 417 void |
433 xep_si_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb) | 418 xep_si_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb) |
434 { | 419 { |
435 const char *type = NULL, *from = NULL, *id = NULL; | 420 const char *type, *id; |
436 xmlnode *si = NULL, *file = NULL; | |
437 BonjourData *bd = NULL; | 421 BonjourData *bd = NULL; |
438 PurpleXfer *xfer = NULL; | 422 PurpleXfer *xfer = NULL; |
439 const char *filename = NULL, *filesize_str = NULL; | |
440 int filesize = 0, option = XEP_BYTESTREAMS; | |
441 | 423 |
442 if(pc == NULL || packet == NULL || pb == NULL) | 424 if(pc == NULL || packet == NULL || pb == NULL) |
443 return; | 425 return; |
444 bd = (BonjourData*) pc->proto_data; | 426 bd = (BonjourData*) pc->proto_data; |
445 if(bd == NULL) | 427 if(bd == NULL) |
446 return; | 428 return; |
447 | 429 |
448 purple_debug_info("bonjour", "xep-si-parse.\n"); | 430 purple_debug_info("bonjour", "xep-si-parse.\n"); |
449 | 431 |
450 type = xmlnode_get_attrib(packet, "type"); | 432 type = xmlnode_get_attrib(packet, "type"); |
451 from = pb->name; | |
452 id = xmlnode_get_attrib(packet, "id"); | 433 id = xmlnode_get_attrib(packet, "id"); |
453 if(type) { | 434 if(type) { |
454 if(!strcmp(type, "set")){ | 435 if(!strcmp(type, "set")) { |
455 si = xmlnode_get_child(packet,"si"); | 436 const char *profile; |
437 xmlnode *si; | |
438 gboolean parsed_receive = FALSE; | |
439 | |
440 si = xmlnode_get_child(packet, "si"); | |
441 | |
456 purple_debug_info("bonjour", "si offer Message type - SET.\n"); | 442 purple_debug_info("bonjour", "si offer Message type - SET.\n"); |
457 file = xmlnode_get_child(si, "file"); | 443 if (si && (profile = xmlnode_get_attrib(si, "profile")) |
458 /**/ | 444 && !strcmp(profile, "http://jabber.org/protocol/si/profile/file-transfer")) { |
459 filename = xmlnode_get_attrib(file, "name"); | 445 const char *filename = NULL, *filesize_str = NULL; |
460 if((filesize_str = xmlnode_get_attrib(file, "size"))) | 446 int filesize = 0; |
461 filesize = atoi(filesize_str); | 447 xmlnode *file; |
462 bonjour_xfer_receive(pc, id, from, filesize, filename, option); | 448 |
463 } else if(!strcmp(type, "result")){ | 449 if ((file = xmlnode_get_child(si, "file"))) { |
464 si = xmlnode_get_child(packet,"si"); | 450 filename = xmlnode_get_attrib(file, "name"); |
451 if((filesize_str = xmlnode_get_attrib(file, "size"))) | |
452 filesize = atoi(filesize_str); | |
453 } | |
454 | |
455 /* TODO: Make sure that it is advertising a bytestreams transfer */ | |
456 | |
457 bonjour_xfer_receive(pc, id, pb->name, filesize, filename, XEP_BYTESTREAMS); | |
458 | |
459 parsed_receive = TRUE; | |
460 } | |
461 | |
462 if (!parsed_receive) { | |
463 purple_debug_info("bonjour", "rejecting unrecognized si SET offer.\n"); | |
464 xep_ft_si_reject((BonjourData *)pc->proto_data, id, pb->name, "403", "cancel"); | |
465 /*TODO: Send Cancel (501) */ | |
466 } | |
467 } else if(!strcmp(type, "result")) { | |
465 purple_debug_info("bonjour", "si offer Message type - RESULT.\n"); | 468 purple_debug_info("bonjour", "si offer Message type - RESULT.\n"); |
466 xfer = bonjour_si_xfer_find(bd, id, from); | 469 |
467 if(xfer == NULL){ | 470 xfer = bonjour_si_xfer_find(bd, id, pb->name); |
471 | |
472 if(xfer == NULL) { | |
468 purple_debug_info("bonjour", "xfer find fail.\n"); | 473 purple_debug_info("bonjour", "xfer find fail.\n"); |
469 xep_ft_si_reject2((BonjourData *)pc->proto_data, from, id); | 474 xep_ft_si_reject((BonjourData *)pc->proto_data, id, pb->name, "403", "cancel"); |
470 } else { | 475 } else |
471 bonjour_bytestreams_init(xfer); | 476 bonjour_bytestreams_init(xfer); |
472 } | 477 |
473 } else if(!strcmp(type, "error")){ | 478 } else if(!strcmp(type, "error")) { |
474 purple_debug_info("bonjour", "si offer Message type - ERROR.\n"); | 479 purple_debug_info("bonjour", "si offer Message type - ERROR.\n"); |
475 xfer = bonjour_si_xfer_find(bd, id, from); | 480 |
476 if(xfer == NULL){ | 481 xfer = bonjour_si_xfer_find(bd, id, pb->name); |
482 | |
483 if(xfer == NULL) | |
477 purple_debug_info("bonjour", "xfer find fail.\n"); | 484 purple_debug_info("bonjour", "xfer find fail.\n"); |
478 } else { | 485 else |
479 purple_xfer_cancel_remote(xfer); | 486 purple_xfer_cancel_remote(xfer); |
480 } | 487 } else |
481 } else { | |
482 purple_debug_info("bonjour", "si offer Message type - Unknown-%d.\n", type); | 488 purple_debug_info("bonjour", "si offer Message type - Unknown-%d.\n", type); |
483 } | |
484 } | 489 } |
485 } | 490 } |
486 | 491 |
487 void | 492 void |
488 xep_bytestreams_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb) | 493 xep_bytestreams_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb) |
489 { | 494 { |
490 const char *type = NULL, *from = NULL, *id = NULL; | 495 const char *type = NULL, *from = NULL; |
491 xmlnode *query = NULL, *streamhost = NULL; | 496 xmlnode *query = NULL, *streamhost = NULL; |
492 BonjourData *bd = NULL; | 497 BonjourData *bd = NULL; |
493 PurpleXfer *xfer = NULL; | 498 PurpleXfer *xfer = NULL; |
494 XepXfer *xf = NULL; | 499 XepXfer *xf = NULL; |
495 const char *jid=NULL, *host=NULL, *port=NULL; | |
496 int portnum; | 500 int portnum; |
497 | 501 |
498 if(pc == NULL || packet == NULL || pb == NULL) | 502 if(pc == NULL || packet == NULL || pb == NULL) |
499 return; | 503 return; |
500 | 504 |
506 | 510 |
507 type = xmlnode_get_attrib(packet, "type"); | 511 type = xmlnode_get_attrib(packet, "type"); |
508 from = pb->name; | 512 from = pb->name; |
509 query = xmlnode_get_child(packet,"query"); | 513 query = xmlnode_get_child(packet,"query"); |
510 if(type) { | 514 if(type) { |
511 if(!strcmp(type, "set")){ | 515 if(!strcmp(type, "set")) { |
516 const char *iq_id, *sid; | |
517 gboolean found = FALSE; | |
518 | |
512 purple_debug_info("bonjour", "bytestream offer Message type - SET.\n"); | 519 purple_debug_info("bonjour", "bytestream offer Message type - SET.\n"); |
513 | 520 |
514 id = xmlnode_get_attrib(query, "sid"); | 521 iq_id = xmlnode_get_attrib(packet, "id"); |
515 xfer = bonjour_si_xfer_find(bd, id, from); | 522 |
516 | 523 sid = xmlnode_get_attrib(query, "sid"); |
517 if(xfer){ | 524 xfer = bonjour_si_xfer_find(bd, sid, from); |
525 | |
526 if(xfer) { | |
527 const char *jid, *host, *port; | |
528 | |
518 xf = (XepXfer*)xfer->data; | 529 xf = (XepXfer*)xfer->data; |
519 for(streamhost = xmlnode_get_child(query, "streamhost"); | 530 for(streamhost = xmlnode_get_child(query, "streamhost"); |
520 streamhost; | 531 streamhost; |
521 streamhost = xmlnode_get_next_twin(streamhost)) { | 532 streamhost = xmlnode_get_next_twin(streamhost)) { |
522 | 533 |
524 (host = xmlnode_get_attrib(streamhost, "host")) && | 535 (host = xmlnode_get_attrib(streamhost, "host")) && |
525 (port = xmlnode_get_attrib(streamhost, "port")) && | 536 (port = xmlnode_get_attrib(streamhost, "port")) && |
526 (portnum = atoi(port))) { | 537 (portnum = atoi(port))) { |
527 | 538 |
528 if(!strcmp(host, xf->buddy_ip)) { | 539 if(!strcmp(host, xf->buddy_ip)) { |
540 g_free(xf->iq_id); | |
541 xf->iq_id = g_strdup(iq_id); | |
529 xf->jid = g_strdup(jid); | 542 xf->jid = g_strdup(jid); |
530 xf->proxy_host = g_strdup(host); | 543 xf->proxy_host = g_strdup(host); |
531 xf->proxy_port = portnum; | 544 xf->proxy_port = portnum; |
532 purple_debug_info("bonjour", "bytestream offer parse" | 545 purple_debug_info("bonjour", "bytestream offer parse" |
533 "jid=%s host=%s port=%d.\n", jid, host, portnum); | 546 "jid=%s host=%s port=%d.\n", jid, host, portnum); |
534 bonjour_bytestreams_connect(xfer); | 547 bonjour_bytestreams_connect(xfer); |
548 found = TRUE; | |
535 break; | 549 break; |
536 } | 550 } |
537 | |
538 } else { | 551 } else { |
539 purple_debug_info("bonjour", "bytestream offer Message parse error.\n"); | 552 purple_debug_info("bonjour", "bytestream offer Message parse error.\n"); |
540 } | 553 } |
541 } | 554 } |
542 } else { | 555 } else { |
543 | 556 |
544 } | 557 } |
545 | 558 |
559 if (!found) { | |
560 purple_debug_error("bonjour", "Didn't find an acceptable streamhost.\n"); | |
561 | |
562 if (iq_id) | |
563 xep_ft_si_reject(bd, iq_id, xfer->who, "404", "cancel"); | |
564 } | |
565 | |
546 } else { | 566 } else { |
547 purple_debug_info("bonjour", "bytestream offer Message type - Unknown-%d.\n", type); | 567 purple_debug_info("bonjour", "bytestream offer Message type - Unknown-%s.\n", type); |
548 } | 568 } |
549 } | 569 } |
550 } | 570 } |
551 | 571 |
552 static void | 572 static void |
555 { | 575 { |
556 PurpleXfer *xfer = NULL; | 576 PurpleXfer *xfer = NULL; |
557 XepXfer *xf = NULL; | 577 XepXfer *xf = NULL; |
558 BonjourData *bd = NULL; | 578 BonjourData *bd = NULL; |
559 | 579 |
560 if(pc == NULL || id == NULL || from == NULL || filename == NULL) | 580 if(pc == NULL || id == NULL || from == NULL) |
561 return; | 581 return; |
562 | 582 |
563 bd = (BonjourData*) pc->proto_data; | 583 bd = (BonjourData*) pc->proto_data; |
564 if(bd == NULL) | 584 if(bd == NULL) |
565 return; | 585 return; |
591 PurpleXfer *xfer = data; | 611 PurpleXfer *xfer = data; |
592 XepXfer *xf = NULL; | 612 XepXfer *xf = NULL; |
593 int acceptfd; | 613 int acceptfd; |
594 int len = 0; | 614 int len = 0; |
595 | 615 |
596 if(xfer == NULL) | |
597 return; | |
598 | |
599 xf = xfer->data; | 616 xf = xfer->data; |
600 if(xf == NULL) | 617 if(xf == NULL) |
601 return; | 618 return; |
602 | 619 |
603 purple_debug_info("bonjour", "bonjour_sock5_request_cb - req_state = 0x%x\n", xf->sock5_req_state); | 620 purple_debug_info("bonjour", "bonjour_sock5_request_cb - req_state = 0x%x\n", xf->sock5_req_state); |
606 case 0x00: | 623 case 0x00: |
607 acceptfd = accept(source, NULL, 0); | 624 acceptfd = accept(source, NULL, 0); |
608 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { | 625 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { |
609 | 626 |
610 } else if(acceptfd == -1) { | 627 } else if(acceptfd == -1) { |
611 | 628 /* TODO: This should cancel the ft */ |
612 } else { | 629 } else { |
613 int flags; | 630 int flags; |
614 | 631 |
615 purple_debug_info("bonjour", "Accepted SOCKS5 ft connection - fd=%d\n", acceptfd); | 632 purple_debug_info("bonjour", "Accepted SOCKS5 ft connection - fd=%d\n", acceptfd); |
616 | 633 |
718 xmlnode *query, *streamhost; | 735 xmlnode *query, *streamhost; |
719 char *port; | 736 char *port; |
720 const char *next_ip; | 737 const char *next_ip; |
721 const char *local_ip = NULL; | 738 const char *local_ip = NULL; |
722 char token [] = ";"; | 739 char token [] = ";"; |
740 BonjourData *bd; | |
723 | 741 |
724 purple_debug_info("bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock); | 742 purple_debug_info("bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock); |
725 if (sock < 0 || xfer == NULL) { | 743 if (sock < 0 || xfer == NULL) { |
726 /*purple_xfer_cancel_local(xfer);*/ | 744 /*purple_xfer_cancel_local(xfer);*/ |
727 return; | 745 return; |
730 xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, | 748 xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ, |
731 bonjour_sock5_request_cb, xfer); | 749 bonjour_sock5_request_cb, xfer); |
732 xf = (XepXfer*)xfer->data; | 750 xf = (XepXfer*)xfer->data; |
733 xf->listen_data = NULL; | 751 xf->listen_data = NULL; |
734 | 752 |
735 iq = xep_iq_new(xf->data, XEP_IQ_SET, xfer->who, xf->sid); | 753 bd = xf->data; |
754 | |
755 iq = xep_iq_new(bd, XEP_IQ_SET, xfer->who, purple_account_get_username(bd->jabber_data->account), xf->sid); | |
736 | 756 |
737 query = xmlnode_new_child(iq->node, "query"); | 757 query = xmlnode_new_child(iq->node, "query"); |
738 xmlnode_set_namespace(query, "http://jabber.org/protocol/bytestreams"); | 758 xmlnode_set_namespace(query, "http://jabber.org/protocol/bytestreams"); |
739 xmlnode_set_attrib(query, "sid", xf->sid); | 759 xmlnode_set_attrib(query, "sid", xf->sid); |
740 xmlnode_set_attrib(query, "mode", "tcp"); | 760 xmlnode_set_attrib(query, "mode", "tcp"); |
743 | 763 |
744 local_ip = purple_network_get_my_ip_ext2(sock); | 764 local_ip = purple_network_get_my_ip_ext2(sock); |
745 /* cheat a little here - the intent of the "const" attribute is to make it clear that the string doesn't need to be freed */ | 765 /* cheat a little here - the intent of the "const" attribute is to make it clear that the string doesn't need to be freed */ |
746 next_ip = strtok((char *)local_ip, token); | 766 next_ip = strtok((char *)local_ip, token); |
747 | 767 |
768 port = g_strdup_printf("%hu", xfer->local_port); | |
748 while(next_ip != NULL) { | 769 while(next_ip != NULL) { |
749 streamhost = xmlnode_new_child(query, "streamhost"); | 770 streamhost = xmlnode_new_child(query, "streamhost"); |
750 xmlnode_set_attrib(streamhost, "jid", xf->sid); | 771 xmlnode_set_attrib(streamhost, "jid", xf->sid); |
751 xmlnode_set_attrib(streamhost, "host", next_ip); | 772 xmlnode_set_attrib(streamhost, "host", next_ip); |
752 port = g_strdup_printf("%hu", xfer->local_port); | |
753 xmlnode_set_attrib(streamhost, "port", port); | 773 xmlnode_set_attrib(streamhost, "port", port); |
754 g_free(port); | |
755 next_ip = strtok(NULL, token); | 774 next_ip = strtok(NULL, token); |
756 } | 775 } |
776 g_free(port); | |
757 | 777 |
758 xep_iq_send_and_free(iq); | 778 xep_iq_send_and_free(iq); |
759 } | 779 } |
760 | 780 |
761 static void | 781 static void |
779 static void | 799 static void |
780 bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message) | 800 bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message) |
781 { | 801 { |
782 PurpleXfer *xfer = data; | 802 PurpleXfer *xfer = data; |
783 XepXfer *xf = xfer->data; | 803 XepXfer *xf = xfer->data; |
784 | 804 XepIq *iq = NULL; |
785 if(data == NULL || source < 0) | 805 xmlnode *q_node, *tmp_node; |
786 return; | 806 BonjourData *bd; |
807 | |
808 if(data == NULL || source < 0) { | |
809 xep_ft_si_reject(xf->data, xf->iq_id, xfer->who, "404", "cancel"); | |
810 /* Cancel the connection */ | |
811 purple_xfer_cancel_local(xfer); | |
812 return; | |
813 } | |
814 | |
815 bd = xf->data; | |
787 | 816 |
788 purple_proxy_info_destroy(xf->proxy_info); | 817 purple_proxy_info_destroy(xf->proxy_info); |
789 xf->proxy_connection = NULL; | 818 xf->proxy_connection = NULL; |
790 xf->proxy_info = NULL; | 819 xf->proxy_info = NULL; |
791 /* Here, start the file transfer.*/ | 820 /* Here, start the file transfer.*/ |
821 | |
822 /* Notify Initiator of Connection */ | |
823 iq = xep_iq_new(bd, XEP_IQ_RESULT, xfer->who, purple_account_get_username(bd->jabber_data->account), xf->iq_id); | |
824 q_node = xmlnode_new_child(iq->node, "query"); | |
825 xmlnode_set_namespace(q_node, "http://jabber.org/protocol/bytestreams"); | |
826 tmp_node = xmlnode_new_child(q_node, "streamhost-used"); | |
827 xmlnode_set_attrib(tmp_node, "jid", xf->jid); | |
828 xep_iq_send_and_free(iq); | |
829 | |
792 purple_xfer_start(xfer, source, NULL, -1); | 830 purple_xfer_start(xfer, source, NULL, -1); |
793 } | 831 } |
794 | 832 |
795 static void | 833 static void |
796 bonjour_bytestreams_connect(PurpleXfer *xfer) | 834 bonjour_bytestreams_connect(PurpleXfer *xfer) |
827 xf->proxy_connection = purple_proxy_connect_socks5(NULL, xf->proxy_info, | 865 xf->proxy_connection = purple_proxy_connect_socks5(NULL, xf->proxy_info, |
828 dstaddr, 0, | 866 dstaddr, 0, |
829 bonjour_bytestreams_connect_cb, xfer); | 867 bonjour_bytestreams_connect_cb, xfer); |
830 | 868 |
831 if(xf->proxy_connection == NULL) { | 869 if(xf->proxy_connection == NULL) { |
832 purple_proxy_info_destroy(xf->proxy_info); | 870 xep_ft_si_reject(xf->data, xf->iq_id, xfer->who, "404", "cancel"); |
833 xf->proxy_info = NULL; | 871 /* Cancel the connection */ |
834 } | 872 purple_xfer_cancel_local(xfer); |
835 } | 873 /*purple_proxy_info_destroy(xf->proxy_info); |
836 | 874 xf->proxy_info = NULL;*/ |
875 } | |
876 } | |
877 |