Ignore:
Timestamp:
2010-10-02T05:34:53Z (14 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
2af3e23
Parents:
05bf2a0 (diff), 04cd284 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merging msnp13 branch which, confusingly, upgrades the msn module to use
MSNP15. (The reason for this is that A) IMHO MSNP13 is what causes most of
the pain in this upgade and B) I initially intended to only implement MSNP13
but then discovered MS doesn't support it anymore.)

This fixes issues with display names being forgotten, adding contacts (and
them automatically getting blocked sometimes!!), and adds support for
away/status messages and some support for sending offline messages.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    r05bf2a0 r62f53b50  
    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.