Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    r70ac477 r27053b5  
    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"
    31 
     30#include "soap.h"
     31#include "xmltree.h"
     32
     33static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
    3234static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );
    33 static int msn_ns_command( gpointer data, char **cmd, int num_parts );
    34 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    35 
    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 );
    38 
    39 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
    40 {
    41         struct im_connection *ic = data;
    42         struct msn_data *md;
    43         char s[1024];
    44        
    45         if( !g_slist_find( msn_connections, ic ) )
    46                 return FALSE;
    47        
    48         if( source == -1 )
     35static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts );
     36static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts );
     37
     38static void msn_ns_send_adl_start( struct im_connection *ic );
     39static void msn_ns_send_adl( struct im_connection *ic );
     40
     41int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... )
     42{
     43        struct msn_data *md = ic->proto_data;
     44        va_list params;
     45        char *out;
     46        size_t len;
     47        int st;
     48       
     49        va_start( params, fmt );
     50        out = g_strdup_vprintf( fmt, params );
     51        va_end( params );
     52       
     53        if( fd < 0 )
     54                fd = md->ns->fd;
     55       
     56        if( getenv( "BITLBEE_DEBUG" ) )
     57                fprintf( stderr, "->NS%d:%s", fd, out );
     58       
     59        len = strlen( out );
     60        st = write( fd, out, len );
     61        g_free( out );
     62        if( st != len )
     63        {
     64                imcb_error( ic, "Short write() to main server" );
     65                imc_logout( ic, TRUE );
     66                return 0;
     67        }
     68       
     69        return 1;
     70}
     71
     72gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port )
     73{
     74        if( handler->fd >= 0 )
     75                closesocket( handler->fd );
     76       
     77        handler->exec_command = msn_ns_command;
     78        handler->exec_message = msn_ns_message;
     79        handler->data = ic;
     80        handler->fd = proxy_connect( host, port, msn_ns_connected, handler );
     81        if( handler->fd < 0 )
    4982        {
    5083                imcb_error( ic, "Could not connect to server" );
     
    5386        }
    5487       
     88        return TRUE;
     89}
     90
     91static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
     92{
     93        struct msn_handler_data *handler = data;
     94        struct im_connection *ic = handler->data;
     95        struct msn_data *md;
     96       
     97        if( !g_slist_find( msn_connections, ic ) )
     98                return FALSE;
     99       
    55100        md = ic->proto_data;
    56101       
    57         if( !md->handler )
    58         {
    59                 md->handler = g_new0( struct msn_handler_data, 1 );
    60                 md->handler->data = ic;
    61                 md->handler->exec_command = msn_ns_command;
    62                 md->handler->exec_message = msn_ns_message;
    63         }
    64         else
    65         {
    66                 if( md->handler->rxq )
    67                         g_free( md->handler->rxq );
    68                
    69                 md->handler->rxlen = 0;
    70         }
    71        
    72         md->handler->fd = md->fd;
    73         md->handler->rxq = g_new0( char, 1 );
    74        
    75         g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
    76         if( msn_write( ic, s, strlen( s ) ) )
    77         {
    78                 ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic );
     102        if( source == -1 )
     103        {
     104                imcb_error( ic, "Could not connect to server" );
     105                imc_logout( ic, TRUE );
     106                return FALSE;
     107        }
     108       
     109        g_free( handler->rxq );
     110        handler->rxlen = 0;
     111        handler->rxq = g_new0( char, 1 );
     112       
     113        if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) )
     114        {
     115                handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler );
    79116                imcb_log( ic, "Connected to server, waiting for reply" );
    80117        }
     
    83120}
    84121
     122void msn_ns_close( struct msn_handler_data *handler )
     123{
     124        if( handler->fd >= 0 )
     125        {
     126                closesocket( handler->fd );
     127                b_event_remove( handler->inpa );
     128        }
     129       
     130        handler->fd = handler->inpa = -1;
     131        g_free( handler->rxq );
     132        g_free( handler->cmd_text );
     133       
     134        handler->rxlen = 0;
     135        handler->rxq = NULL;
     136        handler->cmd_text = NULL;
     137}
     138
    85139static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond )
    86140{
    87         struct im_connection *ic = data;
    88         struct msn_data *md = ic->proto_data;
    89        
    90         if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */
     141        struct msn_handler_data *handler = data;
     142        struct im_connection *ic = handler->data;
     143       
     144        if( msn_handler( handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */
    91145        {
    92146                imcb_error( ic, "Error while reading from server" );
     
    99153}
    100154
    101 static int msn_ns_command( gpointer data, char **cmd, int num_parts )
    102 {
    103         struct im_connection *ic = data;
     155static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts )
     156{
     157        struct im_connection *ic = handler->data;
    104158        struct msn_data *md = ic->proto_data;
    105         char buf[1024];
    106159       
    107160        if( num_parts == 0 )
     
    113166        if( strcmp( cmd[0], "VER" ) == 0 )
    114167        {
    115                 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
     168                if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )
    116169                {
    117170                        imcb_error( ic, "Unsupported protocol" );
     
    120173                }
    121174               
    122                 g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
    123                                                 ++md->trId, ic->acc->user );
    124                 return( msn_write( ic, buf, strlen( buf ) ) );
     175                return( msn_ns_write( ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
     176                                      ++md->trId, ic->acc->user ) );
    125177        }
    126178        else if( strcmp( cmd[0], "CVR" ) == 0 )
    127179        {
    128180                /* 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 );
    130                 return( msn_write( ic, buf, strlen( buf ) ) );
     181                return msn_ns_write( ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user );
    131182        }
    132183        else if( strcmp( cmd[0], "XFR" ) == 0 )
     
    135186                int port;
    136187               
    137                 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
    138                 {
    139                         b_event_remove( ic->inpa );
    140                         ic->inpa = 0;
    141                         closesocket( md->fd );
     188                if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 )
     189                {
     190                        b_event_remove( handler->inpa );
     191                        handler->inpa = -1;
    142192                       
    143193                        server = strchr( cmd[3], ':' );
     
    153203                       
    154204                        imcb_log( ic, "Transferring to other server" );
    155                        
    156                         md->fd = proxy_connect( server, port, msn_ns_connected, ic );
    157                 }
    158                 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
     205                        return msn_ns_connect( ic, handler, server, port );
     206                }
     207                else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 )
    159208                {
    160209                        struct msn_switchboard *sb;
     
    220269        else if( strcmp( cmd[0], "USR" ) == 0 )
    221270        {
    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                        
     271                if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 &&
     272                    strcmp( cmd[3], "S" ) == 0 )
     273                {
     274                        g_free( md->pp_policy );
     275                        md->pp_policy = g_strdup( cmd[4] );
     276                        msn_soap_passport_sso_request( ic, cmd[5] );
     277                }
     278                else if( strcmp( cmd[2], "OK" ) == 0 )
     279                {
    239280                        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 ) ) );
     281                        msn_soap_memlist_request( ic );
    243282                }
    244283                else
     
    251290        else if( strcmp( cmd[0], "MSG" ) == 0 )
    252291        {
    253                 if( num_parts != 4 )
    254                 {
    255                         imcb_error( ic, "Syntax error" );
    256                         imc_logout( ic, TRUE );
    257                         return( 0 );
    258                 }
    259                
    260                 md->handler->msglen = atoi( cmd[3] );
    261                
    262                 if( md->handler->msglen <= 0 )
    263                 {
    264                         imcb_error( ic, "Syntax error" );
    265                         imc_logout( ic, TRUE );
    266                         return( 0 );
    267                 }
    268         }
    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] );
     292                if( num_parts < 4 )
     293                {
     294                        imcb_error( ic, "Syntax error" );
     295                        imc_logout( ic, TRUE );
     296                        return( 0 );
     297                }
     298               
     299                handler->msglen = atoi( cmd[3] );
     300               
     301                if( handler->msglen <= 0 )
     302                {
     303                        imcb_error( ic, "Syntax error" );
     304                        imc_logout( ic, TRUE );
     305                        return( 0 );
     306                }
     307        }
     308        else if( strcmp( cmd[0], "BLP" ) == 0 )
     309        {
     310                msn_ns_send_adl_start( ic );
     311                return msn_ns_finish_login( ic );
     312        }
     313        else if( strcmp( cmd[0], "ADL" ) == 0 )
     314        {
     315                if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 )
     316                {
     317                        msn_ns_send_adl( ic );
     318                        return msn_ns_finish_login( ic );
     319                }
     320                else if( num_parts >= 3 )
     321                {
     322                        handler->msglen = atoi( cmd[2] );
     323                }
     324        }
     325        else if( strcmp( cmd[0], "PRP" ) == 0 )
     326        {
     327                imcb_connected( ic );
    372328        }
    373329        else if( strcmp( cmd[0], "CHL" ) == 0 )
    374330        {
    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] );
    394                
    395                 return( msn_write( ic, buf, strlen( buf ) ) );
     331                char *resp;
     332                int st;
     333               
     334                if( num_parts < 3 )
     335                {
     336                        imcb_error( ic, "Syntax error" );
     337                        imc_logout( ic, TRUE );
     338                        return( 0 );
     339                }
     340               
     341                resp = msn_p11_challenge( cmd[2] );
     342               
     343                st =  msn_ns_write( ic, -1, "QRY %d %s %zd\r\n%s",
     344                                    ++md->trId, MSNP11_PROD_ID,
     345                                    strlen( resp ), resp );
     346                g_free( resp );
     347                return st;
    396348        }
    397349        else if( strcmp( cmd[0], "ILN" ) == 0 )
     
    399351                const struct msn_away_state *st;
    400352               
    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] );
     353                if( num_parts < 6 )
     354                {
     355                        imcb_error( ic, "Syntax error" );
     356                        imc_logout( ic, TRUE );
     357                        return( 0 );
     358                }
     359               
     360                http_decode( cmd[5] );
     361                imcb_rename_buddy( ic, cmd[3], cmd[5] );
    410362               
    411363                st = msn_away_state_by_code( cmd[2] );
     
    432384        {
    433385                const struct msn_away_state *st;
    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] );
     386                int cap;
     387               
     388                if( num_parts < 6 )
     389                {
     390                        imcb_error( ic, "Syntax error" );
     391                        imc_logout( ic, TRUE );
     392                        return( 0 );
     393                }
     394               
     395                http_decode( cmd[4] );
     396                cap = atoi( cmd[5] );
     397                imcb_rename_buddy( ic, cmd[2], cmd[4] );
    444398               
    445399                st = msn_away_state_by_code( cmd[1] );
     
    451405               
    452406                imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
    453                                    ( st != msn_away_state_list ? OPT_AWAY : 0 ),
     407                                   ( st != msn_away_state_list ? OPT_AWAY : 0 ) |
     408                                   ( cap & 1 ? OPT_MOBILE : 0 ),
    454409                                   st->name, NULL );
    455410               
     
    462417                int session, port;
    463418               
    464                 if( num_parts != 7 )
     419                if( num_parts < 7 )
    465420                {
    466421                        imcb_error( ic, "Syntax error" );
     
    504459                }
    505460        }
    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         }
    546461        else if( strcmp( cmd[0], "OUT" ) == 0 )
    547462        {
     
    565480                return( 0 );
    566481        }
     482        else if( strcmp( cmd[0], "IPG" ) == 0 )
     483        {
     484                imcb_error( ic, "Received IPG command, we don't handle them yet." );
     485               
     486                handler->msglen = atoi( cmd[1] );
     487               
     488                if( handler->msglen <= 0 )
     489                {
     490                        imcb_error( ic, "Syntax error" );
     491                        imc_logout( ic, TRUE );
     492                        return( 0 );
     493                }
     494        }
    567495#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
    601         else if( strcmp( cmd[0], "IPG" ) == 0 )
    602         {
    603                 imcb_error( ic, "Received IPG command, we don't handle them yet." );
    604                
    605                 md->handler->msglen = atoi( cmd[1] );
    606                
    607                 if( md->handler->msglen <= 0 )
    608                 {
    609                         imcb_error( ic, "Syntax error" );
    610                         imc_logout( ic, TRUE );
    611                         return( 0 );
    612                 }
    613         }
    614496        else if( strcmp( cmd[0], "ADG" ) == 0 )
    615497        {
     
    656538                }
    657539        }
     540#endif
     541        else if( strcmp( cmd[0], "GCF" ) == 0 )
     542        {
     543                /* Coming up is cmd[2] bytes of stuff we're supposed to
     544                   censore. Meh. */
     545                handler->msglen = atoi( cmd[2] );
     546        }
     547        else if( strcmp( cmd[0], "UBX" ) == 0 )
     548        {
     549                /* Status message. */
     550                if( num_parts >= 4 )
     551                        handler->msglen = atoi( cmd[3] );
     552        }
     553        else if( strcmp( cmd[0], "NOT" ) == 0 )
     554        {
     555                /* Some kind of notification, poorly documented but
     556                   apparently used to announce address book changes. */
     557                if( num_parts >= 2 )
     558                        handler->msglen = atoi( cmd[1] );
     559        }
    658560        else if( isdigit( cmd[0][0] ) )
    659561        {
     
    668570                        return( 0 );
    669571                }
     572               
     573                /* Oh yes, errors can have payloads too now. Discard them for now. */
     574                if( num_parts >= 3 )
     575                        handler->msglen = atoi( cmd[2] );
    670576        }
    671577        else
     
    677583}
    678584
    679 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
    680 {
    681         struct im_connection *ic = data;
     585static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
     586{
     587        struct im_connection *ic = handler->data;
    682588        char *body;
    683589        int blen = 0;
     
    765671                }
    766672        }
     673        else if( strcmp( cmd[0], "UBX" ) == 0 )
     674        {
     675                struct xt_node *psm;
     676                char *psm_text = NULL;
     677               
     678                psm = xt_from_string( msg );
     679                if( psm && strcmp( psm->name, "Data" ) == 0 &&
     680                    ( psm = xt_find_node( psm->children, "PSM" ) ) )
     681                        psm_text = psm->text;
     682               
     683                imcb_buddy_status_msg( ic, cmd[1], psm_text );
     684                xt_free_node( psm );
     685        }
     686        else if( strcmp( cmd[0], "ADL" ) == 0 )
     687        {
     688                struct xt_node *adl, *d, *c;
     689               
     690                if( !( adl = xt_from_string( msg ) ) )
     691                        return 1;
     692               
     693                for( d = adl->children; d; d = d->next )
     694                {
     695                        char *dn;
     696                        if( strcmp( d->name, "d" ) != 0 ||
     697                            ( dn = xt_find_attr( d, "n" ) ) == NULL )
     698                                continue;
     699                        for( c = d->children; c; c = c->next )
     700                        {
     701                                bee_user_t *bu;
     702                                struct msn_buddy_data *bd;
     703                                char *cn, *handle, *f, *l;
     704                                int flags;
     705                               
     706                                if( strcmp( c->name, "c" ) != 0 ||
     707                                    ( l = xt_find_attr( c, "l" ) ) == NULL ||
     708                                    ( cn = xt_find_attr( c, "n" ) ) == NULL )
     709                                        continue;
     710                               
     711                                handle = g_strdup_printf( "%s@%s", cn, dn );
     712                                if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
     713                                       ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )
     714                                {
     715                                        g_free( handle );
     716                                        continue;
     717                                }
     718                                g_free( handle );
     719                                bd = bu->data;
     720                               
     721                                if( ( f = xt_find_attr( c, "f" ) ) )
     722                                {
     723                                        http_decode( f );
     724                                        imcb_rename_buddy( ic, bu->handle, f );
     725                                }
     726                               
     727                                flags = atoi( l ) & 15;
     728                                if( bd->flags != flags )
     729                                {
     730                                        bd->flags = flags;
     731                                        msn_buddy_ask( bu );
     732                                }
     733                        }
     734                }
     735        }
    767736       
    768737        return( 1 );
    769738}
    770739
    771 static void msn_auth_got_passport_token( struct msn_auth_data *mad )
    772 {
    773         struct im_connection *ic = mad->data;
     740void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error )
     741{
    774742        struct msn_data *md;
    775743       
     
    779747       
    780748        md = ic->proto_data;
    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 );
    786                 msn_write( ic, buf, strlen( buf ) );
     749       
     750        if( token )
     751        {
     752                msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
    787753        }
    788754        else
    789755        {
    790                 imcb_error( ic, "Error during Passport authentication: %s", mad->error );
     756                imcb_error( ic, "Error during Passport authentication: %s", error );
    791757                imc_logout( ic, TRUE );
    792758        }
    793759}
    794760
    795 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name )
    796 {
    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         }
     761void msn_auth_got_contact_list( struct im_connection *ic )
     762{
     763        struct msn_data *md;
     764       
     765        /* Dead connection? */
     766        if( g_slist_find( msn_connections, ic ) == NULL )
     767                return;
     768       
     769        md = ic->proto_data;
     770        msn_ns_write( ic, -1, "BLP %d %s\r\n", ++md->trId, "BL" );
     771}
     772
     773static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data )
     774{
     775        struct xt_node *adl = data, *d, *c;
     776        struct bee_user *bu = value;
     777        struct msn_buddy_data *bd = bu->data;
     778        struct msn_data *md = bu->ic->proto_data;
     779        char handle[strlen(bu->handle)];
     780        char *domain;
     781        char l[4];
     782       
     783        if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) )
     784                return FALSE;
     785       
     786        strcpy( handle, bu->handle );
     787        if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */
     788                return FALSE;
     789        *domain = '\0';
     790        domain ++;
     791       
     792        if( ( d = adl->children ) == NULL ||
     793            g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 )
     794        {
     795                d = xt_new_node( "d", NULL, NULL );
     796                xt_add_attr( d, "n", domain );
     797                xt_insert_child( adl, d );
     798        }
     799       
     800        g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 );
     801        c = xt_new_node( "c", NULL, NULL );
     802        xt_add_attr( c, "n", handle );
     803        xt_add_attr( c, "l", l );
     804        xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */
     805        xt_insert_child( d, c );
     806       
     807        /* Do this in batches of 100. */
     808        bd->flags |= MSN_BUDDY_ADL_SYNCED;
     809        return (--md->adl_todo % 140) == 0;
     810}
     811
     812static void msn_ns_send_adl( struct im_connection *ic )
     813{
     814        struct xt_node *adl;
     815        struct msn_data *md = ic->proto_data;
     816        char *adls;
     817       
     818        adl = xt_new_node( "ml", NULL, NULL );
     819        xt_add_attr( adl, "l", "1" );
     820        g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
     821        if( adl->children == NULL )
     822        {
     823                /* This tells the caller that we're done now. */
     824                md->adl_todo = -1;
     825                xt_free_node( adl );
     826                return;
     827        }
     828       
     829        adls = xt_to_string( adl );
     830        msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen( adls ), adls );
     831        g_free( adls );
     832}
     833
     834static void msn_ns_send_adl_start( struct im_connection *ic )
     835{
     836        struct msn_data *md;
     837        GSList *l;
     838       
     839        /* Dead connection? */
     840        if( g_slist_find( msn_connections, ic ) == NULL )
     841                return;
     842       
     843        md = ic->proto_data;
     844        md->adl_todo = 0;
     845        for( l = ic->bee->users; l; l = l->next )
     846        {
     847                bee_user_t *bu = l->data;
     848                struct msn_buddy_data *bd = bu->data;
     849               
     850                if( bu->ic != ic || ( bd->flags & 7 ) == 0 )
     851                        continue;
     852               
     853                bd->flags &= ~MSN_BUDDY_ADL_SYNCED;
     854                md->adl_todo++;
     855        }
     856       
     857        msn_ns_send_adl( ic );
     858}
     859
     860int msn_ns_finish_login( struct im_connection *ic )
     861{
     862        struct msn_data *md = ic->proto_data;
     863       
     864        if( ic->flags & OPT_LOGGED_IN )
     865                return 1;
     866       
     867        if( md->adl_todo < 0 )
     868                md->flags |= MSN_DONE_ADL;
     869       
     870        if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) )
     871                return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );
    818872        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         }
    838 }
     873                return 1;
     874}
Note: See TracChangeset for help on using the changeset viewer.