comparison libpurple/protocols/bonjour/bonjour_ft.c @ 21440:d8106b63b0a4

I thought I was just fixing a leak in this commit, but it turns out I forgot to add the new files in the previous commit.
author Daniel Atallah <daniel.atallah@gmail.com>
date Mon, 12 Nov 2007 04:17:10 +0000
parents
children da75dd6c41fb
comparison
equal deleted inserted replaced
21439:8fbd51946259 21440:d8106b63b0a4
1 /*
2 * purple - Bonjour Protocol Plugin
3 *
4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 #include "internal.h"
23 #include "util.h"
24 #include "debug.h"
25 #include "notify.h"
26 #include "proxy.h"
27 #include "ft.h"
28 #include "buddy.h"
29 #include "bonjour.h"
30 #include "bonjour_ft.h"
31 #include "cipher.h"
32
33 static PurpleXfer*
34 bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from);
35 static void
36 xep_ft_si_offer(PurpleXfer *xfer, const gchar *to);
37 static void
38 xep_ft_si_result(PurpleXfer *xfer, char *to);
39 static void
40 xep_ft_si_reject(PurpleXfer *xfer, char *to);
41 static void
42 xep_ft_si_reject2(BonjourData *bd, const char *to, const char *sid);
43 static void
44 bonjour_bytestreams_init(PurpleXfer *xfer);
45 static void
46 bonjour_bytestreams_listen(int sock, gpointer data);
47 static void
48 bonjour_sock5_request_cb(gpointer data, gint source, PurpleInputCondition cond);
49 static void
50 bonjour_bytestreams_connect(PurpleXfer *xfer);
51 static void
52 bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message);
53 static void
54 bonjour_xfer_init(PurpleXfer *xfer);
55 static void
56 bonjour_xfer_receive(PurpleConnection *pc, const char *id, const char *from,
57 const int filesize, const char *filename, int option);
58 static void bonjour_xfer_cancel_send(PurpleXfer *xfer);
59 static void bonjour_xfer_request_denied(PurpleXfer *xfer);
60 static void bonjour_xfer_cancel_recv(PurpleXfer *xfer);
61 static void bonjour_xfer_end(PurpleXfer *xfer);
62 static void bonjour_free_xfer(PurpleXfer *xfer);
63
64 /* Look for specific xfer handle */
65 static unsigned int next_id = 0;
66
67 static void bonjour_xfer_cancel_send(PurpleXfer *xfer)
68 {
69 purple_debug_info("Bonjour", "Bonjour-xfer-cancel-send.\n");
70 bonjour_free_xfer(xfer);
71 }
72
73 static void bonjour_xfer_request_denied(PurpleXfer *xfer)
74 {
75 purple_debug_info("Bonjour", "Bonjour-xfer-request-denied.\n");
76 xep_ft_si_reject(xfer, xfer->who);
77 bonjour_free_xfer(xfer);
78 }
79
80
81 static void bonjour_xfer_cancel_recv(PurpleXfer *xfer)
82 {
83 purple_debug_info("Bonjour", "Bonjour-xfer-cancel-recv.\n");
84 bonjour_free_xfer(xfer);
85 }
86
87
88 static void bonjour_xfer_end(PurpleXfer *xfer)
89 {
90 purple_debug_info("Bonjour", "Bonjour-xfer-end.\n");
91 bonjour_free_xfer(xfer);
92 }
93
94 static PurpleXfer*
95 bonjour_si_xfer_find(BonjourData *bd, const char *sid, const char *from)
96 {
97 GList *xfers = NULL;
98 PurpleXfer *xfer = NULL;
99 XepXfer *xf = NULL;
100
101 if(!sid || !from || !bd)
102 return NULL;
103
104 purple_debug_info("Bonjour", "Look for sid=%s from=%s xferlists.\n",
105 sid, from);
106
107 for(xfers = bd->xfer_lists; xfers; xfers = xfers->next) {
108 xfer = xfers->data;
109 if(xfer == NULL)
110 break;
111 xf = xfer->data;
112 if(xf == NULL)
113 break;
114 if(xf->sid && xfer->who && !strcmp(xf->sid, sid) &&
115 !strcmp(xfer->who, from))
116 return xfer;
117 }
118
119 purple_debug_info("Bonjour", "Look for xfer list fail\n");
120
121 return NULL;
122 }
123
124 static void
125 xep_ft_si_offer(PurpleXfer *xfer, const gchar *to)
126 {
127 xmlnode *si_node = NULL;
128 xmlnode *feature = NULL;
129 xmlnode *field = NULL;
130 xmlnode *option = NULL;
131 xmlnode *value = NULL;
132 xmlnode *file = NULL;
133 xmlnode *x = NULL;
134 XepIq *iq = NULL;
135 XepXfer *xf = NULL;
136 BonjourData *bd = NULL;
137 char buf[32];
138
139 if(!xfer || !to)
140 return;
141 xf = xfer->data;
142 if(!xf)
143 return;
144 bd = xf->data;
145 if(!bd)
146 return;
147
148 purple_debug_info("Bonjour", "xep file transfer stream initialization offer-id=%d.\n", next_id);
149
150 /* Assign stream id. */
151 memset(buf, 0, 32);
152 g_snprintf(buf, sizeof(buf), "%u", next_id++);
153 iq = xep_iq_new(xf->data, XEP_IQ_SET, to, buf);
154 if(iq == NULL)
155 return;
156
157 g_free(xf->sid);
158 xf->sid = g_strdup(buf);
159 /*Construct Stream initialization offer message.*/
160 si_node = xmlnode_new_child(iq->node, "si");
161 xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si");
162
163 file = xmlnode_new_child(si_node, "file");
164 xmlnode_set_namespace(file, "http://jabber.org/protocol/si/profile/file-transfer");
165 xmlnode_set_attrib(file, "name", xfer->filename);
166 memset(buf, 0, 32);
167 g_snprintf(buf, sizeof(buf), "%" G_GSIZE_FORMAT, xfer->size);
168 xmlnode_set_attrib(file, "size", buf);
169
170 feature = xmlnode_new_child(si_node, "feature");
171 xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");
172
173 x = xmlnode_new_child(feature, "x");
174 xmlnode_set_namespace(x, "jabber:x:data");
175 xmlnode_set_attrib(x, "type", "form");
176
177 field = xmlnode_new_child(x, "field");
178 xmlnode_set_attrib(field, "var", "stream-method");
179 xmlnode_set_attrib(field, "type", "list-single");
180
181 if (xf->mode & XEP_BYTESTREAMS) {
182 option = xmlnode_new_child(field, "option");
183 value = xmlnode_new_child(option, "value");
184 xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
185 }
186 if (xf->mode & XEP_IBB) {
187 option = xmlnode_new_child(field, "option");
188 value = xmlnode_new_child(option, "value");
189 xmlnode_insert_data(value, "http://jabber.org/protocol/ibb", -1);
190 }
191 xep_iq_send(iq);
192 }
193
194 static void
195 xep_ft_si_reject(PurpleXfer *xfer, char *to)
196 {
197 xmlnode *error_node = NULL;
198 xmlnode *forbidden = NULL;
199 xmlnode *text = NULL;
200 XepIq *iq = NULL;
201 XepXfer *xf = NULL;
202
203 if(!to || !xfer)
204 return;
205 xf = xfer->data;
206 if(!xf)
207 return;
208
209 purple_debug_info("Bonjour", "xep file transfer stream initialization error.\n");
210 iq = xep_iq_new(xf->data, XEP_IQ_ERROR, to, xf->sid);
211 if(iq == NULL)
212 return;
213
214 error_node = xmlnode_new_child(iq->node, "error");
215 xmlnode_set_attrib(error_node, "code", "403");
216 xmlnode_set_attrib(error_node, "type", "cancel");
217
218 forbidden = xmlnode_new_child(error_node, "forbidden");
219 xmlnode_set_namespace(forbidden, "urn:ietf:params:xml:ns:xmpp-stanzas");
220
221 text = xmlnode_new_child(error_node, "text");
222 xmlnode_set_namespace(text, "urn:ietf:params:xml:ns:xmpp-stanzas");
223 xmlnode_insert_data(text, "Offer Declined", -1);
224
225 xep_iq_send(iq);
226 }
227 static void
228 xep_ft_si_reject2(BonjourData *bd, const char *to, const char *sid)
229 {
230 xmlnode *error_node = NULL;
231 xmlnode *forbidden = NULL;
232 xmlnode *text = NULL;
233 XepIq *iq = NULL;
234 if(bd == NULL)
235 return;
236 if(!to || !sid)
237 return;
238 purple_debug_info("Bonjour", "xep file transfer stream initialization error.\n");
239 iq = xep_iq_new(bd, XEP_IQ_ERROR, to, sid);
240 if(iq == NULL)
241 return;
242 error_node = xmlnode_new_child(iq->node, "error");
243 xmlnode_set_attrib(error_node, "code", "403");
244 xmlnode_set_attrib(error_node, "type", "cancel");
245
246 forbidden = xmlnode_new_child(error_node, "forbidden");
247 xmlnode_set_namespace(forbidden, "urn:ietf:params:xml:ns:xmpp-stanzas");
248
249 text = xmlnode_new_child(error_node, "text");
250 xmlnode_set_namespace(text, "urn:ietf:params:xml:ns:xmpp-stanzas");
251 xmlnode_insert_data(text, "Offer Declined", -1);
252
253 xep_iq_send(iq);
254 }
255
256 static void
257 xep_ft_si_result(PurpleXfer *xfer, char *to)
258 {
259 xmlnode *si_node = NULL;
260 xmlnode *feature = NULL;
261 xmlnode *field = NULL;
262 xmlnode *value = NULL;
263 xmlnode *x = NULL;
264 XepIq *iq = NULL;
265 XepXfer *xf = NULL;
266
267 if(!to || !xfer)
268 return;
269 xf = xfer->data;
270 if(!xf)
271 return;
272
273 purple_debug_info("Bonjour", "xep file transfer stream initialization result.\n");
274 iq = xep_iq_new(xf->data, XEP_IQ_RESULT, to, xf->sid);
275 if(iq == NULL)
276 return;
277
278 si_node = xmlnode_new_child(iq->node, "si");
279 xmlnode_set_namespace(si_node, "http://jabber.org/protocol/si");
280
281 feature = xmlnode_new_child(si_node, "feature");
282 xmlnode_set_namespace(feature, "http://jabber.org/protocol/feature-neg");
283
284 x = xmlnode_new_child(feature, "x");
285 xmlnode_set_namespace(x, "jabber:x:data");
286 xmlnode_set_attrib(x, "type", "submit");
287
288 field = xmlnode_new_child(x, "field");
289 xmlnode_set_attrib(field, "var", "stream-method");
290
291 value = xmlnode_new_child(field, "value");
292 xmlnode_insert_data(value, "http://jabber.org/protocol/bytestreams", -1);
293
294 xep_iq_send(iq);
295 }
296
297 static void
298 bonjour_free_xfer(PurpleXfer *xfer)
299 {
300 XepXfer *xf = NULL;
301 BonjourData *bd = NULL;
302 if(xfer == NULL) {
303 purple_debug_info("Bonjour", "bonjour-free-xfer-null.\n");
304 return;
305 }
306 purple_debug_info("Bonjour", "bonjour-free-xfer-%x.\n", (int)xfer);
307 xf = (XepXfer*)xfer->data;
308 if(xf != NULL){
309 bd = (BonjourData*)xf->data;
310 if(bd != NULL){
311 bd->xfer_lists = g_list_remove(bd->xfer_lists, xfer);
312 purple_debug_info("Bonjour", "B free xfer from lists(0x%x).\n", (int)bd->xfer_lists);
313 }
314 if (xf->proxy_connection != NULL)
315 purple_proxy_connect_cancel(xf->proxy_connection);
316 if (xf->listen_data != NULL)
317 purple_network_listen_cancel(xf->listen_data);
318 g_free(xf->jid);
319 g_free(xf->proxy_host);
320 g_free(xf->buddy_ip);
321 g_free(xf);
322 xfer->data = NULL;
323 }
324 purple_debug_info("Bonjour", "Need close socket=0x%x.\n", xfer->fd);
325 }
326
327 PurpleXfer *
328 bonjour_new_xfer(PurpleConnection *gc, const char *who)
329 {
330 PurpleXfer *xfer = NULL;
331 XepXfer *xep_xfer = NULL;
332 BonjourData *bd = NULL;
333 if(who == NULL || gc == NULL)
334 return xfer;
335
336 purple_debug_info("Bonjour", "Bonjour-new-xfer to %s.\n", who);
337 bd = (BonjourData*) gc->proto_data;
338 if(bd == NULL)
339 return xfer;
340 /* Build the file transfer handle */
341 xfer = purple_xfer_new(gc->account, PURPLE_XFER_SEND, who);
342
343 if (xfer) {
344 xep_xfer = g_new0(XepXfer, 1);
345 if(xep_xfer == NULL){
346 bonjour_free_xfer(xfer);
347 return NULL;
348 }
349 xep_xfer->data = bd;
350 purple_debug_info("Bonjour", "Bonjour-new-xfer bd=0x%x data=0x%x.\n",(int)bd, (int)xep_xfer->data);
351 xep_xfer->mode = XEP_BYTESTREAMS | XEP_IBB;
352 xfer->data = xep_xfer;
353 xep_xfer->sid = NULL;
354 purple_xfer_set_init_fnc(xfer, bonjour_xfer_init);
355 purple_xfer_set_cancel_send_fnc(xfer, bonjour_xfer_cancel_send);
356 purple_xfer_set_end_fnc(xfer, bonjour_xfer_end);
357 bd->xfer_lists = g_list_append(bd->xfer_lists, xfer);
358 }
359 return xfer;
360 }
361
362 void
363 bonjour_send_file(PurpleConnection *gc, const char *who, const char *file)
364 {
365
366 PurpleXfer *xfer = NULL;
367 if(gc == NULL || who == NULL)
368 return;
369 purple_debug_info("Bonjour", "Bonjour-send-file to=%s.\n", who);
370 xfer = bonjour_new_xfer(gc, who);
371 if(xfer == NULL)
372 return;
373 if (file)
374 purple_xfer_request_accepted(xfer, file);
375 else
376 purple_xfer_request(xfer);
377
378 }
379
380 static void
381 bonjour_xfer_init(PurpleXfer *xfer)
382 {
383 PurpleBuddy *buddy = NULL;
384 BonjourBuddy *bd = NULL;
385 XepXfer *xf = NULL;
386 char buffer[100];
387 if(xfer == NULL)
388 return;
389 xf = (XepXfer*)xfer->data;
390 if(xf == NULL)
391 return;
392 purple_debug_info("Bonjour", "Bonjour-xfer-init.\n");
393
394 buddy = purple_find_buddy(xfer->account, xfer->who);
395 /* this buddy is offline. */
396 if (buddy == NULL)
397 return;
398
399 bd = (BonjourBuddy *)buddy->proto_data;
400 memcpy(buffer, bd->ip, 20);
401 xf->buddy_ip = g_strdup(bd->ip);
402 if (purple_xfer_get_type(xfer) == PURPLE_XFER_SEND) {
403 /* initiate file transfer, send SI offer. */
404 purple_debug_info("Bonjour", "Bonjour xfer type is PURPLE_XFER_SEND.\n");
405 xep_ft_si_offer(xfer, xfer->who);
406
407 } else {
408 /* accept file transfer request, send SI result. */
409 xep_ft_si_result(xfer, xfer->who);
410 purple_debug_info("Bonjour", "Bonjour xfer type is PURPLE_XFER_RECEIVE.\n");
411 }
412 return;
413 }
414
415
416 void
417 xep_si_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb)
418 {
419 const char *type = NULL, *from = NULL, *id = NULL;
420 xmlnode *si = NULL, *file = NULL;
421 BonjourData *bd = NULL;
422 PurpleXfer *xfer = NULL;
423 const char *filename = NULL, *filesize_str = NULL;
424 int filesize = 0, option = XEP_BYTESTREAMS;
425
426 if(pc == NULL || packet == NULL || pb == NULL)
427 return;
428 bd = (BonjourData*) pc->proto_data;
429 if(bd == NULL)
430 return;
431 purple_debug_info("Bonjour", "xep-si-parse.\n");
432 type = xmlnode_get_attrib(packet, "type");
433 from = pb->name;
434 id = xmlnode_get_attrib(packet, "id");
435 if(type) {
436 if(!strcmp(type, "set")){
437 si = xmlnode_get_child(packet,"si");
438 purple_debug_info("Bonjour", "si offer Message type - SET.\n");
439 file = xmlnode_get_child(si, "file");
440 /**/
441 filename = xmlnode_get_attrib(file, "name");
442 if( (filesize_str = xmlnode_get_attrib(file, "size")) != NULL )
443 filesize = atoi(filesize_str);
444 bonjour_xfer_receive(pc, id, from, filesize, filename, option);
445 } else if(!strcmp(type, "result")){
446 si = xmlnode_get_child(packet,"si");
447 purple_debug_info("Bonjour", "si offer Message type - RESULT.\n");
448 xfer = bonjour_si_xfer_find(bd, id, from);
449 if(xfer == NULL){
450 purple_debug_info("Bonjour", "xfer find fail.\n");
451 xep_ft_si_reject2((BonjourData *)pc->proto_data, from, id);
452 } else {
453 bonjour_bytestreams_init(xfer);
454 }
455 } else if(!strcmp(type, "error")){
456 purple_debug_info("Bonjour", "si offer Message type - ERROR.\n");
457 xfer = bonjour_si_xfer_find(bd, id, from);
458 if(xfer == NULL){
459 purple_debug_info("Bonjour", "xfer find fail.\n");
460 } else {
461 purple_xfer_cancel_remote(xfer);
462 }
463 } else {
464 purple_debug_info("Bonjour", "si offer Message type - Unknown-%d.\n",type);
465 }
466 }
467 }
468
469 void
470 xep_bytestreams_parse(PurpleConnection *pc, xmlnode *packet, PurpleBuddy *pb)
471 {
472 const char *type = NULL, *from = NULL, *id = NULL;
473 xmlnode *query = NULL, *streamhost = NULL;
474 BonjourData *bd = NULL;
475 PurpleXfer *xfer = NULL;
476 XepXfer *xf = NULL;
477 const char *jid=NULL, *host=NULL, *port=NULL;
478 int portnum;
479 if(pc == NULL || packet == NULL || pb == NULL)
480 return;
481 bd = (BonjourData*) pc->proto_data;
482 if(bd == NULL)
483 return;
484 purple_debug_info("Bonjour", "xep-bytestreams-parse.\n");
485 type = xmlnode_get_attrib(packet, "type");
486 from = pb->name;
487 query = xmlnode_get_child(packet,"query");
488 if(type) {
489 if(!strcmp(type, "set")){
490 purple_debug_info("Bonjour", "bytestream offer Message type - SET.\n");
491 id = xmlnode_get_attrib(query, "sid");
492 xfer = bonjour_si_xfer_find(bd, id, from);
493 if(xfer){
494 xf = (XepXfer*)xfer->data;
495 for(streamhost = xmlnode_get_child(query, "streamhost");
496 streamhost;
497 streamhost = xmlnode_get_next_twin(streamhost)) {
498 if((jid = xmlnode_get_attrib(streamhost, "jid")) &&
499 (host = xmlnode_get_attrib(streamhost, "host")) &&
500 (port = xmlnode_get_attrib(streamhost, "port")) &&
501 (portnum = atoi(port))) {
502 if(!strcmp(host, xf->buddy_ip)) {
503 xf->jid = g_strdup(jid);
504 xf->proxy_host = g_strdup(host);
505 xf->proxy_port = portnum;
506 purple_debug_info("Bonjour", "bytestream offer parse"
507 "jid=%s host=%s port=0x%x.\n",jid, host, portnum);
508 bonjour_bytestreams_connect(xfer);
509 }
510 } else {
511 purple_debug_info("Bonjour", "bytestream offer Message parse error.\n");
512 }
513 }
514 } else {
515
516 }
517
518 } else {
519 purple_debug_info("Bonjour", "bytestream offer Message type - Unknown-%d.\n",type);
520 }
521 }
522 }
523
524 static void
525 bonjour_xfer_receive(PurpleConnection *pc, const char *id, const char *from,
526 const int filesize, const char *filename, int option)
527 {
528 PurpleXfer *xfer = NULL;
529 XepXfer *xf = NULL;
530 BonjourData *bd = NULL;
531 if(pc == NULL || id == NULL || from == NULL || filename == NULL)
532 return;
533 bd = (BonjourData*) pc->proto_data;
534 if(bd == NULL)
535 return;
536 purple_debug_info("Bonjour", "bonjour-xfer-receive.\n");
537 /* Build the file transfer handle */
538 xfer = purple_xfer_new(pc->account, PURPLE_XFER_RECEIVE, from);
539 if (xfer) {
540 xf = g_new0(XepXfer, 1);
541 xf->data = bd;
542 xfer->data = xf;
543 purple_xfer_set_filename(xfer, filename);
544 xf->sid = g_strdup(id);
545 if(filesize > 0)
546 purple_xfer_set_size(xfer, filesize);
547 purple_xfer_set_init_fnc(xfer, bonjour_xfer_init);
548 purple_xfer_set_request_denied_fnc(xfer, bonjour_xfer_request_denied);
549 purple_xfer_set_cancel_recv_fnc(xfer, bonjour_xfer_cancel_recv);
550 purple_xfer_set_end_fnc(xfer, bonjour_xfer_end);
551 bd->xfer_lists = g_list_append(bd->xfer_lists, xfer);
552 purple_xfer_request(xfer);
553 }
554 }
555
556 static void
557 bonjour_bytestreams_init(PurpleXfer *xfer)
558 {
559 XepXfer *xf = NULL;
560 if(xfer == NULL)
561 return;
562 purple_debug_info("Bonjour", "Bonjour-bytestreams-init.\n");
563 xf = xfer->data;
564 xf->listen_data = purple_network_listen_range(0, 0, SOCK_STREAM,
565 bonjour_bytestreams_listen, xfer);
566 if (xf->listen_data == NULL) {
567 purple_xfer_cancel_local(xfer);
568 }
569 return;
570 }
571
572 static void
573 bonjour_bytestreams_listen(int sock, gpointer data)
574 {
575 PurpleXfer *xfer = NULL;
576 XepXfer *xf;
577 XepIq *iq;
578 xmlnode *query, *streamhost;
579 char *port;
580 char *next_ip = NULL;
581 char *local_ip = NULL;
582 char token [] = ";";
583 purple_debug_info("Bonjour", "Bonjour-bytestreams-listen. sock=%d.\n", sock);
584 if (sock < 0 || data == NULL) {
585 /*purple_xfer_cancel_local(xfer);*/
586 return;
587 }
588 xfer = data;
589 xfer->watcher = purple_input_add(sock, PURPLE_INPUT_READ,
590 bonjour_sock5_request_cb, xfer);
591 xf = (XepXfer*)xfer->data;
592 xf->listen_data = NULL;
593 /*xf->listen_data = NULL;*/
594 iq = xep_iq_new(xf->data, XEP_IQ_SET, xfer->who, xf->sid);
595 query = xmlnode_new_child(iq->node, "query");
596 xmlnode_set_namespace(query, "http://jabber.org/protocol/bytestreams");
597 xmlnode_set_attrib(query, "sid", xf->sid);
598 xmlnode_set_attrib(query, "mode", "tcp");
599 local_ip = purple_network_get_my_ip_ext2(sock);
600 next_ip = strtok(local_ip, token);
601 xfer->local_port = purple_network_get_port_from_fd(sock);
602 while(next_ip != NULL) {
603 streamhost = xmlnode_new_child(query, "streamhost");
604 xmlnode_set_attrib(streamhost, "jid", xf->sid);
605 xmlnode_set_attrib(streamhost, "host", next_ip);
606 port = g_strdup_printf("%hu", xfer->local_port);
607 xmlnode_set_attrib(streamhost, "port", port);
608 g_free(port);
609 next_ip = strtok(NULL, token);
610 }
611 xep_iq_send(iq);
612 }
613
614 static void
615 bonjour_sock5_request_cb(gpointer data, gint source, PurpleInputCondition cond)
616 {
617 PurpleXfer *xfer = data;
618 XepXfer *xf = NULL;
619 int acceptfd;
620 int len = 0;
621 if(xfer == NULL )
622 return;
623 xf = xfer->data;
624 if(xf == NULL)
625 return;
626 switch(xf->sock5_req_state){
627 case 0x00:
628 acceptfd = accept (source, NULL, 0);
629 if(acceptfd == -1 && (errno == EAGAIN || errno == EWOULDBLOCK )) {
630
631 } else if(acceptfd == -1) {
632
633 } else {
634 purple_debug_info("Bonjour", "Conjour-sock5-request-cb. state= %d, accept=%d\n", xf->sock5_req_state,acceptfd);
635 purple_input_remove(xfer->watcher);
636 close(source);
637 xfer->watcher = purple_input_add(acceptfd, PURPLE_INPUT_READ,
638 bonjour_sock5_request_cb, xfer);
639 xf->sock5_req_state++;
640 xf->rxlen = 0;
641 }
642 break;
643 case 0x01:
644 xfer->fd = source;
645 len = read(source, xf->rx_buf + xf->rxlen, 3);
646 if(len < 0 && errno == EAGAIN)
647 return;
648 else if(len <= 0){
649 purple_input_remove(xfer->watcher);
650 xfer->watcher = 0;
651 close(source);
652 purple_xfer_cancel_remote(xfer);
653 return;
654 } else {
655 purple_input_remove(xfer->watcher);
656 xfer->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
657 bonjour_sock5_request_cb, xfer);
658 xf->sock5_req_state++;
659 xf->rxlen = 0;
660 bonjour_sock5_request_cb(xfer, source, PURPLE_INPUT_WRITE);
661 }
662 break;
663 case 0x02:
664 xf->tx_buf[0] = 0x05;
665 xf->tx_buf[1] = 0x00;
666 len = write(source, xf->tx_buf, 2);
667 if (len < 0 && errno == EAGAIN)
668 return;
669 else if (len < 0) {
670 purple_input_remove(xfer->watcher);
671 xfer->watcher = 0;
672 close(source);
673 purple_xfer_cancel_remote(xfer);
674 return;
675 } else {
676 purple_input_remove(xfer->watcher);
677 xfer->watcher = purple_input_add(source, PURPLE_INPUT_READ,
678 bonjour_sock5_request_cb, xfer);
679 xf->sock5_req_state++;
680 xf->rxlen = 0;
681 }
682 break;
683 case 0x03:
684 len = read(source, xf->rx_buf + xf->rxlen, 20);
685 if(len<=0){
686 } else {
687 purple_input_remove(xfer->watcher);
688 xfer->watcher = purple_input_add(source, PURPLE_INPUT_WRITE,
689 bonjour_sock5_request_cb, xfer);
690 xf->sock5_req_state++;
691 xf->rxlen = 0;
692 bonjour_sock5_request_cb(xfer, source, PURPLE_INPUT_WRITE);
693 }
694 break;
695 case 0x04:
696 xf->tx_buf[0] = 0x05;
697 xf->tx_buf[1] = 0x00;
698 xf->tx_buf[2] = 0x00;
699 xf->tx_buf[3] = 0x03;
700 xf->tx_buf[4] = strlen(xf->buddy_ip);
701 memcpy(xf->tx_buf + 5, xf->buddy_ip, strlen(xf->buddy_ip));
702 xf->tx_buf[5+strlen(xf->buddy_ip)] = 0x00;
703 xf->tx_buf[6+strlen(xf->buddy_ip)] = 0x00;
704 len = write(source, xf->tx_buf, 7 + strlen(xf->buddy_ip));
705 if (len < 0 && errno == EAGAIN) {
706 return;
707 } else if (len < 0) {
708 purple_input_remove(xfer->watcher);
709 xfer->watcher = 0;
710 close(source);
711 purple_xfer_cancel_remote(xfer);
712 return;
713 } else {
714 purple_input_remove(xfer->watcher);
715 xfer->watcher = 0;
716 xf->rxlen = 0;
717 /*close(source);*/
718 purple_xfer_start(xfer, source, NULL, -1);
719 }
720 break;
721 default:
722 break;
723 }
724 return;
725 }
726 static void
727 bonjour_bytestreams_connect(PurpleXfer *xfer)
728 {
729 XepXfer *xf = NULL;
730 char dstaddr[41];
731 unsigned char hashval[20];
732 char *p = NULL;
733 int i;
734 if(xfer == NULL)
735 return;
736 purple_debug_info("Bonjour", "bonjour-bytestreams-connect.\n");
737 xf = (XepXfer*)xfer->data;
738 if(!xf)
739 return;
740 xf->proxy_info = purple_proxy_info_new();
741 if(xf->proxy_info == NULL)
742 return;
743 p = g_strdup_printf("%s@%s", xf->sid, xfer->who);
744 purple_cipher_digest_region("sha1", (guchar *)dstaddr, strlen(dstaddr),
745 sizeof(hashval), hashval, NULL);
746 g_free(p);
747 memset(dstaddr, 0, 41);
748 p = dstaddr;
749 for(i=0; i<20; i++) {
750 snprintf(p, 3, "%02x", hashval[i]);
751 }
752 purple_proxy_info_set_type(xf->proxy_info, PURPLE_PROXY_SOCKS5);
753 purple_proxy_info_set_host(xf->proxy_info, xf->proxy_host);
754 purple_proxy_info_set_port(xf->proxy_info, xf->proxy_port);
755 xf->proxy_connection = purple_proxy_connect_socks5(NULL, xf->proxy_info,
756 dstaddr, 0,
757 bonjour_bytestreams_connect_cb, xfer);
758 if(xf->proxy_connection == NULL) {
759 purple_proxy_info_destroy(xf->proxy_info);
760 xf->proxy_info = NULL;
761 }
762 }
763
764 static void
765 bonjour_bytestreams_connect_cb(gpointer data, gint source, const gchar *error_message)
766 {
767 PurpleXfer *xfer = data;
768 XepXfer *xf = xfer->data;
769 if(data == NULL || source < 0)
770 return;
771 purple_proxy_info_destroy(xf->proxy_info);
772 xf->proxy_connection = NULL;
773 xf->proxy_info = NULL;
774 /* Here, start the file transfer.*/
775 purple_xfer_start(xfer, source, NULL, -1);
776 }