comparison libpurple/protocols/msn/slpcall.c @ 31292:47b6eda87723

propagate from branch 'im.pidgin.pidgin' (head 07d0765c444a097af45c2650f54323afb900a07b) to branch 'im.pidgin.soc.2010.msn-tlc' (head f3998422a4724ab424e4e2328f58fc0504856557)
author masca@cpw.pidgin.im
date Mon, 19 Jul 2010 21:11:32 +0000
parents 7b1b7a4e0bb4
children 6814678f3c63
comparison
equal deleted inserted replaced
30698:e874875a74a7 31292:47b6eda87723
19 * 19 *
20 * You should have received a copy of the GNU General Public License 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 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 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 */ 23 */
24 #include "msn.h" 24
25 #include "internal.h"
26 #include "debug.h"
27 #include "smiley.h"
28
25 #include "msnutils.h" 29 #include "msnutils.h"
26 #include "slpcall.h" 30 #include "slpcall.h"
27 31
28 #include "slp.h" 32 #include "slp.h"
33 #include "p2p.h"
34 #include "xfer.h"
29 35
30 /************************************************************************** 36 /**************************************************************************
31 * Main 37 * Main
32 **************************************************************************/ 38 **************************************************************************/
33 39
138 slpcall->started = TRUE; 144 slpcall->started = TRUE;
139 } 145 }
140 146
141 void 147 void
142 msn_slpcall_invite(MsnSlpCall *slpcall, const char *euf_guid, 148 msn_slpcall_invite(MsnSlpCall *slpcall, const char *euf_guid,
143 int app_id, const char *context) 149 MsnP2PAppId app_id, const char *context)
144 { 150 {
145 MsnSlpLink *slplink; 151 MsnSlpLink *slplink;
146 MsnSlpMessage *slpmsg; 152 MsnSlpMessage *slpmsg;
147 char *header; 153 char *header;
148 char *content; 154 char *content;
188 send_bye(slpcall, "application/x-msnmsgr-sessionclosebody"); 194 send_bye(slpcall, "application/x-msnmsgr-sessionclosebody");
189 msn_slplink_send_queued_slpmsgs(slpcall->slplink); 195 msn_slplink_send_queued_slpmsgs(slpcall->slplink);
190 msn_slpcall_destroy(slpcall); 196 msn_slpcall_destroy(slpcall);
191 } 197 }
192 198
199 /*****************************************************************************
200 * Parse received SLP messages
201 ****************************************************************************/
202
203 /**************************************************************************
204 *** Util
205 **************************************************************************/
206
207 static char *
208 get_token(const char *str, const char *start, const char *end)
209 {
210 const char *c, *c2;
211
212 if ((c = strstr(str, start)) == NULL)
213 return NULL;
214
215 c += strlen(start);
216
217 if (end != NULL)
218 {
219 if ((c2 = strstr(c, end)) == NULL)
220 return NULL;
221
222 return g_strndup(c, c2 - c);
223 }
224 else
225 {
226 /* This has to be changed */
227 return g_strdup(c);
228 }
229
230 }
231
232 /* XXX: this could be improved if we tracked custom smileys
233 * per-protocol, per-account, per-session or (ideally) per-conversation
234 */
235 static PurpleStoredImage *
236 find_valid_emoticon(PurpleAccount *account, const char *path)
237 {
238 GList *smileys;
239
240 if (!purple_account_get_bool(account, "custom_smileys", TRUE))
241 return NULL;
242
243 smileys = purple_smileys_get_all();
244
245 for (; smileys; smileys = g_list_delete_link(smileys, smileys)) {
246 PurpleSmiley *smiley;
247 PurpleStoredImage *img;
248
249 smiley = smileys->data;
250 img = purple_smiley_get_stored_image(smiley);
251
252 if (purple_strequal(path, purple_imgstore_get_filename(img))) {
253 g_list_free(smileys);
254 return img;
255 }
256
257 purple_imgstore_unref(img);
258 }
259
260 purple_debug_error("msn", "Received illegal request for file %s\n", path);
261 return NULL;
262 }
263
264 static char *
265 parse_dc_nonce(const char *content, MsnDirectConnNonceType *ntype)
266 {
267 char *nonce;
268
269 *ntype = DC_NONCE_UNKNOWN;
270
271 nonce = get_token(content, "Hashed-Nonce: {", "}\r\n");
272 if (nonce) {
273 *ntype = DC_NONCE_SHA1;
274 } else {
275 guint32 n1, n6;
276 guint16 n2, n3, n4, n5;
277 nonce = get_token(content, "Nonce: {", "}\r\n");
278 if (nonce
279 && sscanf(nonce, "%08x-%04hx-%04hx-%04hx-%04hx%08x",
280 &n1, &n2, &n3, &n4, &n5, &n6) == 6) {
281 *ntype = DC_NONCE_PLAIN;
282 g_free(nonce);
283 nonce = g_malloc(16);
284 *(guint32 *)(nonce + 0) = GUINT32_TO_LE(n1);
285 *(guint16 *)(nonce + 4) = GUINT16_TO_LE(n2);
286 *(guint16 *)(nonce + 6) = GUINT16_TO_LE(n3);
287 *(guint16 *)(nonce + 8) = GUINT16_TO_BE(n4);
288 *(guint16 *)(nonce + 10) = GUINT16_TO_BE(n5);
289 *(guint32 *)(nonce + 12) = GUINT32_TO_BE(n6);
290 } else {
291 /* Invalid nonce, so ignore request */
292 g_free(nonce);
293 nonce = NULL;
294 }
295 }
296
297 return nonce;
298 }
299
300 static void
301 msn_slp_process_transresp(MsnSlpCall *slpcall, const char *content)
302 {
303 /* A direct connection negotiation response */
304 char *bridge;
305 char *nonce;
306 char *listening;
307 MsnDirectConn *dc = slpcall->slplink->dc;
308 MsnDirectConnNonceType ntype;
309
310 purple_debug_info("msn", "process_transresp\n");
311
312 /* Direct connections are disabled. */
313 if (!purple_account_get_bool(slpcall->slplink->session->account, "direct_connect", TRUE))
314 return;
315
316 g_return_if_fail(dc != NULL);
317 g_return_if_fail(dc->state == DC_STATE_CLOSED);
318
319 bridge = get_token(content, "Bridge: ", "\r\n");
320 nonce = parse_dc_nonce(content, &ntype);
321 listening = get_token(content, "Listening: ", "\r\n");
322 if (listening && bridge && !strcmp(bridge, "TCPv1")) {
323 /* Ok, the client supports direct TCP connection */
324
325 /* We always need this. */
326 if (ntype == DC_NONCE_SHA1) {
327 strncpy(dc->remote_nonce, nonce, 36);
328 dc->remote_nonce[36] = '\0';
329 }
330
331 if (!strcasecmp(listening, "false")) {
332 if (dc->listen_data != NULL) {
333 /*
334 * We'll listen for incoming connections but
335 * the listening socket isn't ready yet so we cannot
336 * send the INVITE packet now. Put the slpcall into waiting mode
337 * and let the callback send the invite.
338 */
339 slpcall->wait_for_socket = TRUE;
340
341 } else if (dc->listenfd != -1) {
342 /* The listening socket is ready. Send the INVITE here. */
343 msn_dc_send_invite(dc);
344
345 } else {
346 /* We weren't able to create a listener either. Use SB. */
347 msn_dc_fallback_to_sb(dc);
348 }
349
350 } else {
351 /*
352 * We should connect to the client so parse
353 * IP/port from response.
354 */
355 char *ip, *port_str;
356 int port = 0;
357
358 if (ntype == DC_NONCE_PLAIN) {
359 /* Only needed for listening side. */
360 memcpy(dc->nonce, nonce, 16);
361 }
362
363 /* Cancel any listen attempts because we don't need them. */
364 if (dc->listenfd_handle != 0) {
365 purple_input_remove(dc->listenfd_handle);
366 dc->listenfd_handle = 0;
367 }
368 if (dc->connect_timeout_handle != 0) {
369 purple_timeout_remove(dc->connect_timeout_handle);
370 dc->connect_timeout_handle = 0;
371 }
372 if (dc->listenfd != -1) {
373 purple_network_remove_port_mapping(dc->listenfd);
374 close(dc->listenfd);
375 dc->listenfd = -1;
376 }
377 if (dc->listen_data != NULL) {
378 purple_network_listen_cancel(dc->listen_data);
379 dc->listen_data = NULL;
380 }
381
382 /* Save external IP/port for later use. We'll try local connection first. */
383 dc->ext_ip = get_token(content, "IPv4External-Addrs: ", "\r\n");
384 port_str = get_token(content, "IPv4External-Port: ", "\r\n");
385 if (port_str) {
386 dc->ext_port = atoi(port_str);
387 g_free(port_str);
388 }
389
390 ip = get_token(content, "IPv4Internal-Addrs: ", "\r\n");
391 port_str = get_token(content, "IPv4Internal-Port: ", "\r\n");
392 if (port_str) {
393 port = atoi(port_str);
394 g_free(port_str);
395 }
396
397 if (ip && port) {
398 /* Try internal address first */
399 dc->connect_data = purple_proxy_connect(
400 NULL,
401 slpcall->slplink->session->account,
402 ip,
403 port,
404 msn_dc_connected_to_peer_cb,
405 dc
406 );
407
408 if (dc->connect_data) {
409 /* Add connect timeout handle */
410 dc->connect_timeout_handle = purple_timeout_add_seconds(
411 DC_OUTGOING_TIMEOUT,
412 msn_dc_outgoing_connection_timeout_cb,
413 dc
414 );
415 } else {
416 /*
417 * Connection failed
418 * Try external IP/port (if specified)
419 */
420 msn_dc_outgoing_connection_timeout_cb(dc);
421 }
422
423 } else {
424 /*
425 * Omitted or invalid internal IP address / port
426 * Try external IP/port (if specified)
427 */
428 msn_dc_outgoing_connection_timeout_cb(dc);
429 }
430
431 g_free(ip);
432 }
433
434 } else {
435 /*
436 * Invalid direct connect invitation or
437 * TCP connection is not supported
438 */
439 }
440
441 g_free(listening);
442 g_free(nonce);
443 g_free(bridge);
444
445 return;
446 }
447
448 static void
449 got_sessionreq(MsnSlpCall *slpcall, const char *branch,
450 const char *euf_guid, const char *context)
451 {
452 gboolean accepted = FALSE;
453
454 if (!strcmp(euf_guid, MSN_OBJ_GUID))
455 {
456 /* Emoticon or UserDisplay */
457 char *content;
458 gsize len;
459 MsnSlpLink *slplink;
460 MsnSlpMessage *slpmsg;
461 MsnObject *obj;
462 char *msnobj_data;
463 PurpleStoredImage *img = NULL;
464 int type;
465
466 /* Send Ok */
467 content = g_strdup_printf("SessionID: %lu\r\n\r\n",
468 slpcall->session_id);
469
470 msn_slp_send_ok(slpcall, branch, "application/x-msnmsgr-sessionreqbody",
471 content);
472
473 g_free(content);
474
475 slplink = slpcall->slplink;
476
477 msnobj_data = (char *)purple_base64_decode(context, &len);
478 obj = msn_object_new_from_string(msnobj_data);
479 type = msn_object_get_type(obj);
480 g_free(msnobj_data);
481 if (type == MSN_OBJECT_EMOTICON) {
482 img = find_valid_emoticon(slplink->session->account, obj->location);
483 } else if (type == MSN_OBJECT_USERTILE) {
484 img = msn_object_get_image(obj);
485 if (img)
486 purple_imgstore_ref(img);
487 }
488 msn_object_destroy(obj);
489
490 if (img != NULL) {
491 /* DATA PREP */
492 slpmsg = msn_slpmsg_dataprep_new(slpcall);
493 msn_slpmsg_set_slplink(slpmsg, slplink);
494 msn_slplink_queue_slpmsg(slplink, slpmsg);
495
496 /* DATA */
497 slpmsg = msn_slpmsg_obj_new(slpcall, img);
498 msn_slpmsg_set_slplink(slpmsg, slplink);
499 msn_slplink_queue_slpmsg(slplink, slpmsg);
500 purple_imgstore_unref(img);
501
502 accepted = TRUE;
503
504 } else {
505 purple_debug_error("msn", "Wrong object.\n");
506 }
507 }
508
509 else if (!strcmp(euf_guid, MSN_FT_GUID))
510 {
511 /* File Transfer */
512 PurpleAccount *account;
513 PurpleXfer *xfer;
514 MsnFileContext *header;
515 gsize bin_len;
516 guint32 file_size;
517 char *file_name;
518
519 account = slpcall->slplink->session->account;
520
521 slpcall->end_cb = msn_xfer_end_cb;
522 slpcall->branch = g_strdup(branch);
523
524 slpcall->pending = TRUE;
525
526 xfer = purple_xfer_new(account, PURPLE_XFER_RECEIVE,
527 slpcall->slplink->remote_user);
528
529 header = (MsnFileContext *)purple_base64_decode(context, &bin_len);
530 if (bin_len >= sizeof(MsnFileContext) - 1 &&
531 (header->version == 2 ||
532 (header->version == 3 && header->length == sizeof(MsnFileContext) + 63))) {
533 file_size = GUINT64_FROM_LE(header->file_size);
534
535 file_name = g_convert((const gchar *)&header->file_name,
536 MAX_FILE_NAME_LEN * 2,
537 "UTF-8", "UTF-16LE",
538 NULL, NULL, NULL);
539
540 purple_xfer_set_filename(xfer, file_name ? file_name : "");
541 g_free(file_name);
542 purple_xfer_set_size(xfer, file_size);
543 purple_xfer_set_init_fnc(xfer, msn_xfer_init);
544 purple_xfer_set_request_denied_fnc(xfer, msn_xfer_cancel);
545 purple_xfer_set_cancel_recv_fnc(xfer, msn_xfer_cancel);
546 purple_xfer_set_read_fnc(xfer, msn_xfer_read);
547 purple_xfer_set_write_fnc(xfer, msn_xfer_write);
548
549 slpcall->u.incoming_data = g_byte_array_new();
550
551 slpcall->xfer = xfer;
552 purple_xfer_ref(slpcall->xfer);
553
554 xfer->data = slpcall;
555
556 if (header->type == 0 && bin_len >= sizeof(MsnFileContext)) {
557 purple_xfer_set_thumbnail(xfer, &header->preview,
558 bin_len - sizeof(MsnFileContext),
559 "image/png");
560 }
561
562 purple_xfer_request(xfer);
563 }
564 g_free(header);
565
566 accepted = TRUE;
567
568 } else if (!strcmp(euf_guid, MSN_CAM_REQUEST_GUID)) {
569 purple_debug_info("msn", "Cam request.\n");
570 if (slpcall && slpcall->slplink &&
571 slpcall->slplink->session) {
572 PurpleConversation *conv;
573 gchar *from = slpcall->slplink->remote_user;
574 conv = purple_find_conversation_with_account(
575 PURPLE_CONV_TYPE_IM, from,
576 slpcall->slplink->session->account);
577 if (conv) {
578 char *buf;
579 buf = g_strdup_printf(
580 _("%s requests to view your "
581 "webcam, but this request is "
582 "not yet supported."), from);
583 purple_conversation_write(conv, NULL, buf,
584 PURPLE_MESSAGE_SYSTEM |
585 PURPLE_MESSAGE_NOTIFY,
586 time(NULL));
587 g_free(buf);
588 }
589 }
590
591 } else if (!strcmp(euf_guid, MSN_CAM_GUID)) {
592 purple_debug_info("msn", "Cam invite.\n");
593 if (slpcall && slpcall->slplink &&
594 slpcall->slplink->session) {
595 PurpleConversation *conv;
596 gchar *from = slpcall->slplink->remote_user;
597 conv = purple_find_conversation_with_account(
598 PURPLE_CONV_TYPE_IM, from,
599 slpcall->slplink->session->account);
600 if (conv) {
601 char *buf;
602 buf = g_strdup_printf(
603 _("%s invited you to view his/her webcam, but "
604 "this is not yet supported."), from);
605 purple_conversation_write(conv, NULL, buf,
606 PURPLE_MESSAGE_SYSTEM |
607 PURPLE_MESSAGE_NOTIFY,
608 time(NULL));
609 g_free(buf);
610 }
611 }
612
613 } else
614 purple_debug_warning("msn", "SLP SessionReq with unknown EUF-GUID: %s\n", euf_guid);
615
616 if (!accepted) {
617 char *content = g_strdup_printf("SessionID: %lu\r\n\r\n",
618 slpcall->session_id);
619 msn_slp_send_decline(slpcall, branch, "application/x-msnmsgr-sessionreqbody", content);
620 g_free(content);
621 }
622 }
623
624 void
625 send_bye(MsnSlpCall *slpcall, const char *type)
626 {
627 MsnSlpLink *slplink;
628 PurpleAccount *account;
629 MsnSlpMessage *slpmsg;
630 char *header;
631
632 slplink = slpcall->slplink;
633
634 g_return_if_fail(slplink != NULL);
635
636 account = slplink->session->account;
637
638 header = g_strdup_printf("BYE MSNMSGR:%s MSNSLP/1.0",
639 purple_account_get_username(account));
640
641 slpmsg = msn_slpmsg_sip_new(slpcall, 0, header,
642 "A0D624A6-6C0C-4283-A9E0-BC97B4B46D32",
643 type,
644 "\r\n");
645 g_free(header);
646
647 slpmsg->info = "SLP BYE";
648 slpmsg->text_body = TRUE;
649
650 msn_slplink_queue_slpmsg(slplink, slpmsg);
651 }
652
653 static void
654 got_invite(MsnSlpCall *slpcall,
655 const char *branch, const char *type, const char *content)
656 {
657 MsnSlpLink *slplink;
658
659 slplink = slpcall->slplink;
660
661 if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
662 {
663 char *euf_guid, *context;
664 char *temp;
665
666 euf_guid = get_token(content, "EUF-GUID: {", "}\r\n");
667
668 temp = get_token(content, "SessionID: ", "\r\n");
669 if (temp != NULL)
670 slpcall->session_id = atoi(temp);
671 g_free(temp);
672
673 temp = get_token(content, "AppID: ", "\r\n");
674 if (temp != NULL)
675 slpcall->app_id = atoi(temp);
676 g_free(temp);
677
678 context = get_token(content, "Context: ", "\r\n");
679
680 if (context != NULL)
681 got_sessionreq(slpcall, branch, euf_guid, context);
682
683 g_free(context);
684 g_free(euf_guid);
685 }
686 else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
687 {
688 /* A direct connection negotiation request */
689 char *bridges;
690 char *nonce;
691 MsnDirectConnNonceType ntype;
692
693 purple_debug_info("msn", "got_invite: transreqbody received\n");
694
695 /* Direct connections may be disabled. */
696 if (!purple_account_get_bool(slplink->session->account, "direct_connect", TRUE)) {
697 msn_slp_send_ok(slpcall, branch,
698 "application/x-msnmsgr-transrespbody",
699 "Bridge: TCPv1\r\n"
700 "Listening: false\r\n"
701 "Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
702 "\r\n");
703 msn_slpcall_session_init(slpcall);
704
705 return;
706 }
707
708 /* Don't do anything if we already have a direct connection */
709 if (slplink->dc != NULL)
710 return;
711
712 bridges = get_token(content, "Bridges: ", "\r\n");
713 nonce = parse_dc_nonce(content, &ntype);
714 if (bridges && strstr(bridges, "TCPv1") != NULL) {
715 /*
716 * Ok, the client supports direct TCP connection
717 * Try to create a listening port
718 */
719 MsnDirectConn *dc;
720
721 dc = msn_dc_new(slpcall);
722 if (ntype == DC_NONCE_PLAIN) {
723 /* There is only one nonce for plain auth. */
724 dc->nonce_type = ntype;
725 memcpy(dc->nonce, nonce, 16);
726 } else if (ntype == DC_NONCE_SHA1) {
727 /* Each side has a nonce in SHA1 auth. */
728 dc->nonce_type = ntype;
729 strncpy(dc->remote_nonce, nonce, 36);
730 dc->remote_nonce[36] = '\0';
731 }
732
733 dc->listen_data = purple_network_listen_range(
734 0, 0,
735 SOCK_STREAM,
736 msn_dc_listen_socket_created_cb,
737 dc
738 );
739
740 if (dc->listen_data == NULL) {
741 /* Listen socket creation failed */
742
743 purple_debug_info("msn", "got_invite: listening failed\n");
744
745 if (dc->nonce_type != DC_NONCE_PLAIN)
746 msn_slp_send_ok(slpcall, branch,
747 "application/x-msnmsgr-transrespbody",
748 "Bridge: TCPv1\r\n"
749 "Listening: false\r\n"
750 "Hashed-Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
751 "\r\n");
752 else
753 msn_slp_send_ok(slpcall, branch,
754 "application/x-msnmsgr-transrespbody",
755 "Bridge: TCPv1\r\n"
756 "Listening: false\r\n"
757 "Nonce: {00000000-0000-0000-0000-000000000000}\r\n"
758 "\r\n");
759
760 } else {
761 /*
762 * Listen socket created successfully.
763 * Don't send anything here because we don't know the parameters
764 * of the created socket yet. msn_dc_send_ok will be called from
765 * the callback function: dc_listen_socket_created_cb
766 */
767 purple_debug_info("msn", "got_invite: listening socket created\n");
768
769 dc->send_connection_info_msg_cb = msn_dc_send_ok;
770 slpcall->wait_for_socket = TRUE;
771 }
772
773 } else {
774 /*
775 * Invalid direct connect invitation or
776 * TCP connection is not supported.
777 */
778 }
779
780 g_free(nonce);
781 g_free(bridges);
782 }
783 else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
784 {
785 /* A direct connection negotiation response */
786 msn_slp_process_transresp(slpcall, content);
787 }
788 }
789
790 static void
791 got_ok(MsnSlpCall *slpcall,
792 const char *type, const char *content)
793 {
794 g_return_if_fail(slpcall != NULL);
795 g_return_if_fail(type != NULL);
796
797 if (!strcmp(type, "application/x-msnmsgr-sessionreqbody"))
798 {
799 char *content;
800 char *header;
801 char *nonce = NULL;
802 MsnSession *session = slpcall->slplink->session;
803 MsnSlpMessage *msg;
804 MsnDirectConn *dc;
805 MsnUser *user;
806
807 if (!purple_account_get_bool(session->account, "direct_connect", TRUE)) {
808 /* Don't attempt a direct connection if disabled. */
809 msn_slpcall_session_init(slpcall);
810 return;
811 }
812
813 if (slpcall->slplink->dc != NULL) {
814 /* If we already have an established direct connection
815 * then just start the transfer.
816 */
817 msn_slpcall_session_init(slpcall);
818 return;
819 }
820
821 user = msn_userlist_find_user(session->userlist,
822 slpcall->slplink->remote_user);
823 if (!user || !(user->clientid & 0xF0000000)) {
824 /* Just start a normal SB transfer. */
825 msn_slpcall_session_init(slpcall);
826 return;
827 }
828
829 /* Try direct file transfer by sending a second INVITE */
830 dc = msn_dc_new(slpcall);
831 slpcall->branch = rand_guid();
832
833 dc->listen_data = purple_network_listen_range(
834 0, 0,
835 SOCK_STREAM,
836 msn_dc_listen_socket_created_cb,
837 dc
838 );
839
840 header = g_strdup_printf(
841 "INVITE MSNMSGR:%s MSNSLP/1.0",
842 slpcall->slplink->remote_user
843 );
844
845 if (dc->nonce_type == DC_NONCE_SHA1)
846 nonce = g_strdup_printf("Hashed-Nonce: {%s}\r\n", dc->nonce_hash);
847
848 if (dc->listen_data == NULL) {
849 /* Listen socket creation failed */
850 purple_debug_info("msn", "got_ok: listening failed\n");
851
852 content = g_strdup_printf(
853 "Bridges: TCPv1\r\n"
854 "NetID: %u\r\n"
855 "Conn-Type: IP-Restrict-NAT\r\n"
856 "UPnPNat: false\r\n"
857 "ICF: false\r\n"
858 "%s"
859 "\r\n",
860
861 rand() % G_MAXUINT32,
862 nonce ? nonce : ""
863 );
864
865 } else {
866 /* Listen socket created successfully. */
867 purple_debug_info("msn", "got_ok: listening socket created\n");
868
869 content = g_strdup_printf(
870 "Bridges: TCPv1\r\n"
871 "NetID: 0\r\n"
872 "Conn-Type: Direct-Connect\r\n"
873 "UPnPNat: false\r\n"
874 "ICF: false\r\n"
875 "%s"
876 "\r\n",
877
878 nonce ? nonce : ""
879 );
880 }
881
882 msg = msn_slpmsg_sip_new(
883 slpcall,
884 0,
885 header,
886 slpcall->branch,
887 "application/x-msnmsgr-transreqbody",
888 content
889 );
890 msg->info = "DC INVITE";
891 msg->text_body = TRUE;
892 g_free(nonce);
893 g_free(header);
894 g_free(content);
895
896 msn_slplink_queue_slpmsg(slpcall->slplink, msg);
897 }
898 else if (!strcmp(type, "application/x-msnmsgr-transreqbody"))
899 {
900 /* Do we get this? */
901 purple_debug_info("msn", "OK with transreqbody\n");
902 }
903 else if (!strcmp(type, "application/x-msnmsgr-transrespbody"))
904 {
905 msn_slp_process_transresp(slpcall, content);
906 }
907 }
908
909 static void
910 got_error(MsnSlpCall *slpcall,
911 const char *error, const char *type, const char *content)
912 {
913 /* It's not valid. Kill this off. */
914 purple_debug_error("msn", "Received non-OK result: %s\n",
915 error ? error : "Unknown");
916
917 if (type && !strcmp(type, "application/x-msnmsgr-transreqbody")) {
918 MsnDirectConn *dc = slpcall->slplink->dc;
919 if (dc) {
920 msn_dc_fallback_to_sb(dc);
921 return;
922 }
923 }
924
925 slpcall->wasted = TRUE;
926 }
927
928 static MsnSlpCall *
929 msn_slp_sip_recv(MsnSlpLink *slplink, const char *body)
930 {
931 MsnSlpCall *slpcall;
932
933 if (body == NULL)
934 {
935 purple_debug_warning("msn", "received bogus message\n");
936 return NULL;
937 }
938
939 if (!strncmp(body, "INVITE", strlen("INVITE")))
940 {
941 /* This is an INVITE request */
942 char *branch;
943 char *call_id;
944 char *content;
945 char *content_type;
946
947 /* From: <msnmsgr:buddy@hotmail.com> */
948 #if 0
949 slpcall->remote_user = get_token(body, "From: <msnmsgr:", ">\r\n");
950 #endif
951
952 branch = get_token(body, ";branch={", "}");
953
954 call_id = get_token(body, "Call-ID: {", "}");
955
956 #if 0
957 long content_len = -1;
958
959 temp = get_token(body, "Content-Length: ", "\r\n");
960 if (temp != NULL)
961 content_len = atoi(temp);
962 g_free(temp);
963 #endif
964 content_type = get_token(body, "Content-Type: ", "\r\n");
965
966 content = get_token(body, "\r\n\r\n", NULL);
967
968 slpcall = NULL;
969 if (branch && call_id)
970 {
971 slpcall = msn_slplink_find_slp_call(slplink, call_id);
972 if (slpcall)
973 {
974 g_free(slpcall->branch);
975 slpcall->branch = g_strdup(branch);
976 got_invite(slpcall, branch, content_type, content);
977 }
978 else if (content_type && content)
979 {
980 slpcall = msn_slpcall_new(slplink);
981 slpcall->id = g_strdup(call_id);
982 got_invite(slpcall, branch, content_type, content);
983 }
984 }
985
986 g_free(call_id);
987 g_free(branch);
988 g_free(content_type);
989 g_free(content);
990 }
991 else if (!strncmp(body, "MSNSLP/1.0 ", strlen("MSNSLP/1.0 ")))
992 {
993 /* This is a response */
994 char *content;
995 char *content_type;
996 /* Make sure this is "OK" */
997 const char *status = body + strlen("MSNSLP/1.0 ");
998 char *call_id;
999
1000 call_id = get_token(body, "Call-ID: {", "}");
1001 slpcall = msn_slplink_find_slp_call(slplink, call_id);
1002 g_free(call_id);
1003
1004 g_return_val_if_fail(slpcall != NULL, NULL);
1005
1006 content_type = get_token(body, "Content-Type: ", "\r\n");
1007
1008 content = get_token(body, "\r\n\r\n", NULL);
1009
1010 if (strncmp(status, "200 OK", 6))
1011 {
1012 char *error = NULL;
1013 const char *c;
1014
1015 /* Eww */
1016 if ((c = strchr(status, '\r')) || (c = strchr(status, '\n')) ||
1017 (c = strchr(status, '\0')))
1018 {
1019 size_t len = c - status;
1020 error = g_strndup(status, len);
1021 }
1022
1023 got_error(slpcall, error, content_type, content);
1024 g_free(error);
1025
1026 } else {
1027 /* Everything's just dandy */
1028 got_ok(slpcall, content_type, content);
1029 }
1030
1031 g_free(content_type);
1032 g_free(content);
1033 }
1034 else if (!strncmp(body, "BYE", strlen("BYE")))
1035 {
1036 /* This is a BYE request */
1037 char *call_id;
1038
1039 call_id = get_token(body, "Call-ID: {", "}");
1040 slpcall = msn_slplink_find_slp_call(slplink, call_id);
1041 g_free(call_id);
1042
1043 if (slpcall != NULL)
1044 slpcall->wasted = TRUE;
1045
1046 /* msn_slpcall_destroy(slpcall); */
1047 }
1048 else
1049 slpcall = NULL;
1050
1051 return slpcall;
1052 }
1053
193 MsnSlpCall * 1054 MsnSlpCall *
194 msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg) 1055 msn_slp_process_msg(MsnSlpLink *slplink, MsnSlpMessage *slpmsg)
195 { 1056 {
196 MsnSlpCall *slpcall; 1057 MsnSlpCall *slpcall;
197 const guchar *body; 1058 const guchar *body;
199 1060
200 slpcall = NULL; 1061 slpcall = NULL;
201 body = slpmsg->buffer; 1062 body = slpmsg->buffer;
202 body_len = slpmsg->offset; 1063 body_len = slpmsg->offset;
203 1064
204 if (slpmsg->flags == 0x0 || slpmsg->flags == 0x1000000) 1065 if (slpmsg->flags == P2P_NO_FLAG || slpmsg->flags == P2P_WML2009_COMP)
205 { 1066 {
206 char *body_str; 1067 char *body_str;
207 1068
208 if (slpmsg->session_id == 64) 1069 if (slpmsg->session_id == 64)
209 { 1070 {
260 body_str = g_strndup((const char *)body, body_len); 1121 body_str = g_strndup((const char *)body, body_len);
261 slpcall = msn_slp_sip_recv(slplink, body_str); 1122 slpcall = msn_slp_sip_recv(slplink, body_str);
262 } 1123 }
263 g_free(body_str); 1124 g_free(body_str);
264 } 1125 }
265 else if (slpmsg->flags == 0x20 || 1126 else if (slpmsg->flags == P2P_MSN_OBJ_DATA ||
266 slpmsg->flags == 0x1000020 || 1127 slpmsg->flags == (P2P_WML2009_COMP | P2P_MSN_OBJ_DATA) ||
267 slpmsg->flags == 0x1000030) 1128 slpmsg->flags == P2P_FILE_DATA)
268 { 1129 {
269 slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id); 1130 slpcall = msn_slplink_find_slp_call_with_session_id(slplink, slpmsg->session_id);
270 1131
271 if (slpcall != NULL) 1132 if (slpcall != NULL)
272 { 1133 {
288 1149
289 if (slpcall != NULL) 1150 if (slpcall != NULL)
290 msn_slpcall_session_init(slpcall); 1151 msn_slpcall_session_init(slpcall);
291 } 1152 }
292 #endif 1153 #endif
293 else if (slpmsg->flags == 0x2) 1154 else if (slpmsg->flags == P2P_ACK)
294 { 1155 {
295 /* Acknowledgement of previous message. Don't do anything currently. */ 1156 /* Acknowledgement of previous message. Don't do anything currently. */
296 } 1157 }
297 else 1158 else
298 purple_debug_warning("msn", "Unprocessed SLP message with flags 0x%08lx\n", 1159 purple_debug_warning("msn", "Unprocessed SLP message with flags 0x%08lx\n",