Changeset 62f53b50


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

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

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

Files:
4 added
2 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • configure

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

    r05bf2a0 r62f53b50  
    5050    for a list of supported protocols (works only in libpurple-enabled
    5151    binaries).
     52- Rewritten MSN module, implementing MSNP15 instead of the old MSNP8:
     53  * MSNP8 support from MSN was getting pretty unreliable. There were issues
     54    with remembering display names and adding contacts/auth requests.
     55  * Support for sending offline messages.
     56  * Support for setting and reading status messages.
    5257- Support for file transfers, in and out. /DCC SEND a file to a contact and
    5358  it becomes a file transfer, and incoming file transfers become /DCC SENDs
  • lib/Makefile

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

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

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

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

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

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

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

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

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

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

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

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

    r05bf2a0 r62f53b50  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    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

    r05bf2a0 r62f53b50  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    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

    r05bf2a0 r62f53b50  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    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

    r05bf2a0 r62f53b50  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2727#include "nogaim.h"
    2828#include "msn.h"
    29 #include "passport.h"
    3029#include "md5.h"
    31 
     30#include "soap.h"
     31#include "xmltree.h"
     32
     33static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
    3234static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );
    33 static int msn_ns_command( gpointer data, char **cmd, int num_parts );
    34 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    35 
    36 static void msn_auth_got_passport_token( struct msn_auth_data *mad );
    37 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name );
    38 
    39 gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
    40 {
    41         struct im_connection *ic = data;
    42         struct msn_data *md;
    43         char s[1024];
    44        
    45         if( !g_slist_find( msn_connections, ic ) )
    46                 return FALSE;
    47        
    48         if( source == -1 )
     35static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts );
     36static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts );
     37
     38static void msn_ns_send_adl_start( struct im_connection *ic );
     39static void msn_ns_send_adl( struct im_connection *ic );
     40
     41int msn_ns_write( struct im_connection *ic, int fd, const char *fmt, ... )
     42{
     43        struct msn_data *md = ic->proto_data;
     44        va_list params;
     45        char *out;
     46        size_t len;
     47        int st;
     48       
     49        va_start( params, fmt );
     50        out = g_strdup_vprintf( fmt, params );
     51        va_end( params );
     52       
     53        if( fd < 0 )
     54                fd = md->ns->fd;
     55       
     56        if( getenv( "BITLBEE_DEBUG" ) )
     57                fprintf( stderr, "->NS%d:%s", fd, out );
     58       
     59        len = strlen( out );
     60        st = write( fd, out, len );
     61        g_free( out );
     62        if( st != len )
     63        {
     64                imcb_error( ic, "Short write() to main server" );
     65                imc_logout( ic, TRUE );
     66                return 0;
     67        }
     68       
     69        return 1;
     70}
     71
     72gboolean msn_ns_connect( struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port )
     73{
     74        if( handler->fd >= 0 )
     75                closesocket( handler->fd );
     76       
     77        handler->exec_command = msn_ns_command;
     78        handler->exec_message = msn_ns_message;
     79        handler->data = ic;
     80        handler->fd = proxy_connect( host, port, msn_ns_connected, handler );
     81        if( handler->fd < 0 )
    4982        {
    5083                imcb_error( ic, "Could not connect to server" );
     
    5386        }
    5487       
     88        return TRUE;
     89}
     90
     91static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
     92{
     93        struct msn_handler_data *handler = data;
     94        struct im_connection *ic = handler->data;
     95        struct msn_data *md;
     96       
     97        if( !g_slist_find( msn_connections, ic ) )
     98                return FALSE;
     99       
    55100        md = ic->proto_data;
    56101       
    57         if( !md->handler )
    58         {
    59                 md->handler = g_new0( struct msn_handler_data, 1 );
    60                 md->handler->data = ic;
    61                 md->handler->exec_command = msn_ns_command;
    62                 md->handler->exec_message = msn_ns_message;
    63         }
    64         else
    65         {
    66                 if( md->handler->rxq )
    67                         g_free( md->handler->rxq );
    68                
    69                 md->handler->rxlen = 0;
    70         }
    71        
    72         md->handler->fd = md->fd;
    73         md->handler->rxq = g_new0( char, 1 );
    74        
    75         g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
    76         if( msn_write( ic, s, strlen( s ) ) )
    77         {
    78                 ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic );
     102        if( source == -1 )
     103        {
     104                imcb_error( ic, "Could not connect to server" );
     105                imc_logout( ic, TRUE );
     106                return FALSE;
     107        }
     108       
     109        g_free( handler->rxq );
     110        handler->rxlen = 0;
     111        handler->rxq = g_new0( char, 1 );
     112       
     113        if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) )
     114        {
     115                handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler );
    79116                imcb_log( ic, "Connected to server, waiting for reply" );
    80117        }
     
    83120}
    84121
     122void msn_ns_close( struct msn_handler_data *handler )
     123{
     124        if( handler->fd >= 0 )
     125        {
     126                closesocket( handler->fd );
     127                b_event_remove( handler->inpa );
     128        }
     129       
     130        handler->fd = handler->inpa = -1;
     131        g_free( handler->rxq );
     132        g_free( handler->cmd_text );
     133       
     134        handler->rxlen = 0;
     135        handler->rxq = NULL;
     136        handler->cmd_text = NULL;
     137}
     138
    85139static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond )
    86140{
    87         struct im_connection *ic = data;
    88         struct msn_data *md = ic->proto_data;
    89        
    90         if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */
     141        struct msn_handler_data *handler = data;
     142        struct im_connection *ic = handler->data;
     143       
     144        if( msn_handler( handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */
    91145        {
    92146                imcb_error( ic, "Error while reading from server" );
     
    99153}
    100154
    101 static int msn_ns_command( gpointer data, char **cmd, int num_parts )
    102 {
    103         struct im_connection *ic = data;
     155static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num_parts )
     156{
     157        struct im_connection *ic = handler->data;
    104158        struct msn_data *md = ic->proto_data;
    105         char buf[1024];
    106159       
    107160        if( num_parts == 0 )
     
    113166        if( strcmp( cmd[0], "VER" ) == 0 )
    114167        {
    115                 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
     168                if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )
    116169                {
    117170                        imcb_error( ic, "Unsupported protocol" );
     
    120173                }
    121174               
    122                 g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
    123                                                 ++md->trId, ic->acc->user );
    124                 return( msn_write( ic, buf, strlen( buf ) ) );
     175                return( msn_ns_write( ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",
     176                                      ++md->trId, ic->acc->user ) );
    125177        }
    126178        else if( strcmp( cmd[0], "CVR" ) == 0 )
    127179        {
    128180                /* We don't give a damn about the information we just received */
    129                 g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user );
    130                 return( msn_write( ic, buf, strlen( buf ) ) );
     181                return msn_ns_write( ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user );
    131182        }
    132183        else if( strcmp( cmd[0], "XFR" ) == 0 )
     
    135186                int port;
    136187               
    137                 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
    138                 {
    139                         b_event_remove( ic->inpa );
    140                         ic->inpa = 0;
    141                         closesocket( md->fd );
     188                if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 )
     189                {
     190                        b_event_remove( handler->inpa );
     191                        handler->inpa = -1;
    142192                       
    143193                        server = strchr( cmd[3], ':' );
     
    153203                       
    154204                        imcb_log( ic, "Transferring to other server" );
    155                        
    156                         md->fd = proxy_connect( server, port, msn_ns_connected, ic );
    157                 }
    158                 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
     205                        return msn_ns_connect( ic, handler, server, port );
     206                }
     207                else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 )
    159208                {
    160209                        struct msn_switchboard *sb;
     
    220269        else if( strcmp( cmd[0], "USR" ) == 0 )
    221270        {
    222                 if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 )
    223                 {
    224                         /* Time for some Passport black magic... */
    225                         if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
    226                         {
    227                                 imcb_error( ic, "Error while contacting Passport server" );
    228                                 imc_logout( ic, TRUE );
    229                                 return( 0 );
    230                         }
    231                 }
    232                 else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 )
    233                 {
    234                         if( num_parts == 7 )
    235                                 msn_ns_got_display_name( ic, cmd[4] );
    236                         else
    237                                 imcb_log( ic, "Warning: Friendly name in server response was corrupted" );
    238                        
     271                if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 &&
     272                    strcmp( cmd[3], "S" ) == 0 )
     273                {
     274                        g_free( md->pp_policy );
     275                        md->pp_policy = g_strdup( cmd[4] );
     276                        msn_soap_passport_sso_request( ic, cmd[5] );
     277                }
     278                else if( strcmp( cmd[2], "OK" ) == 0 )
     279                {
    239280                        imcb_log( ic, "Authenticated, getting buddy list" );
    240                        
    241                         g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId );
    242                         return( msn_write( ic, buf, strlen( buf ) ) );
     281                        msn_soap_memlist_request( ic );
    243282                }
    244283                else
     
    251290        else if( strcmp( cmd[0], "MSG" ) == 0 )
    252291        {
    253                 if( num_parts != 4 )
    254                 {
    255                         imcb_error( ic, "Syntax error" );
    256                         imc_logout( ic, TRUE );
    257                         return( 0 );
    258                 }
    259                
    260                 md->handler->msglen = atoi( cmd[3] );
    261                
    262                 if( md->handler->msglen <= 0 )
    263                 {
    264                         imcb_error( ic, "Syntax error" );
    265                         imc_logout( ic, TRUE );
    266                         return( 0 );
    267                 }
    268         }
    269         else if( strcmp( cmd[0], "SYN" ) == 0 )
    270         {
    271                 if( num_parts == 5 )
    272                 {
    273                         int i, groupcount;
    274                        
    275                         groupcount = atoi( cmd[4] );
    276                         if( groupcount > 0 )
    277                         {
    278                                 /* valgrind says this is leaking memory, I'm guessing
    279                                    that this happens during server redirects. */
    280                                 if( md->grouplist )
    281                                 {
    282                                         for( i = 0; i < md->groupcount; i ++ )
    283                                                 g_free( md->grouplist[i] );
    284                                         g_free( md->grouplist );
    285                                 }
    286                                
    287                                 md->groupcount = groupcount;
    288                                 md->grouplist = g_new0( char *, md->groupcount );
    289                         }
    290                        
    291                         md->buddycount = atoi( cmd[3] );
    292                         if( !*cmd[3] || md->buddycount == 0 )
    293                                 msn_logged_in( ic );
    294                 }
    295                 else
    296                 {
    297                         /* Hrrm... This SYN reply doesn't really look like something we expected.
    298                            Let's assume everything is okay. */
    299                        
    300                         msn_logged_in( ic );
    301                 }
    302         }
    303         else if( strcmp( cmd[0], "LST" ) == 0 )
    304         {
    305                 int list;
    306                
    307                 if( num_parts != 4 && num_parts != 5 )
    308                 {
    309                         imcb_error( ic, "Syntax error" );
    310                         imc_logout( ic, TRUE );
    311                         return( 0 );
    312                 }
    313                
    314                 http_decode( cmd[2] );
    315                 list = atoi( cmd[3] );
    316                
    317                 if( list & 1 ) /* FL */
    318                 {
    319                         char *group = NULL;
    320                         int num;
    321                        
    322                         if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount )
    323                                 group = md->grouplist[num];
    324                        
    325                         imcb_add_buddy( ic, cmd[1], group );
    326                         imcb_rename_buddy( ic, cmd[1], cmd[2] );
    327                 }
    328                 if( list & 2 ) /* AL */
    329                 {
    330                         ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) );
    331                 }
    332                 if( list & 4 ) /* BL */
    333                 {
    334                         ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) );
    335                 }
    336                 if( list & 8 ) /* RL */
    337                 {
    338                         if( ( list & 6 ) == 0 )
    339                                 msn_buddy_ask( ic, cmd[1], cmd[2] );
    340                 }
    341                
    342                 if( --md->buddycount == 0 )
    343                 {
    344                         if( ic->flags & OPT_LOGGED_IN )
    345                         {
    346                                 imcb_log( ic, "Successfully transferred to different server" );
    347                                 g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 );
    348                                 return( msn_write( ic, buf, strlen( buf ) ) );
    349                         }
    350                         else
    351                         {
    352                                 msn_logged_in( ic );
    353                         }
    354                 }
    355         }
    356         else if( strcmp( cmd[0], "LSG" ) == 0 )
    357         {
    358                 int num;
    359                
    360                 if( num_parts != 4 )
    361                 {
    362                         imcb_error( ic, "Syntax error" );
    363                         imc_logout( ic, TRUE );
    364                         return( 0 );
    365                 }
    366                
    367                 http_decode( cmd[2] );
    368                 num = atoi( cmd[1] );
    369                
    370                 if( num < md->groupcount )
    371                         md->grouplist[num] = g_strdup( cmd[2] );
     292                if( num_parts < 4 )
     293                {
     294                        imcb_error( ic, "Syntax error" );
     295                        imc_logout( ic, TRUE );
     296                        return( 0 );
     297                }
     298               
     299                handler->msglen = atoi( cmd[3] );
     300               
     301                if( handler->msglen <= 0 )
     302                {
     303                        imcb_error( ic, "Syntax error" );
     304                        imc_logout( ic, TRUE );
     305                        return( 0 );
     306                }
     307        }
     308        else if( strcmp( cmd[0], "BLP" ) == 0 )
     309        {
     310                msn_ns_send_adl_start( ic );
     311                return msn_ns_finish_login( ic );
     312        }
     313        else if( strcmp( cmd[0], "ADL" ) == 0 )
     314        {
     315                if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 )
     316                {
     317                        msn_ns_send_adl( ic );
     318                        return msn_ns_finish_login( ic );
     319                }
     320                else if( num_parts >= 3 )
     321                {
     322                        handler->msglen = atoi( cmd[2] );
     323                }
     324        }
     325        else if( strcmp( cmd[0], "PRP" ) == 0 )
     326        {
     327                imcb_connected( ic );
    372328        }
    373329        else if( strcmp( cmd[0], "CHL" ) == 0 )
    374330        {
    375                 md5_state_t state;
    376                 md5_byte_t digest[16];
    377                 int i;
    378                
    379                 if( num_parts != 3 )
    380                 {
    381                         imcb_error( ic, "Syntax error" );
    382                         imc_logout( ic, TRUE );
    383                         return( 0 );
    384                 }
    385                
    386                 md5_init( &state );
    387                 md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) );
    388                 md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) );
    389                 md5_finish( &state, digest );
    390                
    391                 g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 );
    392                 for( i = 0; i < 16; i ++ )
    393                         g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] );
    394                
    395                 return( msn_write( ic, buf, strlen( buf ) ) );
     331                char *resp;
     332                int st;
     333               
     334                if( num_parts < 3 )
     335                {
     336                        imcb_error( ic, "Syntax error" );
     337                        imc_logout( ic, TRUE );
     338                        return( 0 );
     339                }
     340               
     341                resp = msn_p11_challenge( cmd[2] );
     342               
     343                st =  msn_ns_write( ic, -1, "QRY %d %s %zd\r\n%s",
     344                                    ++md->trId, MSNP11_PROD_ID,
     345                                    strlen( resp ), resp );
     346                g_free( resp );
     347                return st;
    396348        }
    397349        else if( strcmp( cmd[0], "ILN" ) == 0 )
     
    399351                const struct msn_away_state *st;
    400352               
    401                 if( num_parts != 6 )
    402                 {
    403                         imcb_error( ic, "Syntax error" );
    404                         imc_logout( ic, TRUE );
    405                         return( 0 );
    406                 }
    407                
    408                 http_decode( cmd[4] );
    409                 imcb_rename_buddy( ic, cmd[3], cmd[4] );
     353                if( num_parts < 6 )
     354                {
     355                        imcb_error( ic, "Syntax error" );
     356                        imc_logout( ic, TRUE );
     357                        return( 0 );
     358                }
     359               
     360                http_decode( cmd[5] );
     361                imcb_rename_buddy( ic, cmd[3], cmd[5] );
    410362               
    411363                st = msn_away_state_by_code( cmd[2] );
     
    432384        {
    433385                const struct msn_away_state *st;
    434                
    435                 if( num_parts != 5 )
    436                 {
    437                         imcb_error( ic, "Syntax error" );
    438                         imc_logout( ic, TRUE );
    439                         return( 0 );
    440                 }
    441                
    442                 http_decode( cmd[3] );
    443                 imcb_rename_buddy( ic, cmd[2], cmd[3] );
     386                int cap;
     387               
     388                if( num_parts < 6 )
     389                {
     390                        imcb_error( ic, "Syntax error" );
     391                        imc_logout( ic, TRUE );
     392                        return( 0 );
     393                }
     394               
     395                http_decode( cmd[4] );
     396                cap = atoi( cmd[5] );
     397                imcb_rename_buddy( ic, cmd[2], cmd[4] );
    444398               
    445399                st = msn_away_state_by_code( cmd[1] );
     
    451405               
    452406                imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
    453                                    ( st != msn_away_state_list ? OPT_AWAY : 0 ),
     407                                   ( st != msn_away_state_list ? OPT_AWAY : 0 ) |
     408                                   ( cap & 1 ? OPT_MOBILE : 0 ),
    454409                                   st->name, NULL );
    455410               
     
    462417                int session, port;
    463418               
    464                 if( num_parts != 7 )
     419                if( num_parts < 7 )
    465420                {
    466421                        imcb_error( ic, "Syntax error" );
     
    504459                }
    505460        }
    506         else if( strcmp( cmd[0], "ADD" ) == 0 )
    507         {
    508                 if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 )
    509                 {
    510                         GSList *l;
    511                        
    512                         http_decode( cmd[5] );
    513                        
    514                         if( strchr( cmd[4], '@' ) == NULL )
    515                         {
    516                                 imcb_error( ic, "Syntax error" );
    517                                 imc_logout( ic, TRUE );
    518                                 return 0;
    519                         }
    520                        
    521                         /* We got added by someone. If we don't have this
    522                            person in permit/deny yet, inform the user. */
    523                         for( l = ic->permit; l; l = l->next )
    524                                 if( g_strcasecmp( l->data, cmd[4] ) == 0 )
    525                                         return 1;
    526                        
    527                         for( l = ic->deny; l; l = l->next )
    528                                 if( g_strcasecmp( l->data, cmd[4] ) == 0 )
    529                                         return 1;
    530                        
    531                         msn_buddy_ask( ic, cmd[4], cmd[5] );
    532                 }
    533                 else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 )
    534                 {
    535                         const char *group = NULL;
    536                         int num;
    537                        
    538                         if( cmd[6] != NULL && sscanf( cmd[6], "%d", &num ) == 1 && num < md->groupcount )
    539                                 group = md->grouplist[num];
    540                        
    541                         http_decode( cmd[5] );
    542                         imcb_add_buddy( ic, cmd[4], group );
    543                         imcb_rename_buddy( ic, cmd[4], cmd[5] );
    544                 }
    545         }
    546461        else if( strcmp( cmd[0], "OUT" ) == 0 )
    547462        {
     
    565480                return( 0 );
    566481        }
     482        else if( strcmp( cmd[0], "IPG" ) == 0 )
     483        {
     484                imcb_error( ic, "Received IPG command, we don't handle them yet." );
     485               
     486                handler->msglen = atoi( cmd[1] );
     487               
     488                if( handler->msglen <= 0 )
     489                {
     490                        imcb_error( ic, "Syntax error" );
     491                        imc_logout( ic, TRUE );
     492                        return( 0 );
     493                }
     494        }
    567495#if 0
    568         /* Discard this one completely for now since I don't care about the ack
    569            and since MSN servers can apparently screw up the formatting. */
    570         else if( strcmp( cmd[0], "REA" ) == 0 )
    571         {
    572                 if( num_parts != 5 )
    573                 {
    574                         imcb_error( ic, "Syntax error" );
    575                         imc_logout( ic, TRUE );
    576                         return( 0 );
    577                 }
    578                
    579                 if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 )
    580                 {
    581                         set_t *s;
    582                        
    583                         http_decode( cmd[4] );
    584                         strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );
    585                         ic->displayname[sizeof(ic->displayname)-1] = 0;
    586                        
    587                         if( ( s = set_find( &ic->acc->set, "display_name" ) ) )
    588                         {
    589                                 g_free( s->value );
    590                                 s->value = g_strdup( cmd[4] );
    591                         }
    592                 }
    593                 else
    594                 {
    595                         /* This is not supposed to happen, but let's handle it anyway... */
    596                         http_decode( cmd[4] );
    597                         imcb_rename_buddy( ic, cmd[3], cmd[4] );
    598                 }
    599         }
    600 #endif
    601         else if( strcmp( cmd[0], "IPG" ) == 0 )
    602         {
    603                 imcb_error( ic, "Received IPG command, we don't handle them yet." );
    604                
    605                 md->handler->msglen = atoi( cmd[1] );
    606                
    607                 if( md->handler->msglen <= 0 )
    608                 {
    609                         imcb_error( ic, "Syntax error" );
    610                         imc_logout( ic, TRUE );
    611                         return( 0 );
    612                 }
    613         }
    614496        else if( strcmp( cmd[0], "ADG" ) == 0 )
    615497        {
     
    656538                }
    657539        }
     540#endif
     541        else if( strcmp( cmd[0], "GCF" ) == 0 )
     542        {
     543                /* Coming up is cmd[2] bytes of stuff we're supposed to
     544                   censore. Meh. */
     545                handler->msglen = atoi( cmd[2] );
     546        }
     547        else if( strcmp( cmd[0], "UBX" ) == 0 )
     548        {
     549                /* Status message. */
     550                if( num_parts >= 4 )
     551                        handler->msglen = atoi( cmd[3] );
     552        }
     553        else if( strcmp( cmd[0], "NOT" ) == 0 )
     554        {
     555                /* Some kind of notification, poorly documented but
     556                   apparently used to announce address book changes. */
     557                if( num_parts >= 2 )
     558                        handler->msglen = atoi( cmd[1] );
     559        }
    658560        else if( isdigit( cmd[0][0] ) )
    659561        {
     
    668570                        return( 0 );
    669571                }
     572               
     573                /* Oh yes, errors can have payloads too now. Discard them for now. */
     574                if( num_parts >= 3 )
     575                        handler->msglen = atoi( cmd[2] );
    670576        }
    671577        else
     
    677583}
    678584
    679 static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts )
    680 {
    681         struct im_connection *ic = data;
     585static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts )
     586{
     587        struct im_connection *ic = handler->data;
    682588        char *body;
    683589        int blen = 0;
     
    765671                }
    766672        }
     673        else if( strcmp( cmd[0], "UBX" ) == 0 )
     674        {
     675                struct xt_node *psm;
     676                char *psm_text = NULL;
     677               
     678                psm = xt_from_string( msg );
     679                if( psm && strcmp( psm->name, "Data" ) == 0 &&
     680                    ( psm = xt_find_node( psm->children, "PSM" ) ) )
     681                        psm_text = psm->text;
     682               
     683                imcb_buddy_status_msg( ic, cmd[1], psm_text );
     684                xt_free_node( psm );
     685        }
     686        else if( strcmp( cmd[0], "ADL" ) == 0 )
     687        {
     688                struct xt_node *adl, *d, *c;
     689               
     690                if( !( adl = xt_from_string( msg ) ) )
     691                        return 1;
     692               
     693                for( d = adl->children; d; d = d->next )
     694                {
     695                        char *dn;
     696                        if( strcmp( d->name, "d" ) != 0 ||
     697                            ( dn = xt_find_attr( d, "n" ) ) == NULL )
     698                                continue;
     699                        for( c = d->children; c; c = c->next )
     700                        {
     701                                bee_user_t *bu;
     702                                struct msn_buddy_data *bd;
     703                                char *cn, *handle, *f, *l;
     704                                int flags;
     705                               
     706                                if( strcmp( c->name, "c" ) != 0 ||
     707                                    ( l = xt_find_attr( c, "l" ) ) == NULL ||
     708                                    ( cn = xt_find_attr( c, "n" ) ) == NULL )
     709                                        continue;
     710                               
     711                                handle = g_strdup_printf( "%s@%s", cn, dn );
     712                                if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
     713                                       ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )
     714                                {
     715                                        g_free( handle );
     716                                        continue;
     717                                }
     718                                g_free( handle );
     719                                bd = bu->data;
     720                               
     721                                if( ( f = xt_find_attr( c, "f" ) ) )
     722                                {
     723                                        http_decode( f );
     724                                        imcb_rename_buddy( ic, bu->handle, f );
     725                                }
     726                               
     727                                flags = atoi( l ) & 15;
     728                                if( bd->flags != flags )
     729                                {
     730                                        bd->flags = flags;
     731                                        msn_buddy_ask( bu );
     732                                }
     733                        }
     734                }
     735        }
    767736       
    768737        return( 1 );
    769738}
    770739
    771 static void msn_auth_got_passport_token( struct msn_auth_data *mad )
    772 {
    773         struct im_connection *ic = mad->data;
     740void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error )
     741{
    774742        struct msn_data *md;
    775743       
     
    779747       
    780748        md = ic->proto_data;
    781         if( mad->token )
    782         {
    783                 char buf[1024];
    784                
    785                 g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
    786                 msn_write( ic, buf, strlen( buf ) );
     749       
     750        if( token )
     751        {
     752                msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
    787753        }
    788754        else
    789755        {
    790                 imcb_error( ic, "Error during Passport authentication: %s", mad->error );
     756                imcb_error( ic, "Error during Passport authentication: %s", error );
    791757                imc_logout( ic, TRUE );
    792758        }
    793759}
    794760
    795 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name )
    796 {
    797         set_t *s;
    798        
    799         if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL )
    800                 return FALSE; /* Shouldn't happen.. */
    801        
    802         http_decode( name );
    803        
    804         if( s->value && strcmp( s->value, name ) == 0 )
    805         {
    806                 return TRUE;
    807                 /* The names match, nothing to worry about. */
    808         }
    809         else if( s->value != NULL &&
    810                  ( strcmp( name, ic->acc->user ) == 0 ||
    811                    set_getbool( &ic->acc->set, "local_display_name" ) ) )
    812         {
    813                 /* The server thinks our display name is our e-mail address
    814                    which is probably wrong, or the user *wants* us to do this:
    815                    Always use the locally set display_name. */
    816                 return msn_set_display_name( ic, s->value );
    817         }
     761void msn_auth_got_contact_list( struct im_connection *ic )
     762{
     763        struct msn_data *md;
     764       
     765        /* Dead connection? */
     766        if( g_slist_find( msn_connections, ic ) == NULL )
     767                return;
     768       
     769        md = ic->proto_data;
     770        msn_ns_write( ic, -1, "BLP %d %s\r\n", ++md->trId, "BL" );
     771}
     772
     773static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data )
     774{
     775        struct xt_node *adl = data, *d, *c;
     776        struct bee_user *bu = value;
     777        struct msn_buddy_data *bd = bu->data;
     778        struct msn_data *md = bu->ic->proto_data;
     779        char handle[strlen(bu->handle)];
     780        char *domain;
     781        char l[4];
     782       
     783        if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) )
     784                return FALSE;
     785       
     786        strcpy( handle, bu->handle );
     787        if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */
     788                return FALSE;
     789        *domain = '\0';
     790        domain ++;
     791       
     792        if( ( d = adl->children ) == NULL ||
     793            g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 )
     794        {
     795                d = xt_new_node( "d", NULL, NULL );
     796                xt_add_attr( d, "n", domain );
     797                xt_insert_child( adl, d );
     798        }
     799       
     800        g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 );
     801        c = xt_new_node( "c", NULL, NULL );
     802        xt_add_attr( c, "n", handle );
     803        xt_add_attr( c, "l", l );
     804        xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */
     805        xt_insert_child( d, c );
     806       
     807        /* Do this in batches of 100. */
     808        bd->flags |= MSN_BUDDY_ADL_SYNCED;
     809        return (--md->adl_todo % 140) == 0;
     810}
     811
     812static void msn_ns_send_adl( struct im_connection *ic )
     813{
     814        struct xt_node *adl;
     815        struct msn_data *md = ic->proto_data;
     816        char *adls;
     817       
     818        adl = xt_new_node( "ml", NULL, NULL );
     819        xt_add_attr( adl, "l", "1" );
     820        g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
     821        if( adl->children == NULL )
     822        {
     823                /* This tells the caller that we're done now. */
     824                md->adl_todo = -1;
     825                xt_free_node( adl );
     826                return;
     827        }
     828       
     829        adls = xt_to_string( adl );
     830        msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", ++md->trId, strlen( adls ), adls );
     831        g_free( adls );
     832}
     833
     834static void msn_ns_send_adl_start( struct im_connection *ic )
     835{
     836        struct msn_data *md;
     837        GSList *l;
     838       
     839        /* Dead connection? */
     840        if( g_slist_find( msn_connections, ic ) == NULL )
     841                return;
     842       
     843        md = ic->proto_data;
     844        md->adl_todo = 0;
     845        for( l = ic->bee->users; l; l = l->next )
     846        {
     847                bee_user_t *bu = l->data;
     848                struct msn_buddy_data *bd = bu->data;
     849               
     850                if( bu->ic != ic || ( bd->flags & 7 ) == 0 )
     851                        continue;
     852               
     853                bd->flags &= ~MSN_BUDDY_ADL_SYNCED;
     854                md->adl_todo++;
     855        }
     856       
     857        msn_ns_send_adl( ic );
     858}
     859
     860int msn_ns_finish_login( struct im_connection *ic )
     861{
     862        struct msn_data *md = ic->proto_data;
     863       
     864        if( ic->flags & OPT_LOGGED_IN )
     865                return 1;
     866       
     867        if( md->adl_todo < 0 )
     868                md->flags |= MSN_DONE_ADL;
     869       
     870        if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) )
     871                return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );
    818872        else
    819         {
    820                 if( s->value && *s->value )
    821                         imcb_log( ic, "BitlBee thinks your display name is `%s' but "
    822                                       "the MSN server says it's `%s'. Using the MSN "
    823                                       "server's name. Set local_display_name to true "
    824                                       "to use the local name.", s->value, name );
    825                
    826                 if( g_utf8_validate( name, -1, NULL ) )
    827                 {
    828                         g_free( s->value );
    829                         s->value = g_strdup( name );
    830                 }
    831                 else
    832                 {
    833                         imcb_log( ic, "Warning: Friendly name in server response was corrupted" );
    834                 }
    835                
    836                 return TRUE;
    837         }
    838 }
     873                return 1;
     874}
  • protocols/msn/sb.c

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

    r05bf2a0 r62f53b50  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    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

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

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

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