Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    r70ac477 r5848675  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2727#include "nogaim.h"
    2828#include "msn.h"
    29 #include "passport.h"
    3029#include "md5.h"
     30#include "soap.h"
     31#include "xmltree.h"
    3132
    3233static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );
     
    3435static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    3536
    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 );
     37static void msn_ns_send_adl( struct im_connection *ic );
    3838
    3939gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
     
    7373        md->handler->rxq = g_new0( char, 1 );
    7474       
    75         g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
     75        g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER );
    7676        if( msn_write( ic, s, strlen( s ) ) )
    7777        {
     
    113113        if( strcmp( cmd[0], "VER" ) == 0 )
    114114        {
    115                 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
     115                if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )
    116116                {
    117117                        imcb_error( ic, "Unsupported protocol" );
     
    127127        {
    128128                /* We don't give a damn about the information we just received */
    129                 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user );
     129                g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user );
    130130                return( msn_write( ic, buf, strlen( buf ) ) );
    131131        }
     
    135135                int port;
    136136               
    137                 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
     137                if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 )
    138138                {
    139139                        b_event_remove( ic->inpa );
     
    156156                        md->fd = proxy_connect( server, port, msn_ns_connected, ic );
    157157                }
    158                 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
     158                else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 )
    159159                {
    160160                        struct msn_switchboard *sb;
     
    220220        else if( strcmp( cmd[0], "USR" ) == 0 )
    221221        {
    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                        
     222                if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 &&
     223                    strcmp( cmd[3], "S" ) == 0 )
     224                {
     225                        msn_soap_passport_sso_request( ic, cmd[4], cmd[5] );
     226                }
     227                else if( strcmp( cmd[2], "OK" ) == 0 )
     228                {
    239229                        imcb_log( ic, "Authenticated, getting buddy list" );
    240                        
    241                         g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId );
    242                         return( msn_write( ic, buf, strlen( buf ) ) );
     230                        msn_soap_memlist_request( ic );
    243231                }
    244232                else
     
    251239        else if( strcmp( cmd[0], "MSG" ) == 0 )
    252240        {
    253                 if( num_parts != 4 )
     241                if( num_parts < 4 )
    254242                {
    255243                        imcb_error( ic, "Syntax error" );
     
    267255                }
    268256        }
    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] );
     257        else if( strcmp( cmd[0], "BLP" ) == 0 )
     258        {
     259                msn_ns_send_adl( ic );
     260        }
     261        else if( strcmp( cmd[0], "ADL" ) == 0 )
     262        {
     263                if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 )
     264                {
     265                        char buf[1024];
     266                        char *fn_raw = set_getstr( &ic->acc->set, "display_name" );
     267                        char *fn;
     268                       
     269                        if( fn_raw == NULL )
     270                                fn_raw = ic->acc->user;
     271                        fn = g_malloc( strlen( fn_raw ) * 3 + 1 );
     272                        strcpy( fn, fn_raw );
     273                        http_encode( fn );
     274                       
     275                        g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n",
     276                                    ++md->trId, fn );
     277                        g_free( fn );
     278                       
     279                        msn_write( ic, buf, strlen( buf ) );
     280                }
     281        }
     282        else if( strcmp( cmd[0], "PRP" ) == 0 )
     283        {
     284                imcb_connected( ic );
    372285        }
    373286        else if( strcmp( cmd[0], "CHL" ) == 0 )
    374287        {
    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] );
     288                char *resp;
     289               
     290                if( num_parts < 3 )
     291                {
     292                        imcb_error( ic, "Syntax error" );
     293                        imc_logout( ic, TRUE );
     294                        return( 0 );
     295                }
     296               
     297                resp = msn_p11_challenge( cmd[2] );
     298                g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s",
     299                            ++md->trId, MSNP11_PROD_ID,
     300                            strlen( resp ), resp );
     301                g_free( resp );
    394302               
    395303                return( msn_write( ic, buf, strlen( buf ) ) );
     
    399307                const struct msn_away_state *st;
    400308               
    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] );
     309                if( num_parts < 6 )
     310                {
     311                        imcb_error( ic, "Syntax error" );
     312                        imc_logout( ic, TRUE );
     313                        return( 0 );
     314                }
     315               
     316                http_decode( cmd[5] );
     317                imcb_rename_buddy( ic, cmd[3], cmd[5] );
    410318               
    411319                st = msn_away_state_by_code( cmd[2] );
     
    433341                const struct msn_away_state *st;
    434342               
    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] );
     343                if( num_parts < 5 )
     344                {
     345                        imcb_error( ic, "Syntax error" );
     346                        imc_logout( ic, TRUE );
     347                        return( 0 );
     348                }
     349               
     350                http_decode( cmd[4] );
     351                imcb_rename_buddy( ic, cmd[2], cmd[4] );
    444352               
    445353                st = msn_away_state_by_code( cmd[1] );
     
    462370                int session, port;
    463371               
    464                 if( num_parts != 7 )
     372                if( num_parts < 7 )
    465373                {
    466374                        imcb_error( ic, "Syntax error" );
     
    506414        else if( strcmp( cmd[0], "ADD" ) == 0 )
    507415        {
    508                 if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 )
     416                if( num_parts >= 6 && strcmp( cmd[2], "RL" ) == 0 )
    509417                {
    510418                        GSList *l;
     
    565473                return( 0 );
    566474        }
    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
    601475        else if( strcmp( cmd[0], "IPG" ) == 0 )
    602476        {
     
    655529                        }
    656530                }
     531        }
     532        else if( strcmp( cmd[0], "GCF" ) == 0 )
     533        {
     534                /* Coming up is cmd[2] bytes of stuff we're supposed to
     535                   censore. Meh. */
     536                md->handler->msglen = atoi( cmd[2] );
     537        }
     538        else if( strcmp( cmd[0], "UBX" ) == 0 )
     539        {
     540                /* Status message. Parser coming soon. */
     541                if( num_parts >= 4 )
     542                        md->handler->msglen = atoi( cmd[3] );
     543        }
     544        else if( strcmp( cmd[0], "NOT" ) == 0 )
     545        {
     546                /* Some kind of notification, not sure if it still exists
     547                   but we have to skip the payload or stuff breaks. */
     548                if( num_parts >= 3 )
     549                        md->handler->msglen = atoi( cmd[2] );
    657550        }
    658551        else if( isdigit( cmd[0][0] ) )
     
    765658                }
    766659        }
     660        else if( strcmp( cmd[0], "UBX" ) == 0 )
     661        {
     662                struct xt_node *psm;
     663                char *psm_text = NULL;
     664               
     665                psm = xt_from_string( msg );
     666                if( psm && strcmp( psm->name, "Data" ) == 0 &&
     667                    ( psm = xt_find_node( psm->children, "PSM" ) ) )
     668                        psm_text = psm->text;
     669               
     670                imcb_buddy_status_msg( ic, cmd[1], psm_text );
     671                xt_free_node( psm );
     672        }
    767673       
    768674        return( 1 );
    769675}
    770676
    771 static void msn_auth_got_passport_token( struct msn_auth_data *mad )
     677void msn_auth_got_passport_token( struct im_connection *ic, char *token )
    772678{
    773         struct im_connection *ic = mad->data;
    774679        struct msn_data *md;
    775680       
     
    779684       
    780685        md = ic->proto_data;
    781         if( mad->token )
     686       
    782687        {
    783688                char buf[1024];
    784689               
    785                 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
     690                g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
    786691                msn_write( ic, buf, strlen( buf ) );
    787692        }
    788         else
    789         {
    790                 imcb_error( ic, "Error during Passport authentication: %s", mad->error );
    791                 imc_logout( ic, TRUE );
    792         }
    793693}
    794694
    795 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name )
     695void msn_auth_got_contact_list( struct im_connection *ic )
    796696{
    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         }
     697        char buf[64];
     698        struct msn_data *md;
     699       
     700        /* Dead connection? */
     701        if( g_slist_find( msn_connections, ic ) == NULL )
     702                return;
     703       
     704        md = ic->proto_data;
     705       
     706       
     707        g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" );
     708        msn_write( ic, buf, strlen( buf ) );
    838709}
     710
     711static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data )
     712{
     713        struct xt_node *adl = data, *d, *c;
     714        struct bee_user *bu = value;
     715        struct msn_buddy_data *bd = bu->data;
     716        char handle[strlen(bu->handle)];
     717        char *domain;
     718        char l[4];
     719       
     720        strcpy( handle, bu->handle );
     721        if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */
     722                return FALSE;
     723        *domain = '\0';
     724        domain ++;
     725       
     726        if( ( d = adl->children ) == NULL ||
     727            g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 )
     728        {
     729                d = xt_new_node( "d", NULL, NULL );
     730                xt_add_attr( d, "n", domain );
     731                xt_insert_child( adl, d );
     732        }
     733       
     734        g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 );
     735        c = xt_new_node( "c", NULL, NULL );
     736        xt_add_attr( c, "n", handle );
     737        xt_add_attr( c, "l", l );
     738        xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */
     739        xt_insert_child( d, c );
     740       
     741        return FALSE;
     742}
     743
     744static void msn_ns_send_adl( struct im_connection *ic )
     745{
     746        struct xt_node *adl;
     747        struct msn_data *md;
     748        char *adls, buf[64];
     749       
     750        /* Dead connection? */
     751        if( g_slist_find( msn_connections, ic ) == NULL )
     752                return;
     753       
     754        md = ic->proto_data;
     755       
     756        adl = xt_new_node( "ml", NULL, NULL );
     757        xt_add_attr( adl, "l", "1" );
     758        g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
     759        adls = xt_to_string( adl );
     760       
     761        g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) );
     762        if( msn_write( ic, buf, strlen( buf ) ) )
     763                msn_write( ic, adls, strlen( adls ) );
     764       
     765        g_free( adls );
     766        xt_free_node( adl );
     767}
Note: See TracChangeset for help on using the changeset viewer.