Mercurial > pidgin.yaz
comparison libpurple/protocols/msnp9/slplink.c @ 21312:a07cfce78345
Add MSNP9 back as an alternative alongside the existing MSN prpl. Cowardly
old fools like me who prefer the stability of our MSNP9 code over the
features of MSNP14 can enable this using the --disable-msnp14 ./configure
option.
If we want to release from i.p.p and MSN stability is the only blocker, we
can trivially flick the default to use MSNP9 in configure.ac
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sun, 11 Nov 2007 12:57:52 +0000 |
parents | |
children | 48abe30dc90a |
comparison
equal
deleted
inserted
replaced
21311:7d031cec5ba2 | 21312:a07cfce78345 |
---|---|
1 /** | |
2 * @file slplink.c MSNSLP Link support | |
3 * | |
4 * purple | |
5 * | |
6 * Purple is the legal property of its developers, whose names are too numerous | |
7 * to list here. Please refer to the COPYRIGHT file distributed with this | |
8 * source distribution. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA | |
23 */ | |
24 #include "msn.h" | |
25 #include "slplink.h" | |
26 | |
27 #include "switchboard.h" | |
28 #include "slp.h" | |
29 | |
30 void msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg); | |
31 | |
32 #ifdef MSN_DEBUG_SLP_FILES | |
33 static int m_sc = 0; | |
34 static int m_rc = 0; | |
35 | |
36 static void | |
37 debug_msg_to_file(MsnMessage *msg, gboolean send) | |
38 { | |
39 char *tmp; | |
40 char *dir; | |
41 char *pload; | |
42 FILE *tf; | |
43 int c; | |
44 gsize pload_size; | |
45 | |
46 dir = send ? "send" : "recv"; | |
47 c = send ? m_sc++ : m_rc++; | |
48 tmp = g_strdup_printf("%s/msntest/%s/%03d", g_get_home_dir(), dir, c); | |
49 tf = g_fopen(tmp, "wb"); | |
50 if (tf == NULL) | |
51 { | |
52 purple_debug_error("msn", "could not open debug file\n"); | |
53 return; | |
54 } | |
55 pload = msn_message_gen_payload(msg, &pload_size); | |
56 fwrite(pload, 1, pload_size, tf); | |
57 fclose(tf); | |
58 g_free(tmp); | |
59 } | |
60 #endif | |
61 | |
62 /************************************************************************** | |
63 * Main | |
64 **************************************************************************/ | |
65 | |
66 MsnSlpLink * | |
67 msn_slplink_new(MsnSession *session, const char *username) | |
68 { | |
69 MsnSlpLink *slplink; | |
70 | |
71 g_return_val_if_fail(session != NULL, NULL); | |
72 | |
73 slplink = g_new0(MsnSlpLink, 1); | |
74 | |
75 #ifdef MSN_DEBUG_SLPLINK | |
76 purple_debug_info("msn", "slplink_new: slplink(%p)\n", slplink); | |
77 #endif | |
78 | |
79 slplink->session = session; | |
80 slplink->slp_seq_id = rand() % 0xFFFFFF00 + 4; | |
81 | |
82 slplink->local_user = g_strdup(msn_user_get_passport(session->user)); | |
83 slplink->remote_user = g_strdup(username); | |
84 | |
85 slplink->slp_msg_queue = g_queue_new(); | |
86 | |
87 session->slplinks = | |
88 g_list_append(session->slplinks, slplink); | |
89 | |
90 return slplink; | |
91 } | |
92 | |
93 void | |
94 msn_slplink_destroy(MsnSlpLink *slplink) | |
95 { | |
96 MsnSession *session; | |
97 | |
98 #ifdef MSN_DEBUG_SLPLINK | |
99 purple_debug_info("msn", "slplink_destroy: slplink(%p)\n", slplink); | |
100 #endif | |
101 | |
102 g_return_if_fail(slplink != NULL); | |
103 | |
104 if (slplink->swboard != NULL) | |
105 slplink->swboard->slplinks = g_list_remove(slplink->swboard->slplinks, slplink); | |
106 | |
107 session = slplink->session; | |
108 | |
109 if (slplink->local_user != NULL) | |
110 g_free(slplink->local_user); | |
111 | |
112 if (slplink->remote_user != NULL) | |
113 g_free(slplink->remote_user); | |
114 | |
115 if (slplink->directconn != NULL) | |
116 msn_directconn_destroy(slplink->directconn); | |
117 | |
118 while (slplink->slp_calls != NULL) | |
119 msn_slp_call_destroy(slplink->slp_calls->data); | |
120 | |
121 session->slplinks = | |
122 g_list_remove(session->slplinks, slplink); | |
123 | |
124 g_free(slplink); | |
125 } | |
126 | |
127 MsnSlpLink * | |
128 msn_session_find_slplink(MsnSession *session, const char *who) | |
129 { | |
130 GList *l; | |
131 | |
132 for (l = session->slplinks; l != NULL; l = l->next) | |
133 { | |
134 MsnSlpLink *slplink; | |
135 | |
136 slplink = l->data; | |
137 | |
138 if (!strcmp(slplink->remote_user, who)) | |
139 return slplink; | |
140 } | |
141 | |
142 return NULL; | |
143 } | |
144 | |
145 MsnSlpLink * | |
146 msn_session_get_slplink(MsnSession *session, const char *username) | |
147 { | |
148 MsnSlpLink *slplink; | |
149 | |
150 g_return_val_if_fail(session != NULL, NULL); | |
151 g_return_val_if_fail(username != NULL, NULL); | |
152 | |
153 slplink = msn_session_find_slplink(session, username); | |
154 | |
155 if (slplink == NULL) | |
156 slplink = msn_slplink_new(session, username); | |
157 | |
158 return slplink; | |
159 } | |
160 | |
161 MsnSlpSession * | |
162 msn_slplink_find_slp_session(MsnSlpLink *slplink, long session_id) | |
163 { | |
164 GList *l; | |
165 MsnSlpSession *slpsession; | |
166 | |
167 for (l = slplink->slp_sessions; l != NULL; l = l->next) | |
168 { | |
169 slpsession = l->data; | |
170 | |
171 if (slpsession->id == session_id) | |
172 return slpsession; | |
173 } | |
174 | |
175 return NULL; | |
176 } | |
177 | |
178 void | |
179 msn_slplink_add_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall) | |
180 { | |
181 if (slplink->swboard != NULL) | |
182 slplink->swboard->flag |= MSN_SB_FLAG_FT; | |
183 | |
184 slplink->slp_calls = g_list_append(slplink->slp_calls, slpcall); | |
185 } | |
186 | |
187 void | |
188 msn_slplink_remove_slpcall(MsnSlpLink *slplink, MsnSlpCall *slpcall) | |
189 { | |
190 slplink->slp_calls = g_list_remove(slplink->slp_calls, slpcall); | |
191 | |
192 /* The slplink has no slpcalls in it. If no one is using it, we might | |
193 * destroy the switchboard, but we should be careful not to use the slplink | |
194 * again. */ | |
195 if (slplink->slp_calls == NULL) | |
196 { | |
197 if (slplink->swboard != NULL) | |
198 { | |
199 if (msn_switchboard_release(slplink->swboard, MSN_SB_FLAG_FT)) | |
200 /* I'm not sure this is the best thing to do, but it's better | |
201 * than nothing. */ | |
202 slpcall->slplink = NULL; | |
203 } | |
204 } | |
205 } | |
206 | |
207 MsnSlpCall * | |
208 msn_slplink_find_slp_call(MsnSlpLink *slplink, const char *id) | |
209 { | |
210 GList *l; | |
211 MsnSlpCall *slpcall; | |
212 | |
213 if (!id) | |
214 return NULL; | |
215 | |
216 for (l = slplink->slp_calls; l != NULL; l = l->next) | |
217 { | |
218 slpcall = l->data; | |
219 | |
220 if (slpcall->id && !strcmp(slpcall->id, id)) | |
221 return slpcall; | |
222 } | |
223 | |
224 return NULL; | |
225 } | |
226 | |
227 MsnSlpCall * | |
228 msn_slplink_find_slp_call_with_session_id(MsnSlpLink *slplink, long id) | |
229 { | |
230 GList *l; | |
231 MsnSlpCall *slpcall; | |
232 | |
233 for (l = slplink->slp_calls; l != NULL; l = l->next) | |
234 { | |
235 slpcall = l->data; | |
236 | |
237 if (slpcall->session_id == id) | |
238 return slpcall; | |
239 } | |
240 | |
241 return NULL; | |
242 } | |
243 | |
244 void | |
245 msn_slplink_send_msg(MsnSlpLink *slplink, MsnMessage *msg) | |
246 { | |
247 if (slplink->directconn != NULL) | |
248 { | |
249 msn_directconn_send_msg(slplink->directconn, msg); | |
250 } | |
251 else | |
252 { | |
253 if (slplink->swboard == NULL) | |
254 { | |
255 slplink->swboard = msn_session_get_swboard(slplink->session, | |
256 slplink->remote_user, MSN_SB_FLAG_FT); | |
257 | |
258 if (slplink->swboard == NULL) | |
259 return; | |
260 | |
261 /* If swboard is destroyed we will be too */ | |
262 slplink->swboard->slplinks = g_list_prepend(slplink->swboard->slplinks, slplink); | |
263 } | |
264 | |
265 msn_switchboard_send_msg(slplink->swboard, msg, TRUE); | |
266 } | |
267 } | |
268 | |
269 /* We have received the message ack */ | |
270 static void | |
271 msg_ack(MsnMessage *msg, void *data) | |
272 { | |
273 MsnSlpMessage *slpmsg; | |
274 long long real_size; | |
275 | |
276 slpmsg = data; | |
277 | |
278 real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size; | |
279 | |
280 slpmsg->offset += msg->msnslp_header.length; | |
281 | |
282 if (slpmsg->offset < real_size) | |
283 { | |
284 msn_slplink_send_msgpart(slpmsg->slplink, slpmsg); | |
285 } | |
286 else | |
287 { | |
288 /* The whole message has been sent */ | |
289 if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) | |
290 { | |
291 if (slpmsg->slpcall != NULL) | |
292 { | |
293 if (slpmsg->slpcall->cb) | |
294 slpmsg->slpcall->cb(slpmsg->slpcall, | |
295 NULL, 0); | |
296 } | |
297 } | |
298 } | |
299 | |
300 slpmsg->msgs = g_list_remove(slpmsg->msgs, msg); | |
301 } | |
302 | |
303 /* We have received the message nak. */ | |
304 static void | |
305 msg_nak(MsnMessage *msg, void *data) | |
306 { | |
307 MsnSlpMessage *slpmsg; | |
308 | |
309 slpmsg = data; | |
310 | |
311 msn_slplink_send_msgpart(slpmsg->slplink, slpmsg); | |
312 | |
313 slpmsg->msgs = g_list_remove(slpmsg->msgs, msg); | |
314 } | |
315 | |
316 void | |
317 msn_slplink_send_msgpart(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) | |
318 { | |
319 MsnMessage *msg; | |
320 long long real_size; | |
321 size_t len = 0; | |
322 | |
323 /* Maybe we will want to create a new msg for this slpmsg instead of | |
324 * reusing the same one all the time. */ | |
325 msg = slpmsg->msg; | |
326 | |
327 real_size = (slpmsg->flags == 0x2) ? 0 : slpmsg->size; | |
328 | |
329 if (slpmsg->offset < real_size) | |
330 { | |
331 if (slpmsg->fp) | |
332 { | |
333 char data[1202]; | |
334 len = fread(data, 1, sizeof(data), slpmsg->fp); | |
335 msn_message_set_bin_data(msg, data, len); | |
336 } | |
337 else | |
338 { | |
339 len = slpmsg->size - slpmsg->offset; | |
340 | |
341 if (len > 1202) | |
342 len = 1202; | |
343 | |
344 msn_message_set_bin_data(msg, slpmsg->buffer + slpmsg->offset, len); | |
345 } | |
346 | |
347 msg->msnslp_header.offset = slpmsg->offset; | |
348 msg->msnslp_header.length = len; | |
349 } | |
350 | |
351 #ifdef MSN_DEBUG_SLP | |
352 msn_message_show_readable(msg, slpmsg->info, slpmsg->text_body); | |
353 #endif | |
354 | |
355 #ifdef MSN_DEBUG_SLP_FILES | |
356 debug_msg_to_file(msg, TRUE); | |
357 #endif | |
358 | |
359 slpmsg->msgs = | |
360 g_list_append(slpmsg->msgs, msg); | |
361 msn_slplink_send_msg(slplink, msg); | |
362 | |
363 if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && | |
364 (slpmsg->slpcall != NULL)) | |
365 { | |
366 slpmsg->slpcall->progress = TRUE; | |
367 | |
368 if (slpmsg->slpcall->progress_cb != NULL) | |
369 { | |
370 slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, | |
371 len, slpmsg->offset); | |
372 } | |
373 } | |
374 | |
375 /* slpmsg->offset += len; */ | |
376 } | |
377 | |
378 void | |
379 msn_slplink_release_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) | |
380 { | |
381 MsnMessage *msg; | |
382 | |
383 slpmsg->msg = msg = msn_message_new_msnslp(); | |
384 | |
385 if (slpmsg->flags == 0x0) | |
386 { | |
387 msg->msnslp_header.session_id = slpmsg->session_id; | |
388 msg->msnslp_header.ack_id = rand() % 0xFFFFFF00; | |
389 } | |
390 else if (slpmsg->flags == 0x2) | |
391 { | |
392 msg->msnslp_header.session_id = slpmsg->session_id; | |
393 msg->msnslp_header.ack_id = slpmsg->ack_id; | |
394 msg->msnslp_header.ack_size = slpmsg->ack_size; | |
395 msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id; | |
396 } | |
397 else if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) | |
398 { | |
399 MsnSlpSession *slpsession; | |
400 slpsession = slpmsg->slpsession; | |
401 | |
402 g_return_if_fail(slpsession != NULL); | |
403 msg->msnslp_header.session_id = slpsession->id; | |
404 msg->msnslp_footer.value = slpsession->app_id; | |
405 msg->msnslp_header.ack_id = rand() % 0xFFFFFF00; | |
406 } | |
407 else if (slpmsg->flags == 0x100) | |
408 { | |
409 msg->msnslp_header.ack_id = slpmsg->ack_id; | |
410 msg->msnslp_header.ack_sub_id = slpmsg->ack_sub_id; | |
411 msg->msnslp_header.ack_size = slpmsg->ack_size; | |
412 } | |
413 | |
414 msg->msnslp_header.id = slpmsg->id; | |
415 msg->msnslp_header.flags = slpmsg->flags; | |
416 | |
417 msg->msnslp_header.total_size = slpmsg->size; | |
418 | |
419 msn_message_set_attr(msg, "P2P-Dest", slplink->remote_user); | |
420 | |
421 msg->ack_cb = msg_ack; | |
422 msg->nak_cb = msg_nak; | |
423 msg->ack_data = slpmsg; | |
424 | |
425 msn_slplink_send_msgpart(slplink, slpmsg); | |
426 | |
427 msn_message_destroy(msg); | |
428 } | |
429 | |
430 void | |
431 msn_slplink_queue_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) | |
432 { | |
433 slpmsg->id = slplink->slp_seq_id++; | |
434 | |
435 g_queue_push_head(slplink->slp_msg_queue, slpmsg); | |
436 } | |
437 | |
438 void | |
439 msn_slplink_send_slpmsg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) | |
440 { | |
441 slpmsg->id = slplink->slp_seq_id++; | |
442 | |
443 msn_slplink_release_slpmsg(slplink, slpmsg); | |
444 } | |
445 | |
446 void | |
447 msn_slplink_unleash(MsnSlpLink *slplink) | |
448 { | |
449 MsnSlpMessage *slpmsg; | |
450 | |
451 /* Send the queued msgs in the order they came. */ | |
452 | |
453 while ((slpmsg = g_queue_pop_tail(slplink->slp_msg_queue)) != NULL) | |
454 { | |
455 msn_slplink_release_slpmsg(slplink, slpmsg); | |
456 } | |
457 } | |
458 | |
459 void | |
460 msn_slplink_send_ack(MsnSlpLink *slplink, MsnMessage *msg) | |
461 { | |
462 MsnSlpMessage *slpmsg; | |
463 | |
464 slpmsg = msn_slpmsg_new(slplink); | |
465 | |
466 slpmsg->session_id = msg->msnslp_header.session_id; | |
467 slpmsg->size = msg->msnslp_header.total_size; | |
468 slpmsg->flags = 0x02; | |
469 slpmsg->ack_id = msg->msnslp_header.id; | |
470 slpmsg->ack_sub_id = msg->msnslp_header.ack_id; | |
471 slpmsg->ack_size = msg->msnslp_header.total_size; | |
472 | |
473 #ifdef MSN_DEBUG_SLP | |
474 slpmsg->info = "SLP ACK"; | |
475 #endif | |
476 | |
477 msn_slplink_send_slpmsg(slplink, slpmsg); | |
478 } | |
479 | |
480 static void | |
481 send_file_cb(MsnSlpSession *slpsession) | |
482 { | |
483 MsnSlpCall *slpcall; | |
484 MsnSlpMessage *slpmsg; | |
485 struct stat st; | |
486 PurpleXfer *xfer; | |
487 | |
488 slpcall = slpsession->slpcall; | |
489 slpmsg = msn_slpmsg_new(slpcall->slplink); | |
490 slpmsg->slpcall = slpcall; | |
491 slpmsg->flags = 0x1000030; | |
492 slpmsg->slpsession = slpsession; | |
493 #ifdef MSN_DEBUG_SLP | |
494 slpmsg->info = "SLP FILE"; | |
495 #endif | |
496 xfer = (PurpleXfer *)slpcall->xfer; | |
497 purple_xfer_start(slpcall->xfer, 0, NULL, 0); | |
498 slpmsg->fp = xfer->dest_fp; | |
499 if (g_stat(purple_xfer_get_local_filename(xfer), &st) == 0) | |
500 slpmsg->size = st.st_size; | |
501 xfer->dest_fp = NULL; /* Disable double fclose() */ | |
502 | |
503 msn_slplink_send_slpmsg(slpcall->slplink, slpmsg); | |
504 } | |
505 | |
506 void | |
507 msn_slplink_process_msg(MsnSlpLink *slplink, MsnMessage *msg) | |
508 { | |
509 MsnSlpMessage *slpmsg; | |
510 const char *data; | |
511 gsize offset; | |
512 gsize len; | |
513 | |
514 #ifdef MSN_DEBUG_SLP | |
515 msn_slpmsg_show(msg); | |
516 #endif | |
517 | |
518 #ifdef MSN_DEBUG_SLP_FILES | |
519 debug_msg_to_file(msg, FALSE); | |
520 #endif | |
521 | |
522 if (msg->msnslp_header.total_size < msg->msnslp_header.length) | |
523 { | |
524 purple_debug_error("msn", "This can't be good\n"); | |
525 g_return_if_reached(); | |
526 } | |
527 | |
528 slpmsg = NULL; | |
529 data = msn_message_get_bin_data(msg, &len); | |
530 | |
531 /* | |
532 OVERHEAD! | |
533 if (msg->msnslp_header.length < msg->msnslp_header.total_size) | |
534 */ | |
535 | |
536 offset = msg->msnslp_header.offset; | |
537 | |
538 if (offset == 0) | |
539 { | |
540 slpmsg = msn_slpmsg_new(slplink); | |
541 slpmsg->id = msg->msnslp_header.id; | |
542 slpmsg->session_id = msg->msnslp_header.session_id; | |
543 slpmsg->size = msg->msnslp_header.total_size; | |
544 slpmsg->flags = msg->msnslp_header.flags; | |
545 | |
546 if (slpmsg->session_id) | |
547 { | |
548 if (slpmsg->slpcall == NULL) | |
549 slpmsg->slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id); | |
550 | |
551 if (slpmsg->slpcall != NULL) | |
552 { | |
553 if (slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) | |
554 { | |
555 PurpleXfer *xfer; | |
556 | |
557 xfer = slpmsg->slpcall->xfer; | |
558 | |
559 if (xfer != NULL) | |
560 { | |
561 purple_xfer_start(slpmsg->slpcall->xfer, | |
562 0, NULL, 0); | |
563 slpmsg->fp = ((PurpleXfer *)slpmsg->slpcall->xfer)->dest_fp; | |
564 xfer->dest_fp = NULL; /* Disable double fclose() */ | |
565 } | |
566 } | |
567 } | |
568 } | |
569 if (!slpmsg->fp && slpmsg->size) | |
570 { | |
571 slpmsg->buffer = g_try_malloc(slpmsg->size); | |
572 if (slpmsg->buffer == NULL) | |
573 { | |
574 purple_debug_error("msn", "Failed to allocate buffer for slpmsg\n"); | |
575 return; | |
576 } | |
577 } | |
578 } | |
579 else | |
580 { | |
581 slpmsg = msn_slplink_message_find(slplink, msg->msnslp_header.session_id, msg->msnslp_header.id); | |
582 } | |
583 | |
584 if (slpmsg == NULL) | |
585 { | |
586 /* Probably the transfer was canceled */ | |
587 purple_debug_error("msn", "Couldn't find slpmsg\n"); | |
588 return; | |
589 } | |
590 | |
591 if (slpmsg->fp) | |
592 { | |
593 /* fseek(slpmsg->fp, offset, SEEK_SET); */ | |
594 len = fwrite(data, 1, len, slpmsg->fp); | |
595 } | |
596 else if (slpmsg->size) | |
597 { | |
598 if ((offset + len) > slpmsg->size) | |
599 { | |
600 purple_debug_error("msn", "Oversized slpmsg\n"); | |
601 g_return_if_reached(); | |
602 } | |
603 else | |
604 memcpy(slpmsg->buffer + offset, data, len); | |
605 } | |
606 | |
607 if ((slpmsg->flags == 0x20 || slpmsg->flags == 0x1000030) && | |
608 (slpmsg->slpcall != NULL)) | |
609 { | |
610 slpmsg->slpcall->progress = TRUE; | |
611 | |
612 if (slpmsg->slpcall->progress_cb != NULL) | |
613 { | |
614 slpmsg->slpcall->progress_cb(slpmsg->slpcall, slpmsg->size, | |
615 len, offset); | |
616 } | |
617 } | |
618 | |
619 #if 0 | |
620 if (slpmsg->buffer == NULL) | |
621 return; | |
622 #endif | |
623 | |
624 if (msg->msnslp_header.offset + msg->msnslp_header.length | |
625 >= msg->msnslp_header.total_size) | |
626 { | |
627 /* All the pieces of the slpmsg have been received */ | |
628 MsnSlpCall *slpcall; | |
629 | |
630 slpcall = msn_slp_process_msg(slplink, slpmsg); | |
631 | |
632 if (slpmsg->flags == 0x100) | |
633 { | |
634 MsnDirectConn *directconn; | |
635 | |
636 directconn = slplink->directconn; | |
637 | |
638 if (!directconn->acked) | |
639 msn_directconn_send_handshake(directconn); | |
640 } | |
641 else if (slpmsg->flags == 0x0 || slpmsg->flags == 0x20 || | |
642 slpmsg->flags == 0x1000030) | |
643 { | |
644 /* Release all the messages and send the ACK */ | |
645 | |
646 msn_slplink_send_ack(slplink, msg); | |
647 msn_slplink_unleash(slplink); | |
648 } | |
649 | |
650 msn_slpmsg_destroy(slpmsg); | |
651 | |
652 if (slpcall != NULL && slpcall->wasted) | |
653 msn_slp_call_destroy(slpcall); | |
654 } | |
655 } | |
656 | |
657 MsnSlpMessage * | |
658 msn_slplink_message_find(MsnSlpLink *slplink, long session_id, long id) | |
659 { | |
660 GList *e; | |
661 | |
662 for (e = slplink->slp_msgs; e != NULL; e = e->next) | |
663 { | |
664 MsnSlpMessage *slpmsg = e->data; | |
665 | |
666 if ((slpmsg->session_id == session_id) && (slpmsg->id == id)) | |
667 return slpmsg; | |
668 } | |
669 | |
670 return NULL; | |
671 } | |
672 | |
673 typedef struct | |
674 { | |
675 guint32 length; | |
676 guint32 unk1; | |
677 guint32 file_size; | |
678 guint32 unk2; | |
679 guint32 unk3; | |
680 } MsnContextHeader; | |
681 | |
682 #define MAX_FILE_NAME_LEN 0x226 | |
683 | |
684 static gchar * | |
685 gen_context(const char *file_name, const char *file_path) | |
686 { | |
687 struct stat st; | |
688 gsize size = 0; | |
689 MsnContextHeader header; | |
690 gchar *u8 = NULL; | |
691 guchar *base; | |
692 guchar *n; | |
693 gchar *ret; | |
694 gunichar2 *uni = NULL; | |
695 glong currentChar = 0; | |
696 glong uni_len = 0; | |
697 gsize len; | |
698 | |
699 if (g_stat(file_path, &st) == 0) | |
700 size = st.st_size; | |
701 | |
702 if(!file_name) { | |
703 u8 = purple_utf8_try_convert(g_basename(file_path)); | |
704 file_name = u8; | |
705 } | |
706 | |
707 uni = g_utf8_to_utf16(file_name, -1, NULL, &uni_len, NULL); | |
708 | |
709 if(u8) { | |
710 g_free(u8); | |
711 file_name = NULL; | |
712 u8 = NULL; | |
713 } | |
714 | |
715 len = sizeof(MsnContextHeader) + MAX_FILE_NAME_LEN + 4; | |
716 | |
717 header.length = GUINT32_TO_LE(len); | |
718 header.unk1 = GUINT32_TO_LE(2); | |
719 header.file_size = GUINT32_TO_LE(size); | |
720 header.unk2 = GUINT32_TO_LE(0); | |
721 header.unk3 = GUINT32_TO_LE(0); | |
722 | |
723 base = g_malloc(len + 1); | |
724 n = base; | |
725 | |
726 memcpy(n, &header, sizeof(MsnContextHeader)); | |
727 n += sizeof(MsnContextHeader); | |
728 | |
729 memset(n, 0x00, MAX_FILE_NAME_LEN); | |
730 for(currentChar = 0; currentChar < uni_len; currentChar++) { | |
731 *((gunichar2 *)n + currentChar) = GUINT16_TO_LE(uni[currentChar]); | |
732 } | |
733 n += MAX_FILE_NAME_LEN; | |
734 | |
735 memset(n, 0xFF, 4); | |
736 n += 4; | |
737 | |
738 g_free(uni); | |
739 ret = purple_base64_encode(base, len); | |
740 g_free(base); | |
741 return ret; | |
742 } | |
743 | |
744 void | |
745 msn_slplink_request_ft(MsnSlpLink *slplink, PurpleXfer *xfer) | |
746 { | |
747 MsnSlpCall *slpcall; | |
748 char *context; | |
749 const char *fn; | |
750 const char *fp; | |
751 | |
752 fn = purple_xfer_get_filename(xfer); | |
753 fp = purple_xfer_get_local_filename(xfer); | |
754 | |
755 g_return_if_fail(slplink != NULL); | |
756 g_return_if_fail(fp != NULL); | |
757 | |
758 slpcall = msn_slp_call_new(slplink); | |
759 msn_slp_call_init(slpcall, MSN_SLPCALL_DC); | |
760 | |
761 slpcall->session_init_cb = send_file_cb; | |
762 slpcall->end_cb = msn_xfer_end_cb; | |
763 slpcall->progress_cb = msn_xfer_progress_cb; | |
764 slpcall->cb = msn_xfer_completed_cb; | |
765 slpcall->xfer = xfer; | |
766 purple_xfer_ref(slpcall->xfer); | |
767 | |
768 slpcall->pending = TRUE; | |
769 | |
770 purple_xfer_set_cancel_send_fnc(xfer, msn_xfer_cancel); | |
771 | |
772 xfer->data = slpcall; | |
773 | |
774 context = gen_context(fn, fp); | |
775 | |
776 msn_slp_call_invite(slpcall, "5D3E02AB-6190-11D3-BBBB-00C04F795683", 2, | |
777 context); | |
778 | |
779 g_free(context); | |
780 } | |
781 | |
782 void | |
783 msn_slplink_request_object(MsnSlpLink *slplink, | |
784 const char *info, | |
785 MsnSlpCb cb, | |
786 MsnSlpEndCb end_cb, | |
787 const MsnObject *obj) | |
788 { | |
789 MsnSlpCall *slpcall; | |
790 char *msnobj_data; | |
791 char *msnobj_base64; | |
792 | |
793 g_return_if_fail(slplink != NULL); | |
794 g_return_if_fail(obj != NULL); | |
795 | |
796 msnobj_data = msn_object_to_string(obj); | |
797 msnobj_base64 = purple_base64_encode((const guchar *)msnobj_data, strlen(msnobj_data)); | |
798 g_free(msnobj_data); | |
799 | |
800 slpcall = msn_slp_call_new(slplink); | |
801 msn_slp_call_init(slpcall, MSN_SLPCALL_ANY); | |
802 | |
803 slpcall->data_info = g_strdup(info); | |
804 slpcall->cb = cb; | |
805 slpcall->end_cb = end_cb; | |
806 | |
807 msn_slp_call_invite(slpcall, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6", 1, | |
808 msnobj_base64); | |
809 | |
810 g_free(msnobj_base64); | |
811 } |