Changes in protocols/msn/ns.c [fd424c8:70ac477]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/ns.c
rfd424c8 r70ac477 2 2 * BitlBee -- An IRC to other IM-networks gateway * 3 3 * * 4 * Copyright 2002-20 10Wilmer van der Gaast and others *4 * Copyright 2002-2004 Wilmer van der Gaast and others * 5 5 \********************************************************************/ 6 6 … … 27 27 #include "nogaim.h" 28 28 #include "msn.h" 29 #include "passport.h" 29 30 #include "md5.h" 30 #include "soap.h"31 #include "xmltree.h"32 31 33 32 static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); … … 35 34 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); 36 35 37 static void msn_ ns_send_adl_start( struct im_connection *ic);38 static void msn_ns_send_adl( struct im_connection *ic);36 static void msn_auth_got_passport_token( struct msn_auth_data *mad ); 37 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ); 39 38 40 39 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) … … 74 73 md->handler->rxq = g_new0( char, 1 ); 75 74 76 g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER);75 g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); 77 76 if( msn_write( ic, s, strlen( s ) ) ) 78 77 { … … 114 113 if( strcmp( cmd[0], "VER" ) == 0 ) 115 114 { 116 if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )115 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 ) 117 116 { 118 117 imcb_error( ic, "Unsupported protocol" ); … … 128 127 { 129 128 /* We don't give a damn about the information we just received */ 130 g_snprintf( buf, sizeof( buf ), "USR %d SSOI %s\r\n", ++md->trId, ic->acc->user );129 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); 131 130 return( msn_write( ic, buf, strlen( buf ) ) ); 132 131 } … … 136 135 int port; 137 136 138 if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 )137 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) 139 138 { 140 139 b_event_remove( ic->inpa ); … … 157 156 md->fd = proxy_connect( server, port, msn_ns_connected, ic ); 158 157 } 159 else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 )158 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 ) 160 159 { 161 160 struct msn_switchboard *sb; … … 221 220 else if( strcmp( cmd[0], "USR" ) == 0 ) 222 221 { 223 if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 && 224 strcmp( cmd[3], "S" ) == 0 ) 225 { 226 msn_soap_passport_sso_request( ic, cmd[4], cmd[5] ); 227 } 228 else if( strcmp( cmd[2], "OK" ) == 0 ) 229 { 222 if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) 223 { 224 /* Time for some Passport black magic... */ 225 if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) 226 { 227 imcb_error( ic, "Error while contacting Passport server" ); 228 imc_logout( ic, TRUE ); 229 return( 0 ); 230 } 231 } 232 else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 ) 233 { 234 if( num_parts == 7 ) 235 msn_ns_got_display_name( ic, cmd[4] ); 236 else 237 imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); 238 230 239 imcb_log( ic, "Authenticated, getting buddy list" ); 231 msn_soap_memlist_request( ic ); 240 241 g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); 242 return( msn_write( ic, buf, strlen( buf ) ) ); 232 243 } 233 244 else … … 240 251 else if( strcmp( cmd[0], "MSG" ) == 0 ) 241 252 { 242 if( num_parts <4 )253 if( num_parts != 4 ) 243 254 { 244 255 imcb_error( ic, "Syntax error" ); … … 256 267 } 257 268 } 258 else if( strcmp( cmd[0], "BLP" ) == 0 ) 259 { 260 msn_ns_send_adl_start( ic ); 261 return msn_ns_finish_login( ic ); 262 } 263 else if( strcmp( cmd[0], "ADL" ) == 0 ) 264 { 265 if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 ) 266 { 267 msn_ns_send_adl( ic ); 268 return msn_ns_finish_login( ic ); 269 } 270 else if( num_parts >= 3 ) 271 { 272 md->handler->msglen = atoi( cmd[2] ); 273 } 274 } 275 else if( strcmp( cmd[0], "PRP" ) == 0 ) 276 { 277 imcb_connected( ic ); 269 else if( strcmp( cmd[0], "SYN" ) == 0 ) 270 { 271 if( num_parts == 5 ) 272 { 273 int i, groupcount; 274 275 groupcount = atoi( cmd[4] ); 276 if( groupcount > 0 ) 277 { 278 /* valgrind says this is leaking memory, I'm guessing 279 that this happens during server redirects. */ 280 if( md->grouplist ) 281 { 282 for( i = 0; i < md->groupcount; i ++ ) 283 g_free( md->grouplist[i] ); 284 g_free( md->grouplist ); 285 } 286 287 md->groupcount = groupcount; 288 md->grouplist = g_new0( char *, md->groupcount ); 289 } 290 291 md->buddycount = atoi( cmd[3] ); 292 if( !*cmd[3] || md->buddycount == 0 ) 293 msn_logged_in( ic ); 294 } 295 else 296 { 297 /* Hrrm... This SYN reply doesn't really look like something we expected. 298 Let's assume everything is okay. */ 299 300 msn_logged_in( ic ); 301 } 302 } 303 else if( strcmp( cmd[0], "LST" ) == 0 ) 304 { 305 int list; 306 307 if( num_parts != 4 && num_parts != 5 ) 308 { 309 imcb_error( ic, "Syntax error" ); 310 imc_logout( ic, TRUE ); 311 return( 0 ); 312 } 313 314 http_decode( cmd[2] ); 315 list = atoi( cmd[3] ); 316 317 if( list & 1 ) /* FL */ 318 { 319 char *group = NULL; 320 int num; 321 322 if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount ) 323 group = md->grouplist[num]; 324 325 imcb_add_buddy( ic, cmd[1], group ); 326 imcb_rename_buddy( ic, cmd[1], cmd[2] ); 327 } 328 if( list & 2 ) /* AL */ 329 { 330 ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) ); 331 } 332 if( list & 4 ) /* BL */ 333 { 334 ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) ); 335 } 336 if( list & 8 ) /* RL */ 337 { 338 if( ( list & 6 ) == 0 ) 339 msn_buddy_ask( ic, cmd[1], cmd[2] ); 340 } 341 342 if( --md->buddycount == 0 ) 343 { 344 if( ic->flags & OPT_LOGGED_IN ) 345 { 346 imcb_log( ic, "Successfully transferred to different server" ); 347 g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); 348 return( msn_write( ic, buf, strlen( buf ) ) ); 349 } 350 else 351 { 352 msn_logged_in( ic ); 353 } 354 } 355 } 356 else if( strcmp( cmd[0], "LSG" ) == 0 ) 357 { 358 int num; 359 360 if( num_parts != 4 ) 361 { 362 imcb_error( ic, "Syntax error" ); 363 imc_logout( ic, TRUE ); 364 return( 0 ); 365 } 366 367 http_decode( cmd[2] ); 368 num = atoi( cmd[1] ); 369 370 if( num < md->groupcount ) 371 md->grouplist[num] = g_strdup( cmd[2] ); 278 372 } 279 373 else if( strcmp( cmd[0], "CHL" ) == 0 ) 280 374 { 281 char *resp; 282 283 if( num_parts < 3 ) 284 { 285 imcb_error( ic, "Syntax error" ); 286 imc_logout( ic, TRUE ); 287 return( 0 ); 288 } 289 290 resp = msn_p11_challenge( cmd[2] ); 291 g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s", 292 ++md->trId, MSNP11_PROD_ID, 293 strlen( resp ), resp ); 294 g_free( resp ); 375 md5_state_t state; 376 md5_byte_t digest[16]; 377 int i; 378 379 if( num_parts != 3 ) 380 { 381 imcb_error( ic, "Syntax error" ); 382 imc_logout( ic, TRUE ); 383 return( 0 ); 384 } 385 386 md5_init( &state ); 387 md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) ); 388 md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) ); 389 md5_finish( &state, digest ); 390 391 g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 ); 392 for( i = 0; i < 16; i ++ ) 393 g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); 295 394 296 395 return( msn_write( ic, buf, strlen( buf ) ) ); … … 300 399 const struct msn_away_state *st; 301 400 302 if( num_parts <6 )303 { 304 imcb_error( ic, "Syntax error" ); 305 imc_logout( ic, TRUE ); 306 return( 0 ); 307 } 308 309 http_decode( cmd[ 5] );310 imcb_rename_buddy( ic, cmd[3], cmd[ 5] );401 if( num_parts != 6 ) 402 { 403 imcb_error( ic, "Syntax error" ); 404 imc_logout( ic, TRUE ); 405 return( 0 ); 406 } 407 408 http_decode( cmd[4] ); 409 imcb_rename_buddy( ic, cmd[3], cmd[4] ); 311 410 312 411 st = msn_away_state_by_code( cmd[2] ); … … 333 432 { 334 433 const struct msn_away_state *st; 335 int cap; 336 337 if( num_parts < 6 ) 338 { 339 imcb_error( ic, "Syntax error" ); 340 imc_logout( ic, TRUE ); 341 return( 0 ); 342 } 343 344 http_decode( cmd[4] ); 345 cap = atoi( cmd[5] ); 346 imcb_rename_buddy( ic, cmd[2], cmd[4] ); 434 435 if( num_parts != 5 ) 436 { 437 imcb_error( ic, "Syntax error" ); 438 imc_logout( ic, TRUE ); 439 return( 0 ); 440 } 441 442 http_decode( cmd[3] ); 443 imcb_rename_buddy( ic, cmd[2], cmd[3] ); 347 444 348 445 st = msn_away_state_by_code( cmd[1] ); … … 354 451 355 452 imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | 356 ( st != msn_away_state_list ? OPT_AWAY : 0 ) | 357 ( cap & 1 ? OPT_MOBILE : 0 ), 453 ( st != msn_away_state_list ? OPT_AWAY : 0 ), 358 454 st->name, NULL ); 359 455 … … 366 462 int session, port; 367 463 368 if( num_parts <7 )464 if( num_parts != 7 ) 369 465 { 370 466 imcb_error( ic, "Syntax error" ); … … 408 504 } 409 505 } 506 else if( strcmp( cmd[0], "ADD" ) == 0 ) 507 { 508 if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 ) 509 { 510 GSList *l; 511 512 http_decode( cmd[5] ); 513 514 if( strchr( cmd[4], '@' ) == NULL ) 515 { 516 imcb_error( ic, "Syntax error" ); 517 imc_logout( ic, TRUE ); 518 return 0; 519 } 520 521 /* We got added by someone. If we don't have this 522 person in permit/deny yet, inform the user. */ 523 for( l = ic->permit; l; l = l->next ) 524 if( g_strcasecmp( l->data, cmd[4] ) == 0 ) 525 return 1; 526 527 for( l = ic->deny; l; l = l->next ) 528 if( g_strcasecmp( l->data, cmd[4] ) == 0 ) 529 return 1; 530 531 msn_buddy_ask( ic, cmd[4], cmd[5] ); 532 } 533 else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 ) 534 { 535 const char *group = NULL; 536 int num; 537 538 if( cmd[6] != NULL && sscanf( cmd[6], "%d", &num ) == 1 && num < md->groupcount ) 539 group = md->grouplist[num]; 540 541 http_decode( cmd[5] ); 542 imcb_add_buddy( ic, cmd[4], group ); 543 imcb_rename_buddy( ic, cmd[4], cmd[5] ); 544 } 545 } 410 546 else if( strcmp( cmd[0], "OUT" ) == 0 ) 411 547 { … … 429 565 return( 0 ); 430 566 } 567 #if 0 568 /* Discard this one completely for now since I don't care about the ack 569 and since MSN servers can apparently screw up the formatting. */ 570 else if( strcmp( cmd[0], "REA" ) == 0 ) 571 { 572 if( num_parts != 5 ) 573 { 574 imcb_error( ic, "Syntax error" ); 575 imc_logout( ic, TRUE ); 576 return( 0 ); 577 } 578 579 if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 ) 580 { 581 set_t *s; 582 583 http_decode( cmd[4] ); 584 strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); 585 ic->displayname[sizeof(ic->displayname)-1] = 0; 586 587 if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) 588 { 589 g_free( s->value ); 590 s->value = g_strdup( cmd[4] ); 591 } 592 } 593 else 594 { 595 /* This is not supposed to happen, but let's handle it anyway... */ 596 http_decode( cmd[4] ); 597 imcb_rename_buddy( ic, cmd[3], cmd[4] ); 598 } 599 } 600 #endif 431 601 else if( strcmp( cmd[0], "IPG" ) == 0 ) 432 602 { … … 442 612 } 443 613 } 444 #if 0445 614 else if( strcmp( cmd[0], "ADG" ) == 0 ) 446 615 { … … 486 655 } 487 656 } 488 }489 #endif490 else if( strcmp( cmd[0], "GCF" ) == 0 )491 {492 /* Coming up is cmd[2] bytes of stuff we're supposed to493 censore. Meh. */494 md->handler->msglen = atoi( cmd[2] );495 }496 else if( strcmp( cmd[0], "UBX" ) == 0 )497 {498 /* Status message. */499 if( num_parts >= 4 )500 md->handler->msglen = atoi( cmd[3] );501 }502 else if( strcmp( cmd[0], "NOT" ) == 0 )503 {504 /* Some kind of notification, poorly documented but505 apparently used to announce address book changes. */506 if( num_parts >= 2 )507 md->handler->msglen = atoi( cmd[1] );508 657 } 509 658 else if( isdigit( cmd[0][0] ) ) … … 616 765 } 617 766 } 618 else if( strcmp( cmd[0], "UBX" ) == 0 )619 {620 struct xt_node *psm;621 char *psm_text = NULL;622 623 psm = xt_from_string( msg );624 if( psm && strcmp( psm->name, "Data" ) == 0 &&625 ( psm = xt_find_node( psm->children, "PSM" ) ) )626 psm_text = psm->text;627 628 imcb_buddy_status_msg( ic, cmd[1], psm_text );629 xt_free_node( psm );630 }631 else if( strcmp( cmd[0], "ADL" ) == 0 )632 {633 struct xt_node *adl, *d, *c;634 635 if( !( adl = xt_from_string( msg ) ) )636 return 1;637 638 for( d = adl->children; d; d = d->next )639 {640 char *dn;641 if( strcmp( d->name, "d" ) != 0 ||642 ( dn = xt_find_attr( d, "n" ) ) == NULL )643 continue;644 for( c = d->children; c; c = c->next )645 {646 bee_user_t *bu;647 struct msn_buddy_data *bd;648 char *cn, *handle, *f, *l;649 int flags;650 651 if( strcmp( c->name, "c" ) != 0 ||652 ( l = xt_find_attr( c, "l" ) ) == NULL ||653 ( cn = xt_find_attr( c, "n" ) ) == NULL )654 continue;655 656 handle = g_strdup_printf( "%s@%s", cn, dn );657 if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||658 ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )659 {660 g_free( handle );661 continue;662 }663 g_free( handle );664 bd = bu->data;665 666 if( ( f = xt_find_attr( c, "f" ) ) )667 {668 http_decode( f );669 imcb_rename_buddy( ic, bu->handle, f );670 }671 672 flags = atoi( l ) & 15;673 if( bd->flags != flags )674 {675 bd->flags = flags;676 msn_buddy_ask( bu );677 }678 }679 }680 }681 767 682 768 return( 1 ); 683 769 } 684 770 685 void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error)771 static void msn_auth_got_passport_token( struct msn_auth_data *mad ) 686 772 { 773 struct im_connection *ic = mad->data; 687 774 struct msn_data *md; 688 775 … … 692 779 693 780 md = ic->proto_data; 694 695 if( token ) 696 { 697 char buf[1536]; 698 699 g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); 781 if( mad->token ) 782 { 783 char buf[1024]; 784 785 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); 700 786 msn_write( ic, buf, strlen( buf ) ); 701 787 } 702 788 else 703 789 { 704 imcb_error( ic, "Error during Passport authentication: %s", error );790 imcb_error( ic, "Error during Passport authentication: %s", mad->error ); 705 791 imc_logout( ic, TRUE ); 706 792 } 707 793 } 708 794 709 void msn_auth_got_contact_list( struct im_connection *ic)795 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name ) 710 796 { 711 char buf[64]; 712 struct msn_data *md; 713 714 /* Dead connection? */ 715 if( g_slist_find( msn_connections, ic ) == NULL ) 716 return; 717 718 md = ic->proto_data; 719 720 721 g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" ); 722 msn_write( ic, buf, strlen( buf ) ); 797 set_t *s; 798 799 if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL ) 800 return FALSE; /* Shouldn't happen.. */ 801 802 http_decode( name ); 803 804 if( s->value && strcmp( s->value, name ) == 0 ) 805 { 806 return TRUE; 807 /* The names match, nothing to worry about. */ 808 } 809 else if( s->value != NULL && 810 ( strcmp( name, ic->acc->user ) == 0 || 811 set_getbool( &ic->acc->set, "local_display_name" ) ) ) 812 { 813 /* The server thinks our display name is our e-mail address 814 which is probably wrong, or the user *wants* us to do this: 815 Always use the locally set display_name. */ 816 return msn_set_display_name( ic, s->value ); 817 } 818 else 819 { 820 if( s->value && *s->value ) 821 imcb_log( ic, "BitlBee thinks your display name is `%s' but " 822 "the MSN server says it's `%s'. Using the MSN " 823 "server's name. Set local_display_name to true " 824 "to use the local name.", s->value, name ); 825 826 if( g_utf8_validate( name, -1, NULL ) ) 827 { 828 g_free( s->value ); 829 s->value = g_strdup( name ); 830 } 831 else 832 { 833 imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); 834 } 835 836 return TRUE; 837 } 723 838 } 724 725 static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data )726 {727 struct xt_node *adl = data, *d, *c;728 struct bee_user *bu = value;729 struct msn_buddy_data *bd = bu->data;730 struct msn_data *md = bu->ic->proto_data;731 char handle[strlen(bu->handle)];732 char *domain;733 char l[4];734 735 if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) )736 return FALSE;737 738 strcpy( handle, bu->handle );739 if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */740 return FALSE;741 *domain = '\0';742 domain ++;743 744 if( ( d = adl->children ) == NULL ||745 g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 )746 {747 d = xt_new_node( "d", NULL, NULL );748 xt_add_attr( d, "n", domain );749 xt_insert_child( adl, d );750 }751 752 g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 );753 c = xt_new_node( "c", NULL, NULL );754 xt_add_attr( c, "n", handle );755 xt_add_attr( c, "l", l );756 xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */757 xt_insert_child( d, c );758 759 /* Do this in batches of 100. */760 bd->flags |= MSN_BUDDY_ADL_SYNCED;761 return (--md->adl_todo % 140) == 0;762 }763 764 static void msn_ns_send_adl( struct im_connection *ic )765 {766 struct xt_node *adl;767 struct msn_data *md = ic->proto_data;768 char *adls, buf[64];769 770 adl = xt_new_node( "ml", NULL, NULL );771 xt_add_attr( adl, "l", "1" );772 g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );773 if( adl->children == NULL )774 {775 /* This tells the caller that we're done now. */776 md->adl_todo = -1;777 xt_free_node( adl );778 return;779 }780 adls = xt_to_string( adl );781 782 g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) );783 if( msn_write( ic, buf, strlen( buf ) ) )784 msn_write( ic, adls, strlen( adls ) );785 786 g_free( adls );787 }788 789 static void msn_ns_send_adl_start( struct im_connection *ic )790 {791 struct msn_data *md;792 GSList *l;793 794 /* Dead connection? */795 if( g_slist_find( msn_connections, ic ) == NULL )796 return;797 798 md = ic->proto_data;799 md->adl_todo = 0;800 for( l = ic->bee->users; l; l = l->next )801 {802 bee_user_t *bu = l->data;803 struct msn_buddy_data *bd = bu->data;804 805 if( bu->ic != ic || ( bd->flags & 7 ) == 0 )806 continue;807 808 bd->flags &= ~MSN_BUDDY_ADL_SYNCED;809 md->adl_todo++;810 }811 812 msn_ns_send_adl( ic );813 }814 815 int msn_ns_finish_login( struct im_connection *ic )816 {817 struct msn_data *md = ic->proto_data;818 819 if( ic->flags & OPT_LOGGED_IN )820 return 1;821 822 if( md->adl_todo < 0 )823 md->flags |= MSN_DONE_ADL;824 825 if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) )826 return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );827 else828 return 1;829 }
Note: See TracChangeset
for help on using the changeset viewer.