Mercurial > pidgin.yaz
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 } |