Changes in / [ed320e8:975708a]


Ignore:
Files:
4 added
2 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • configure

    red320e8 r975708a  
    423423fi;
    424424
     425if [ "$msn" = "1" -a "$ssl" != "openssl" ]; then
     426        # Needed for MSN only. OpenSSL exports nice cipher functions already,
     427        # others don't, so use our own 3des code.
     428        echo 'DES=des.o' >> Makefile.settings
     429fi
     430
    425431echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
    426432
  • doc/CHANGES

    red320e8 r975708a  
    44http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on
    55
    6 Version 1.3dev:
     6Version ...
    77- For the first time since 2007, a dev snapshot. Like then, this is pretty
    88  stable already (running on testing.bitlbee.org for weeks by now), but not
     
    5252    for a list of supported protocols (works only in libpurple-enabled
    5353    binaries).
     54- Rewritten MSN module, implementing MSNP15 instead of the old MSNP8:
     55  * MSNP8 support from MSN was getting pretty unreliable. There were issues
     56    with remembering display names and adding contacts/auth requests.
     57  * Support for sending offline messages.
     58  * Support for setting and reading status messages.
    5459- Support for file transfers, in and out. /DCC SEND a file to a contact and
    5560  it becomes a file transfer, and incoming file transfers become /DCC SENDs
     
    5964  fixes issues with authorization requests.
    6065
    61 Finished 6 Aug 2010
     66Finished ...
    6267
    6368Version 1.2.8:
  • lib/Makefile

    red320e8 r975708a  
    1313
    1414# [SH] Program variables
    15 objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
     15objects = arc.o base64.o $(DES) $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o
    1616
    1717LFLAGS += -r
  • lib/misc.c

    red320e8 r975708a  
    298298void http_encode( char *s )
    299299{
    300         char *t;
     300        char t[strlen(s)+1];
    301301        int i, j;
    302302       
    303         t = g_strdup( s );
    304        
     303        strcpy( t, s );
    305304        for( i = j = 0; t[i]; i ++, j ++ )
    306305        {
     
    320319        }
    321320        s[j] = 0;
    322        
    323         g_free( t );
    324321}
    325322
  • lib/sha1.c

    red320e8 r975708a  
    3636 */
    3737
     38#include <string.h>
    3839#include "sha1.h"
    3940
     
    374375        sha1_process_block(context);
    375376}
     377
     378#define HMAC_BLOCK_SIZE 64
     379
     380/* BitlBee addition: */
     381void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, uint8_t Message_Digest[sha1_hash_size])
     382{
     383        sha1_state_t sha1;
     384        uint8_t hash[sha1_hash_size];
     385        uint8_t key[HMAC_BLOCK_SIZE+1];
     386        int i;
     387       
     388        if( key_len == 0 )
     389                key_len = strlen( key_ );
     390        if( payload_len == 0 )
     391                payload_len = strlen( payload );
     392       
     393        /* Create K. If our current key is >64 chars we have to hash it,
     394           otherwise just pad. */
     395        memset( key, 0, HMAC_BLOCK_SIZE + 1 );
     396        if( key_len > HMAC_BLOCK_SIZE )
     397        {
     398                sha1_init( &sha1 );
     399                sha1_append( &sha1, (uint8_t*) key_, key_len );
     400                sha1_finish( &sha1, key );
     401        }
     402        else
     403        {
     404                memcpy( key, key_, key_len );
     405        }
     406       
     407        /* Inner part: H(K XOR 0x36, text) */
     408        sha1_init( &sha1 );
     409        for( i = 0; i < HMAC_BLOCK_SIZE; i ++ )
     410                key[i] ^= 0x36;
     411        sha1_append( &sha1, key, HMAC_BLOCK_SIZE );
     412        sha1_append( &sha1, (const uint8_t*) payload, payload_len );
     413        sha1_finish( &sha1, hash );
     414       
     415        /* Final result: H(K XOR 0x5C, inner stuff) */
     416        sha1_init( &sha1 );
     417        for( i = 0; i < HMAC_BLOCK_SIZE; i ++ )
     418                key[i] ^= 0x36 ^ 0x5c;
     419        sha1_append( &sha1, key, HMAC_BLOCK_SIZE );
     420        sha1_append( &sha1, hash, sha1_hash_size );
     421        sha1_finish( &sha1, Message_Digest );
     422}
  • lib/sha1.h

    red320e8 r975708a  
    6767G_MODULE_EXPORT int sha1_append(sha1_state_t *, const uint8_t *, unsigned int);
    6868G_MODULE_EXPORT int sha1_finish(sha1_state_t *, uint8_t Message_Digest[sha1_hash_size]);
     69G_MODULE_EXPORT void sha1_hmac(const char *key_, size_t key_len, const char *payload, size_t payload_len, uint8_t Message_Digest[sha1_hash_size]);
    6970
    7071#endif
  • lib/ssl_client.h

    red320e8 r975708a  
    7878   the same action as the handler that just received the SSL_AGAIN.) */
    7979G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn );
     80
     81G_MODULE_EXPORT size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res);
  • lib/ssl_gnutls.c

    red320e8 r975708a  
    189189                ssl_errno = SSL_AGAIN;
    190190       
     191        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
     192       
    191193        return st;
    192194}
     
    207209        if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )
    208210                ssl_errno = SSL_AGAIN;
     211       
     212        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
    209213       
    210214        return st;
  • lib/ssl_openssl.c

    red320e8 r975708a  
    116116        {
    117117                initialized = TRUE;
    118                 SSLeay_add_ssl_algorithms();
     118                SSL_library_init();
     119                //SSLeay_add_ssl_algorithms();
     120                //OpenSSL_add_all_algorithms();
    119121        }
    120122       
     
    205207        }
    206208       
     209        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
     210       
    207211        return st;
    208212}
     
    219223       
    220224        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
     225       
     226        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
    221227       
    222228        ssl_errno = SSL_OK;
     
    272278        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
    273279}
     280
     281size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res)
     282{
     283        int output_length = 0;   
     284        EVP_CIPHER_CTX ctx;
     285       
     286        *res = g_new0(unsigned char, 72);
     287       
     288        /* Don't set key or IV because we will modify the parameters */
     289        EVP_CIPHER_CTX_init(&ctx);
     290        EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1);
     291        EVP_CIPHER_CTX_set_key_length(&ctx, key_len);
     292        EVP_CIPHER_CTX_set_padding(&ctx, 0);
     293        /* We finished modifying parameters so now we can set key and IV */
     294        EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);
     295        EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len);
     296        EVP_CipherFinal_ex(&ctx, *res, &output_length);
     297        EVP_CIPHER_CTX_cleanup(&ctx);   
     298        //EVP_cleanup();
     299       
     300        return output_length;
     301}
  • lib/xmltree.c

    red320e8 r975708a  
    141141/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on
    142142   end-of-stream and 1 otherwise. */
    143 int xt_feed( struct xt_parser *xt, char *text, int text_len )
     143int xt_feed( struct xt_parser *xt, const char *text, int text_len )
    144144{
    145145        if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) )
     
    174174        if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) )
    175175        {
    176                 for( i = 0; xt->handlers[i].func; i ++ )
     176                if( xt->handlers ) for( i = 0; xt->handlers[i].func; i ++ )
    177177                {
    178178                        /* This one is fun! \o/ */
    179179                       
    180                                                 /* If handler.name == NULL it means it should always match. */
     180                            /* If handler.name == NULL it means it should always match. */
    181181                        if( ( xt->handlers[i].name == NULL ||
    182                                                 /* If it's not, compare. There should always be a name. */
     182                              /* If it's not, compare. There should always be a name. */
    183183                              g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) &&
    184                                                 /* If handler.parent == NULL, it's a match. */
     184                            /* If handler.parent == NULL, it's a match. */
    185185                            ( xt->handlers[i].parent == NULL ||
    186                                                 /* If there's a parent node, see if the name matches. */
     186                              /* If there's a parent node, see if the name matches. */
    187187                              ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 :
    188                                                 /* If there's no parent, the handler should mention <root> as a parent. */
    189                                                g_strcasecmp( xt->handlers[i].parent, "<root>" ) == 0 ) ) )
     188                              /* If there's no parent, the handler should mention <root> as a parent. */
     189                                               strcmp( xt->handlers[i].parent, "<root>" ) == 0 ) ) )
    190190                        {
    191191                                st = xt->handlers[i].func( node, xt->data );
     
    260260}
    261261
     262struct xt_node *xt_from_string( const char *in )
     263{
     264        struct xt_parser *parser;
     265        struct xt_node *ret;
     266       
     267        parser = xt_new( NULL, NULL );
     268        xt_feed( parser, in, strlen( in ) );
     269        ret = parser->root;
     270        parser->root = NULL;
     271        xt_free( parser );
     272       
     273        return ret;
     274}
     275
    262276static void xt_to_string_real( struct xt_node *node, GString *str )
    263277{
     
    317331        /* Indentation */
    318332        for( c = node; c->parent; c = c->parent )
    319                 printf( "\t" );
     333                printf( "    " );
    320334       
    321335        /* Start the tag */
     
    324338        /* Print the attributes */
    325339        for( i = 0; node->attr[i].key; i ++ )
    326                 printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) );
     340        {
     341                char *v = g_markup_escape_text( node->attr[i].value, -1 );
     342                printf( " %s=\"%s\"", node->attr[i].key, v );
     343                g_free( v );
     344        }
    327345       
    328346        /* /> in case there's really *nothing* inside this tag, otherwise
     
    344362                for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ );
    345363                if( node->text[i] )
    346                         printf( "%s", g_markup_escape_text( node->text, -1 ) );
     364                {
     365                        char *v = g_markup_escape_text( node->text, -1 );
     366                        printf( "%s", v );
     367                        g_free( v );
     368                }
    347369        }
    348370       
     
    355377        if( node->children )
    356378                for( c = node; c->parent; c = c->parent )
    357                         printf( "\t" );
     379                        printf( "    " );
    358380       
    359381        /* Non-empty tag is now finished. */
     
    460482               
    461483                node = node->next;
     484        }
     485       
     486        return node;
     487}
     488
     489/* More advanced than the one above, understands something like
     490   ../foo/bar to find a subnode bar of a node foo which is a child
     491   of node's parent. Pass the node directly, not its list of children. */
     492struct xt_node *xt_find_path( struct xt_node *node, const char *name )
     493{
     494        while( name && *name && node )
     495        {
     496                char *colon, *slash;
     497                int n;
     498               
     499                if( ( slash = strchr( name, '/' ) ) )
     500                        n = slash - name;
     501                else
     502                        n = strlen( name );
     503               
     504                if( strncmp( name, "..", n ) == 0 )
     505                {
     506                        node = node->parent;
     507                }
     508                else
     509                {
     510                        node = node->children;
     511                       
     512                        while( node )
     513                        {
     514                                if( g_strncasecmp( node->name, name, n ) == 0 ||
     515                                    ( ( colon = strchr( node->name, ':' ) ) &&
     516                                      g_strncasecmp( colon + 1, name, n ) == 0 ) )
     517                                        break;
     518                               
     519                                node = node->next;
     520                        }
     521                }
     522               
     523                name = slash ? slash + 1 : NULL;
    462524        }
    463525       
     
    550612}
    551613
     614/* Same, but at the beginning. */
     615void xt_insert_child( struct xt_node *parent, struct xt_node *child )
     616{
     617        struct xt_node *node, *last;
     618       
     619        for( node = child; node; node = node->next )
     620        {
     621                if( node->parent != NULL )
     622                {
     623                        /* ERROR CONDITION: They seem to have a parent already??? */
     624                }
     625               
     626                node->parent = parent;
     627                last = node;
     628        }
     629       
     630        last->next = parent->children;
     631        parent->children = child;
     632}
     633
    552634void xt_add_attr( struct xt_node *node, const char *key, const char *value )
    553635{
  • lib/xmltree.h

    red320e8 r975708a  
    7979struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data );
    8080void xt_reset( struct xt_parser *xt );
    81 int xt_feed( struct xt_parser *xt, char *text, int text_len );
     81int xt_feed( struct xt_parser *xt, const char *text, int text_len );
    8282int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth );
    8383void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth );
     84struct xt_node *xt_from_string( const char *in );
    8485char *xt_to_string( struct xt_node *node );
    8586void xt_print( struct xt_node *node );
     
    8889void xt_free( struct xt_parser *xt );
    8990struct xt_node *xt_find_node( struct xt_node *node, const char *name );
     91struct xt_node *xt_find_path( struct xt_node *node, const char *name );
    9092char *xt_find_attr( struct xt_node *node, const char *key );
    9193
    9294struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children );
    9395void xt_add_child( struct xt_node *parent, struct xt_node *child );
     96void xt_insert_child( struct xt_node *parent, struct xt_node *child );
    9497void xt_add_attr( struct xt_node *node, const char *key, const char *value );
    9598int xt_remove_attr( struct xt_node *node, const char *key );
  • protocols/bee.h

    red320e8 r975708a  
    151151 * - 'state' and 'message' can be NULL */
    152152G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message );
     153G_MODULE_EXPORT void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message );
    153154G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle );
    154155/* Call when a handle says something. 'flags' and 'sent_at may be just 0. */
  • protocols/bee_user.c

    red320e8 r975708a  
    187187        /* TODO(wilmer): OPT_AWAY, or just state == NULL ? */
    188188        bu->flags = flags;
    189         bu->status = g_strdup( ( flags & OPT_AWAY ) && state == NULL ? "Away" : state );
    190189        bu->status_msg = g_strdup( message );
     190        if( state && *state )
     191                bu->status = g_strdup( state );
     192        else if( flags & OPT_AWAY )
     193                bu->status = g_strdup( "Away" );
     194        else
     195                bu->status = NULL;
    191196       
    192197        if( bu->status == NULL && ( flags & OPT_MOBILE ) &&
     
    205210}
    206211
     212/* Same, but only change the away/status message, not any away/online state info. */
     213void imcb_buddy_status_msg( struct im_connection *ic, const char *handle, const char *message )
     214{
     215        bee_t *bee = ic->bee;
     216        bee_user_t *bu, *old;
     217       
     218        if( !( bu = bee_user_by_handle( bee, ic, handle ) ) )
     219        {
     220                return;
     221        }
     222       
     223        old = g_memdup( bu, sizeof( bee_user_t ) );
     224       
     225        bu->status_msg = message && *message ? g_strdup( message ) : NULL;
     226       
     227        if( bee->ui->user_status )
     228                bee->ui->user_status( bee, bu, old );
     229       
     230        g_free( old->status_msg );
     231        g_free( old );
     232}
     233
    207234void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle )
    208235{
  • protocols/msn/Makefile

    red320e8 r975708a  
    1313
    1414# [SH] Program variables
    15 objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
     15objects = msn.o msn_util.o ns.o sb.o soap.o tables.o
    1616
    1717LFLAGS += -r
  • protocols/msn/msn.c

    red320e8 r975708a  
    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
     
    2525
    2626#include "nogaim.h"
     27#include "soap.h"
    2728#include "msn.h"
    2829
     
    3536static void msn_init( account_t *acc )
    3637{
    37         set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc );
    38         set_add( &acc->set, "local_display_name", "false", set_eval_bool, acc );
     38        set_t *s;
     39       
     40        s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc );
     41        s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
     42       
    3943        set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc );
    4044        set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc );
     45       
     46        acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE;
    4147}
    4248
     
    4753       
    4854        ic->proto_data = md;
    49         md->fd = -1;
    5055       
    5156        if( strchr( acc->user, '@' ) == NULL )
     
    5661        }
    5762       
    58         imcb_log( ic, "Connecting" );
    59        
    60         md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic );
    61         if( md->fd < 0 )
    62         {
    63                 imcb_error( ic, "Could not connect to server" );
    64                 imc_logout( ic, TRUE );
    65                 return;
    66         }
    67        
    6863        md->ic = ic;
    6964        md->away_state = msn_away_state_list;
    70        
    71         msn_connections = g_slist_append( msn_connections, ic );
     65        md->domaintree = g_tree_new( msn_domaintree_cmp );
     66        md->ns->fd = -1;
     67       
     68        msn_connections = g_slist_prepend( msn_connections, ic );
     69       
     70        imcb_log( ic, "Connecting" );
     71        msn_ns_connect( ic, md->ns, MSN_NS_HOST, MSN_NS_PORT );
    7272}
    7373
     
    7676        struct msn_data *md = ic->proto_data;
    7777        GSList *l;
     78        int i;
    7879       
    7980        if( md )
     
    8586                */
    8687               
    87                 if( md->fd >= 0 )
    88                         closesocket( md->fd );
    89                
    90                 if( md->handler )
    91                 {
    92                         if( md->handler->rxq ) g_free( md->handler->rxq );
    93                         if( md->handler->cmd_text ) g_free( md->handler->cmd_text );
    94                         g_free( md->handler );
    95                 }
     88                msn_ns_close( md->ns );
    9689               
    9790                while( md->switchboards )
     
    9992               
    10093                msn_msgq_purge( ic, &md->msgq );
    101                
    102                 while( md->groupcount > 0 )
    103                         g_free( md->grouplist[--md->groupcount] );
    104                 g_free( md->grouplist );
     94                msn_soapq_flush( ic, FALSE );
     95               
     96                for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ )
     97                        g_free( md->tokens[i] );
     98                g_free( md->lock_key );
     99                g_free( md->pp_policy );
     100               
     101                while( md->groups )
     102                {
     103                        struct msn_group *mg = md->groups->data;
     104                        g_free( mg->id );
     105                        g_free( mg->name );
     106                        g_free( mg );
     107                        md->groups = g_slist_remove( md->groups, mg );
     108                }
     109               
     110                g_tree_destroy( md->domaintree );
     111                md->domaintree = NULL;
    105112               
    106113                while( md->grpq )
     
    134141        if( strcmp( who, "raw" ) == 0 )
    135142        {
    136                 msn_write( ic, message, strlen( message ) );
    137                 msn_write( ic, "\r\n", 2 );
     143                msn_ns_write( ic, -1, "%s\r\n", message );
    138144        }
    139145        else
     
    173179static void msn_set_away( struct im_connection *ic, char *state, char *message )
    174180{
    175         char buf[1024];
     181        char *uux;
    176182        struct msn_data *md = ic->proto_data;
    177183       
     
    181187                md->away_state = msn_away_state_list + 1;
    182188       
    183         g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code );
    184         msn_write( ic, buf, strlen( buf ) );
    185 }
    186 
    187 static void msn_set_my_name( struct im_connection *ic, char *info )
    188 {
    189         msn_set_display_name( ic, info );
     189        if( !msn_ns_write( ic, -1, "CHG %d %s\r\n", ++md->trId, md->away_state->code ) )
     190                return;
     191       
     192        uux = g_markup_printf_escaped( "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia>"
     193                                       "</Data>", message ? message : "" );
     194        msn_ns_write( ic, -1, "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux );
     195        g_free( uux );
    190196}
    191197
     
    200206        struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who );
    201207       
    202         msn_buddy_list_add( ic, "FL", who, who, group );
     208        msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group );
    203209        if( bu && bu->group )
    204                 msn_buddy_list_remove( ic, "FL", who, bu->group->name );
     210                msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name );
    205211}
    206212
    207213static void msn_remove_buddy( struct im_connection *ic, char *who, char *group )
    208214{
    209         msn_buddy_list_remove( ic, "FL", who, NULL );
     215        msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL );
    210216}
    211217
     
    267273static void msn_keepalive( struct im_connection *ic )
    268274{
    269         msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) );
     275        msn_ns_write( ic, -1, "PNG\r\n" );
    270276}
    271277
    272278static void msn_add_permit( struct im_connection *ic, char *who )
    273279{
    274         msn_buddy_list_add( ic, "AL", who, who, NULL );
     280        msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL );
    275281}
    276282
    277283static void msn_rem_permit( struct im_connection *ic, char *who )
    278284{
    279         msn_buddy_list_remove( ic, "AL", who, NULL );
     285        msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL );
    280286}
    281287
     
    284290        struct msn_switchboard *sb;
    285291       
    286         msn_buddy_list_add( ic, "BL", who, who, NULL );
     292        msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL );
    287293       
    288294        /* If there's still a conversation with this person, close it. */
     
    295301static void msn_rem_deny( struct im_connection *ic, char *who )
    296302{
    297         msn_buddy_list_remove( ic, "BL", who, NULL );
     303        msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL );
    298304}
    299305
     
    314320        account_t *acc = set->data;
    315321        struct im_connection *ic = acc->ic;
    316        
    317         /* Allow any name if we're offline. */
    318         if( ic == NULL )
    319                 return value;
     322        struct msn_data *md = ic->proto_data;
    320323       
    321324        if( strlen( value ) > 129 )
     
    325328        }
    326329       
    327         /* Returning NULL would be better, because the server still has to
    328            confirm the name change. However, it looks a bit confusing to the
    329            user. */
    330         return msn_set_display_name( ic, value ) ? value : NULL;
     330        if( md->flags & MSN_GOT_PROFILE_DN )
     331                imcb_log( ic, "Warning: Persistent name changes for this account have to be done "
     332                              "in the profile. BitlBee doesn't currently support this." );
     333       
     334        msn_soap_addressbook_set_display_name( ic, value );
     335        return msn_ns_set_display_name( ic, value ) ? value : NULL;
     336}
     337
     338static void msn_buddy_data_add( bee_user_t *bu )
     339{
     340        struct msn_data *md = bu->ic->proto_data;
     341        bu->data = g_new0( struct msn_buddy_data, 1 );
     342        g_tree_insert( md->domaintree, bu->handle, bu );
     343}
     344
     345static void msn_buddy_data_free( bee_user_t *bu )
     346{
     347        struct msn_data *md = bu->ic->proto_data;
     348        g_tree_remove( md->domaintree, bu->handle );
     349        g_free( bu->data );
    331350}
    332351
     
    343362        ret->set_away = msn_set_away;
    344363        ret->get_info = msn_get_info;
    345         ret->set_my_name = msn_set_my_name;
    346364        ret->add_buddy = msn_add_buddy;
    347365        ret->remove_buddy = msn_remove_buddy;
     
    357375        ret->send_typing = msn_send_typing;
    358376        ret->handle_cmp = g_strcasecmp;
     377        ret->buddy_data_add = msn_buddy_data_add;
     378        ret->buddy_data_free = msn_buddy_data_free;
     379       
    359380        //ret->transfer_request = msn_ftp_transfer_request;
    360381
  • protocols/msn/msn.h

    red320e8 r975708a  
    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
     
    3939#endif
    4040
    41 #define QRY_NAME "msmsgs@msnmsgr.com"
    42 #define QRY_CODE "Q1P7W2E4J9R8U3S5"
     41/* This should be MSN Messenger 7.0.0813
     42#define MSNP11_PROD_KEY "CFHUR$52U_{VIX5T"
     43#define MSNP11_PROD_ID  "PROD0101{0RM?UBW"
     44*/
     45
     46#define MSN_NS_HOST "messenger.hotmail.com"
     47#define MSN_NS_PORT 1863
     48
     49/* Some other version.
     50#define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G"
     51#define MSNP11_PROD_ID  "PROD01065C%ZFN6F"
     52*/
     53
     54#define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX"
     55#define MSNP11_PROD_ID  "PROD0119GSJUC$18"
     56#define MSNP_VER        "MSNP15"
     57#define MSNP_BUILD      "8.5.1288"
    4358
    4459#define MSN_SB_NEW         -24062002
     
    6176#define PROFILE_URL "http://members.msn.com/"
    6277
     78typedef enum
     79{
     80        MSN_GOT_PROFILE = 1,
     81        MSN_GOT_PROFILE_DN = 2,
     82        MSN_DONE_ADL = 4,
     83        MSN_REAUTHING = 8,
     84} msn_flags_t;
     85
     86struct msn_handler_data
     87{
     88        int fd, inpa;
     89        int rxlen;
     90        char *rxq;
     91       
     92        int msglen;
     93        char *cmd_text;
     94       
     95        /* Either ic or sb */
     96        gpointer data;
     97       
     98        int (*exec_command) ( struct msn_handler_data *handler, char **cmd, int count );
     99        int (*exec_message) ( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int count );
     100};
     101
    63102struct msn_data
    64103{
    65104        struct im_connection *ic;
    66105       
    67         int fd;
    68         struct msn_handler_data *handler;
     106        struct msn_handler_data ns[1];
     107        msn_flags_t flags;
    69108       
    70109        int trId;
    71        
    72         GSList *msgq, *grpq;
     110        char *tokens[4];
     111        char *lock_key, *pp_policy;
     112       
     113        GSList *msgq, *grpq, *soapq;
    73114        GSList *switchboards;
    74115        int sb_failures;
    75116        time_t first_sb_failure;
    76         GSList *filetransfers;
    77117       
    78118        const struct msn_away_state *away_state;
    79         int buddycount;
    80         int groupcount;
    81         char **grouplist;
     119        GSList *groups;
     120       
     121        /* Mostly used for sending the ADL command; since MSNP13 the client
     122           is responsible for downloading the contact list and then sending
     123           it to the MSNP server. */
     124        GTree *domaintree;
     125        int adl_todo;
    82126};
    83127
     
    86130        struct im_connection *ic;
    87131       
     132        /* The following two are also in the handler. TODO: Clean up. */
    88133        int fd;
    89134        gint inp;
     
    127172};
    128173
    129 struct msn_handler_data
    130 {
    131         int fd;
    132         int rxlen;
    133         char *rxq;
    134        
    135         int msglen;
    136         char *cmd_text;
    137        
    138         gpointer data;
    139        
    140         int (*exec_command) ( gpointer data, char **cmd, int count );
    141         int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count );
     174typedef enum
     175{
     176        MSN_BUDDY_FL = 1,   /* Warning: FL,AL,BL *must* be 1,2,4. */
     177        MSN_BUDDY_AL = 2,
     178        MSN_BUDDY_BL = 4,
     179        MSN_BUDDY_RL = 8,
     180        MSN_BUDDY_PL = 16,
     181        MSN_BUDDY_ADL_SYNCED = 256,
     182} msn_buddy_flags_t;
     183
     184struct msn_buddy_data
     185{
     186        char *cid;
     187        msn_buddy_flags_t flags;
     188};
     189
     190struct msn_group
     191{
     192        char *name;
     193        char *id;
    142194};
    143195
     
    161213
    162214/* ns.c */
    163 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
     215int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... );
     216gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port );
     217void msn_ns_close( struct msn_handler_data *handler );
     218void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error );
     219void msn_auth_got_contact_list( struct im_connection *ic );
     220int msn_ns_finish_login( struct im_connection *ic );
    164221
    165222/* msn_util.c */
    166 int msn_write( struct im_connection *ic, char *s, int len );
    167223int msn_logged_in( struct im_connection *ic );
    168 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group );
    169 int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group );
    170 void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname );
     224int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group );
     225int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group );
     226void msn_buddy_ask( bee_user_t *bu );
    171227char *msn_findheader( char *text, char *header, int len );
    172228char **msn_linesplit( char *line );
    173229int msn_handler( struct msn_handler_data *h );
    174 char *msn_http_encode( const char *input );
    175230void msn_msgq_purge( struct im_connection *ic, GSList **list );
    176 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname );
     231char *msn_p11_challenge( char *challenge );
     232gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ );
     233struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name );
     234struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id );
     235int msn_ns_set_display_name( struct im_connection *ic, const char *value );
    177236
    178237/* tables.c */
     
    183242
    184243/* sb.c */
    185 int msn_sb_write( struct msn_switchboard *sb, char *s, int len );
     244int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... );
    186245struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session );
    187246struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle );
     
    196255void msn_sb_stop_keepalives( struct msn_switchboard *sb );
    197256
    198 /* invitation.c */
    199 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
    200 
    201257#endif //_MSN_H
  • protocols/msn/msn_util.c

    red320e8 r975708a  
    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
     
    2626#include "nogaim.h"
    2727#include "msn.h"
     28#include "md5.h"
     29#include "soap.h"
    2830#include <ctype.h>
    2931
    30 int msn_write( struct im_connection *ic, char *s, int len )
     32int msn_logged_in( struct im_connection *ic )
     33{
     34        imcb_connected( ic );
     35       
     36        return( 0 );
     37}
     38
     39static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list )
     40{
     41        char *domain, handle[strlen(handle_)+1];
     42       
     43        strcpy( handle, handle_ );
     44        if( ( domain = strchr( handle, '@' ) ) )
     45                *(domain++) = '\0';
     46        else
     47                return NULL;
     48       
     49        return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>",
     50                domain, handle, list );
     51}
     52
     53int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group )
    3154{
    3255        struct msn_data *md = ic->proto_data;
    33         int st;
    34        
    35         st = write( md->fd, s, len );
    36         if( st != len )
    37         {
    38                 imcb_error( ic, "Short write() to main server" );
    39                 imc_logout( ic, TRUE );
    40                 return 0;
    41         }
    42        
    43         return 1;
    44 }
    45 
    46 int msn_logged_in( struct im_connection *ic )
    47 {
    48         imcb_connected( ic );
    49        
    50         return( 0 );
    51 }
    52 
    53 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group )
    54 {
    55         struct msn_data *md = ic->proto_data;
    56         char buf[1024], *realname, groupid[8];
     56        char groupid[8];
     57        bee_user_t *bu;
     58        struct msn_buddy_data *bd;
     59        char *adl;
    5760       
    5861        *groupid = '\0';
     62#if 0
    5963        if( group )
    6064        {
     
    8791                        if( l == NULL )
    8892                        {
    89                                 char *groupname = msn_http_encode( group );
     93                                char groupname[strlen(group)+1];
     94                                strcpy( groupname, group );
     95                                http_encode( groupname );
    9096                                g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 );
    91                                 g_free( groupname );
    9297                                return msn_write( ic, buf, strlen( buf ) );
    9398                        }
     
    101106                }
    102107        }
    103        
    104         realname = msn_http_encode( realname_ );
    105         g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid );
    106         g_free( realname );
    107        
    108         return msn_write( ic, buf, strlen( buf ) );
    109 }
    110 
    111 int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group )
     108#endif
     109       
     110        if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
     111               ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) ||
     112            !( bd = bu->data ) || bd->flags & list )
     113                return 1;
     114       
     115        bd->flags |= list;
     116       
     117        if( list == MSN_BUDDY_FL )
     118                msn_soap_ab_contact_add( ic, bu );
     119        else
     120                msn_soap_memlist_edit( ic, who, TRUE, list );
     121       
     122        if( ( adl = adlrml_entry( who, list ) ) )
     123        {
     124                int st = msn_ns_write( ic, -1, "ADL %d %zd\r\n%s",
     125                                       ++md->trId, strlen( adl ), adl );
     126                g_free( adl );
     127               
     128                return st;
     129        }
     130       
     131        return 1;
     132}
     133
     134int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group )
    112135{
    113136        struct msn_data *md = ic->proto_data;
    114         char buf[1024], groupid[8];
     137        char groupid[8];
     138        bee_user_t *bu;
     139        struct msn_buddy_data *bd;
     140        char *adl;
    115141       
    116142        *groupid = '\0';
     143#if 0
    117144        if( group )
    118145        {
     
    125152                        }
    126153        }
    127        
    128         g_snprintf( buf, sizeof( buf ), "REM %d %s %s%s\r\n", ++md->trId, list, who, groupid );
    129         if( msn_write( ic, buf, strlen( buf ) ) )
    130                 return( 1 );
    131        
    132         return( 0 );
     154#endif
     155       
     156        if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
     157            !( bd = bu->data ) || !( bd->flags & list ) )
     158                return 1;
     159       
     160        bd->flags &= ~list;
     161       
     162        if( list == MSN_BUDDY_FL )
     163                msn_soap_ab_contact_del( ic, bu );
     164        else
     165                msn_soap_memlist_edit( ic, who, FALSE, list );
     166       
     167        if( ( adl = adlrml_entry( who, list ) ) )
     168        {
     169                int st = msn_ns_write( ic, -1, "RML %d %zd\r\n%s",
     170                                       ++md->trId, strlen( adl ), adl );
     171                g_free( adl );
     172               
     173                return st;
     174        }
     175       
     176        return 1;
    133177}
    134178
     
    144188        struct msn_buddy_ask_data *bla = data;
    145189       
    146         msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL );
     190        msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL );
    147191       
    148192        imcb_ask_add( bla->ic, bla->handle, NULL );
     
    157201        struct msn_buddy_ask_data *bla = data;
    158202       
    159         msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL );
     203        msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL );
    160204       
    161205        g_free( bla->handle );
     
    164208}
    165209
    166 void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname )
    167 {
    168         struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 );
     210void msn_buddy_ask( bee_user_t *bu )
     211{
     212        struct msn_buddy_ask_data *bla;
     213        struct msn_buddy_data *bd = bu->data;
    169214        char buf[1024];
    170215       
    171         bla->ic = ic;
    172         bla->handle = g_strdup( handle );
    173         bla->realname = g_strdup( realname );
     216        if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 )
     217                return;
     218       
     219        bla = g_new0( struct msn_buddy_ask_data, 1 );
     220        bla->ic = bu->ic;
     221        bla->handle = g_strdup( bu->handle );
     222        bla->realname = g_strdup( bu->fullname );
    174223       
    175224        g_snprintf( buf, sizeof( buf ),
    176225                    "The user %s (%s) wants to add you to his/her buddy list.",
    177                     handle, realname );
    178         imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );
     226                    bu->handle, bu->fullname );
     227        imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );
    179228}
    180229
     
    279328        if( st <= 0 )
    280329                return( -1 );
     330       
     331        if( getenv( "BITLBEE_DEBUG" ) )
     332        {
     333                write( 2, "->C:", 4 );
     334                write( 2, h->rxq + h->rxlen - st, st );
     335        }
    281336       
    282337        while( st )
     
    296351                                        cmd = msn_linesplit( cmd_text );
    297352                                        for( count = 0; cmd[count]; count ++ );
    298                                         st = h->exec_command( h->data, cmd, count );
     353                                        st = h->exec_command( h, cmd, count );
    299354                                        g_free( cmd_text );
    300355                                       
     
    331386                        for( count = 0; cmd[count]; count ++ );
    332387                       
    333                         st = h->exec_message( h->data, msg, h->msglen, cmd, count );
     388                        st = h->exec_message( h, msg, h->msglen, cmd, count );
    334389                        g_free( msg );
    335390                        g_free( h->cmd_text );
     
    367422}
    368423
    369 /* The difference between this function and the normal http_encode() function
    370    is that this one escapes every 7-bit ASCII character because this is said
    371    to avoid some lame server-side checks when setting a real-name. Also,
    372    non-ASCII characters are not escaped because MSN servers don't seem to
    373    appreciate that! */
    374 char *msn_http_encode( const char *input )
    375 {
    376         char *ret, *s;
    377         int i;
    378        
    379         ret = s = g_new0( char, strlen( input ) * 3 + 1 );
    380         for( i = 0; input[i]; i ++ )
    381                 if( input[i] & 128 )
    382                 {
    383                         *s = input[i];
    384                         s ++;
    385                 }
    386                 else
    387                 {
    388                         g_snprintf( s, 4, "%%%02X", input[i] );
    389                         s += 3;
    390                 }
    391        
    392         return ret;
    393 }
    394 
    395424void msn_msgq_purge( struct im_connection *ic, GSList **list )
    396425{
     
    433462}
    434463
    435 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname )
    436 {
    437         char *fn = msn_http_encode( rawname );
     464/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
     465char *msn_p11_challenge( char *challenge )
     466{
     467        char *output, buf[256];
     468        md5_state_t md5c;
     469        unsigned char md5Hash[16], *newHash;
     470        unsigned int *md5Parts, *chlStringParts, newHashParts[5];
     471        long long nHigh = 0, nLow = 0;
     472        int i, n;
     473
     474        /* Create the MD5 hash */
     475        md5_init(&md5c);
     476        md5_append(&md5c, (unsigned char*) challenge, strlen(challenge));
     477        md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY));
     478        md5_finish(&md5c, md5Hash);
     479
     480        /* Split it into four integers */
     481        md5Parts = (unsigned int *)md5Hash;
     482        for (i = 0; i < 4; i ++)
     483        { 
     484                md5Parts[i] = GUINT32_TO_LE(md5Parts[i]);
     485               
     486                /* & each integer with 0x7FFFFFFF */
     487                /* and save one unmodified array for later */
     488                newHashParts[i] = md5Parts[i];
     489                md5Parts[i] &= 0x7FFFFFFF;
     490        }
     491       
     492        /* make a new string and pad with '0' */
     493        n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID);
     494        /* truncate at an 8-byte boundary */
     495        buf[n&=~7] = '\0';
     496       
     497        /* split into integers */
     498        chlStringParts = (unsigned int *)buf;
     499       
     500        /* this is magic */
     501        for (i = 0; i < (n / 4) - 1; i += 2)
     502        {
     503                long long temp;
     504
     505                chlStringParts[i]   = GUINT32_TO_LE(chlStringParts[i]);
     506                chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]);
     507
     508                temp  = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF;
     509                nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF;
     510                nLow  = nLow + nHigh + temp;
     511        }
     512        nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF;
     513        nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF;
     514       
     515        newHashParts[0] ^= nHigh;
     516        newHashParts[1] ^= nLow;
     517        newHashParts[2] ^= nHigh;
     518        newHashParts[3] ^= nLow;
     519       
     520        /* swap more bytes if big endian */
     521        for (i = 0; i < 4; i ++)
     522                newHashParts[i] = GUINT32_TO_LE(newHashParts[i]);
     523       
     524        /* make a string of the parts */
     525        newHash = (unsigned char *)newHashParts;
     526       
     527        /* convert to hexadecimal */
     528        output = g_new(char, 33);
     529        for (i = 0; i < 16; i ++)
     530                sprintf(output + i * 2, "%02x", newHash[i]);
     531       
     532        return output;
     533}
     534
     535gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ )
     536{
     537        const char *a = a_, *b = b_;
     538        gint ret;
     539       
     540        if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) ||
     541            ( ret = strcmp( a, b ) ) == 0 )
     542                ret = strcmp( a_, b_ );
     543       
     544        return ret;
     545}
     546
     547struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name )
     548{
    438549        struct msn_data *md = ic->proto_data;
    439         char buf[1024];
    440        
    441         g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn );
    442         g_free( fn );
    443        
    444         return msn_write( ic, buf, strlen( buf ) ) != 0;
    445 }
     550        GSList *l;
     551       
     552        for( l = md->groups; l; l = l->next )
     553        {
     554                struct msn_group *mg = l->data;
     555               
     556                if( g_strcasecmp( mg->name, name ) == 0 )
     557                        return mg;
     558        }
     559       
     560        return NULL;
     561}
     562
     563struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id )
     564{
     565        struct msn_data *md = ic->proto_data;
     566        GSList *l;
     567       
     568        for( l = md->groups; l; l = l->next )
     569        {
     570                struct msn_group *mg = l->data;
     571               
     572                if( g_strcasecmp( mg->id, id ) == 0 )
     573                        return mg;
     574        }
     575       
     576        return NULL;
     577}
     578
     579int msn_ns_set_display_name( struct im_connection *ic, const char *value )
     580{
     581        struct msn_data *md = ic->proto_data;
     582        char fn[strlen(value)*3+1];
     583       
     584        strcpy( fn, value );
     585        http_encode( fn );
     586       
     587        /* Note: We don't actually know if the server accepted the new name,
     588           and won't give proper feedback yet if it doesn't. */
     589        return msn_ns_write( ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn );
     590}
  • protocols/msn/ns.c

    red320e8 r975708a  
    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}
  • protocols/msn/sb.c

    red320e8 r975708a  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2005 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"
    3131#include "invitation.h"
    3232
    3333static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond );
    34 static int msn_sb_command( gpointer data, char **cmd, int num_parts );
    35 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    36 
    37 int msn_sb_write( struct msn_switchboard *sb, char *s, int len )
    38 {
     34static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts );
     35static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts );
     36
     37int msn_sb_write( struct msn_switchboard *sb, const char *fmt, ... )
     38{
     39        va_list params;
     40        char *out;
     41        size_t len;
    3942        int st;
    4043       
    41         st = write( sb->fd, s, len );
     44        va_start( params, fmt );
     45        out = g_strdup_vprintf( fmt, params );
     46        va_end( params );
     47       
     48        if( getenv( "BITLBEE_DEBUG" ) )
     49                fprintf( stderr, "->SB%d:%s", sb->fd, out );
     50       
     51        len = strlen( out );
     52        st = write( sb->fd, out, len );
     53        g_free( out );
    4254        if( st != len )
    4355        {
    4456                msn_sb_destroy( sb );
    45                 return( 0 );
    46         }
    47        
    48         return( 1 );
     57                return 0;
     58        }
     59       
     60        return 1;
    4961}
    5062
     
    5365        struct msn_data *md = ic->proto_data;
    5466        struct msn_switchboard *sb;
    55         char buf[1024];
    5667
    5768        /* FIXME: *CHECK* the reliability of using spare sb's! */
     
    6172               
    6273                sb->who = g_strdup( m->who );
    63                 g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who );
    64                 if( msn_sb_write( sb, buf, strlen( buf ) ) )
     74                if( msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, m->who ) )
    6575                {
    6676                        /* He/She should join the switchboard soon, let's queue the message. */
     
    7383       
    7484        /* If we reach this line, there was no spare switchboard, so let's make one. */
    75         g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
    76         if( !msn_write( ic, buf, strlen( buf ) ) )
     85        if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )
    7786        {
    7887                g_free( m->who );
     
    165174        if( sb->ready )
    166175        {
    167                 char *packet, *buf;
     176                char *buf;
    168177                int i, j;
    169178               
     
    201210               
    202211                /* Build the final packet (MSG command + the message). */
    203                 packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf );
    204                 g_free( buf );
    205                 if( msn_sb_write( sb, packet, strlen( packet ) ) )
    206                 {
    207                         g_free( packet );
    208                         return( 1 );
     212                if( msn_sb_write( sb, "MSG %d N %d\r\n%s", ++sb->trId, i, buf ) )
     213                {
     214                        g_free( buf );
     215                        return 1;
    209216                }
    210217                else
    211218                {
    212                         g_free( packet );
    213                         return( 0 );
     219                        g_free( buf );
     220                        return 0;
    214221                }
    215222        }
     
    326333                g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session );
    327334       
    328         if( msn_sb_write( sb, buf, strlen( buf ) ) )
     335        if( msn_sb_write( sb, "%s", buf ) )
    329336                sb->inp = b_input_add( sb->fd, B_EV_IO_READ, msn_sb_callback, sb );
    330337        else
     
    346353        {
    347354                time_t now = time( NULL );
    348                 char buf[1024];
    349355               
    350356                if( now - md->first_sb_failure > 600 )
     
    378384                debug( "Moved queued messages back to the main queue, "
    379385                       "creating a new switchboard to retry." );
    380                 g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId );
    381                 if( !msn_write( ic, buf, strlen( buf ) ) )
     386                if( !msn_ns_write( ic, -1, "XFR %d SB\r\n", ++md->trId ) )
    382387                        return FALSE;
    383388        }
     
    387392}
    388393
    389 static int msn_sb_command( gpointer data, char **cmd, int num_parts )
    390 {
    391         struct msn_switchboard *sb = data;
     394static int msn_sb_command( struct msn_handler_data *handler, char **cmd, int num_parts )
     395{
     396        struct msn_switchboard *sb = handler->data;
    392397        struct im_connection *ic = sb->ic;
    393         char buf[1024];
    394398       
    395399        if( !num_parts )
     
    407411        else if( strcmp( cmd[0], "USR" ) == 0 )
    408412        {
    409                 if( num_parts != 5 )
     413                if( num_parts < 5 )
    410414                {
    411415                        msn_sb_destroy( sb );
     
    420424               
    421425                if( sb->who )
    422                 {
    423                         g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, sb->who );
    424                         return( msn_sb_write( sb, buf, strlen( buf ) ) );
    425                 }
     426                        return msn_sb_write( sb, "CAL %d %s\r\n", ++sb->trId, sb->who );
    426427                else
    427                 {
    428428                        debug( "Just created a switchboard, but I don't know what to do with it." );
    429                 }
    430429        }
    431430        else if( strcmp( cmd[0], "IRO" ) == 0 )
     
    433432                int num, tot;
    434433               
    435                 if( num_parts != 6 )
     434                if( num_parts < 6 )
    436435                {
    437436                        msn_sb_destroy( sb );
     
    470469        else if( strcmp( cmd[0], "ANS" ) == 0 )
    471470        {
    472                 if( num_parts != 3 )
     471                if( num_parts < 3 )
    473472                {
    474473                        msn_sb_destroy( sb );
     
    489488        else if( strcmp( cmd[0], "CAL" ) == 0 )
    490489        {
    491                 if( num_parts != 4 || !isdigit( cmd[3][0] ) )
     490                if( num_parts < 4 || !isdigit( cmd[3][0] ) )
    492491                {
    493492                        msn_sb_destroy( sb );
     
    499498        else if( strcmp( cmd[0], "JOI" ) == 0 )
    500499        {
    501                 if( num_parts != 3 )
     500                if( num_parts < 3 )
    502501                {
    503502                        msn_sb_destroy( sb );
     
    560559        else if( strcmp( cmd[0], "MSG" ) == 0 )
    561560        {
    562                 if( num_parts != 4 )
     561                if( num_parts < 4 )
    563562                {
    564563                        msn_sb_destroy( sb );
     
    625624                const struct msn_status_code *err = msn_status_by_number( num );
    626625               
    627                 imcb_error( ic, "Error reported by switchboard server: %s", err->text );
     626                /* If the person is offline, send an offline message instead,
     627                   and don't report an error. */
     628                if( num == 217 )
     629                        msn_soap_oim_send_queue( ic, &sb->msgq );
     630                else
     631                        imcb_error( ic, "Error reported by switchboard server: %s", err->text );
    628632               
    629633                if( err->flags & STATUS_SB_FATAL )
     
    661665}
    662666
    663 static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
    664 {
    665         struct msn_switchboard *sb = data;
     667static int msn_sb_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
     668{
     669        struct msn_switchboard *sb = handler->data;
    666670        struct im_connection *ic = sb->ic;
    667671        char *body;
     
    741745                else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0 )
    742746                {
    743                         imcb_error( sb->ic, "Cannot receive file from %s: BitlBee does not "
    744                                         "support msnmsgrp2p yet.", sb->who );
     747                        /* Not currently implemented. Don't warn about it since
     748                           this seems to be used for avatars now. */
    745749                        g_free( ct );
    746750                }
  • protocols/msn/tables.c

    red320e8 r975708a  
    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
     
    8383        { 230, "Cannot remove that group",                              0 },
    8484        { 231, "Invalid group",                                         0 },
     85        { 240, "ADL/RML command with corrupted payload",                STATUS_FATAL },
     86        { 241, "ADL/RML command with invalid modification",             0 },
    8587        { 280, "Switchboard failed",                                    STATUS_SB_FATAL },
    8688        { 281, "Transfer to switchboard failed",                        0 },
  • protocols/nogaim.c

    red320e8 r975708a  
    252252                serv_got_crap( ic, "Error: %s", text );
    253253        else
    254                 serv_got_crap( ic, "Couldn't log in: %s", text );
     254                serv_got_crap( ic, "Login error: %s", text );
    255255       
    256256        g_free( text );
     
    325325       
    326326        imcb_log( ic, "Signing off.." );
    327        
    328         b_event_remove( ic->keepalive );
    329         ic->keepalive = 0;
    330         ic->acc->prpl->logout( ic );
    331         b_event_remove( ic->inpa );
    332        
    333         g_free( ic->away );
    334         ic->away = NULL;
    335327       
    336328        for( l = bee->users; l; )
     
    344336                l = next;
    345337        }
     338       
     339        b_event_remove( ic->keepalive );
     340        ic->keepalive = 0;
     341        ic->acc->prpl->logout( ic );
     342        b_event_remove( ic->inpa );
     343       
     344        g_free( ic->away );
     345        ic->away = NULL;
    346346       
    347347        query_del_by_conn( (irc_t*) ic->bee->ui_data, ic );
  • protocols/nogaim.h

    red320e8 r975708a  
    195195           this info via imcb_log(). Implementing these are optional. */
    196196        void (* get_info)       (struct im_connection *, char *who);
     197        /* set_my_name is *DEPRECATED*, not used by the UI anymore. Use the
     198           display_name setting instead. */
    197199        void (* set_my_name)    (struct im_connection *, char *name);
    198200        void (* set_name)       (struct im_connection *, char *who, char *name);
  • storage_xml.c

    red320e8 r975708a  
    320320        else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting )
    321321        {
     322                if( xd->current_account )
     323                {
     324                        set_t *s = set_find( xd->current_set_head, xd->current_setting );
     325                        if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) )
     326                        {
     327                                g_free( xd->current_setting );
     328                                xd->current_setting = NULL;
     329                                return;
     330                        }
     331                }
    322332                set_setstr( xd->current_set_head, xd->current_setting, (char*) text );
    323333                g_free( xd->current_setting );
Note: See TracChangeset for help on using the changeset viewer.