Changes in / [c00dd71:4022b68]


Ignore:
Files:
4 added
2 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • configure

    rc00dd71 r4022b68  
    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

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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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

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

    rc00dd71 r4022b68  
    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 = g_strdup( message );
     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

    rc00dd71 r4022b68  
    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
     
    4242        @echo '*' Linking msn_mod.o
    4343        @$(LD) $(LFLAGS) $(objects) -o msn_mod.o
    44        
    45 
  • protocols/msn/msn.c

    rc00dd71 r4022b68  
    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
     
    6874        md->ic = ic;
    6975        md->away_state = msn_away_state_list;
     76        md->domaintree = g_tree_new( msn_domaintree_cmp );
    7077       
    7178        msn_connections = g_slist_append( msn_connections, ic );
     
    7683        struct msn_data *md = ic->proto_data;
    7784        GSList *l;
     85        int i;
    7886       
    7987        if( md )
     
    100108                msn_msgq_purge( ic, &md->msgq );
    101109               
    102                 while( md->groupcount > 0 )
    103                         g_free( md->grouplist[--md->groupcount] );
    104                 g_free( md->grouplist );
     110                for( i = 0; i < sizeof( md->tokens ) / sizeof( md->tokens[0] ); i ++ )
     111                        g_free( md->tokens[i] );
     112                g_free( md->lock_key );
     113               
     114                while( md->groups )
     115                {
     116                        struct msn_group *mg = md->groups->data;
     117                        g_free( mg->id );
     118                        g_free( mg->name );
     119                        g_free( mg );
     120                        md->groups = g_slist_remove( md->groups, mg );
     121                }
     122               
     123                g_tree_destroy( md->domaintree );
     124                md->domaintree = NULL;
    105125               
    106126                while( md->grpq )
     
    174194{
    175195        char buf[1024];
     196        char *uux;
    176197        struct msn_data *md = ic->proto_data;
    177198       
     
    182203       
    183204        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 );
     205        if( !msn_write( ic, buf, strlen( buf ) ) )
     206                return;
     207       
     208        uux = g_markup_printf_escaped( "<Data><PSM>%s</PSM><CurrentMedia></CurrentMedia>"
     209                                       "</Data>", message ? message : "" );
     210        g_snprintf( buf, sizeof( buf ), "UUX %d %zd\r\n%s", ++md->trId, strlen( uux ), uux );
     211        if( !msn_write( ic, buf, strlen( buf ) ) )
     212                return;
    190213}
    191214
     
    200223        struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who );
    201224       
    202         msn_buddy_list_add( ic, "FL", who, who, group );
     225        msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group );
    203226        if( bu && bu->group )
    204                 msn_buddy_list_remove( ic, "FL", who, bu->group->name );
     227                msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name );
    205228}
    206229
    207230static void msn_remove_buddy( struct im_connection *ic, char *who, char *group )
    208231{
    209         msn_buddy_list_remove( ic, "FL", who, NULL );
     232        msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, NULL );
    210233}
    211234
     
    272295static void msn_add_permit( struct im_connection *ic, char *who )
    273296{
    274         msn_buddy_list_add( ic, "AL", who, who, NULL );
     297        msn_buddy_list_add( ic, MSN_BUDDY_AL, who, who, NULL );
    275298}
    276299
    277300static void msn_rem_permit( struct im_connection *ic, char *who )
    278301{
    279         msn_buddy_list_remove( ic, "AL", who, NULL );
     302        msn_buddy_list_remove( ic, MSN_BUDDY_AL, who, NULL );
    280303}
    281304
     
    284307        struct msn_switchboard *sb;
    285308       
    286         msn_buddy_list_add( ic, "BL", who, who, NULL );
     309        msn_buddy_list_add( ic, MSN_BUDDY_BL, who, who, NULL );
    287310       
    288311        /* If there's still a conversation with this person, close it. */
     
    295318static void msn_rem_deny( struct im_connection *ic, char *who )
    296319{
    297         msn_buddy_list_remove( ic, "BL", who, NULL );
     320        msn_buddy_list_remove( ic, MSN_BUDDY_BL, who, NULL );
    298321}
    299322
     
    314337        account_t *acc = set->data;
    315338        struct im_connection *ic = acc->ic;
    316        
    317         /* Allow any name if we're offline. */
    318         if( ic == NULL )
    319                 return value;
     339        struct msn_data *md = ic->proto_data;
    320340       
    321341        if( strlen( value ) > 129 )
     
    325345        }
    326346       
    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;
     347        if( md->flags & MSN_GOT_PROFILE_DN )
     348                imcb_log( ic, "Warning: Persistent name changes for this account have to be done "
     349                              "in the profile. BitlBee doesn't currently support this." );
     350       
     351        msn_soap_addressbook_set_display_name( ic, value );
     352        return msn_ns_set_display_name( ic, value ) ? value : NULL;
     353}
     354
     355static void msn_buddy_data_add( bee_user_t *bu )
     356{
     357        struct msn_data *md = bu->ic->proto_data;
     358        bu->data = g_new0( struct msn_buddy_data, 1 );
     359        g_tree_insert( md->domaintree, bu->handle, bu );
     360}
     361
     362static void msn_buddy_data_free( bee_user_t *bu )
     363{
     364        struct msn_data *md = bu->ic->proto_data;
     365        g_tree_remove( md->domaintree, bu->handle );
     366        g_free( bu->data );
    331367}
    332368
     
    343379        ret->set_away = msn_set_away;
    344380        ret->get_info = msn_get_info;
    345         ret->set_my_name = msn_set_my_name;
    346381        ret->add_buddy = msn_add_buddy;
    347382        ret->remove_buddy = msn_remove_buddy;
     
    357392        ret->send_typing = msn_send_typing;
    358393        ret->handle_cmp = g_strcasecmp;
     394        ret->buddy_data_add = msn_buddy_data_add;
     395        ret->buddy_data_free = msn_buddy_data_free;
     396       
    359397        //ret->transfer_request = msn_ftp_transfer_request;
    360398
  • protocols/msn/msn.h

    rc00dd71 r4022b68  
    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/* Some other version.
     47#define MSNP11_PROD_KEY "O4BG@C7BWLYQX?5G"
     48#define MSNP11_PROD_ID  "PROD01065C%ZFN6F"
     49*/
     50
     51#define MSNP11_PROD_KEY "ILTXC!4IXB5FB*PX"
     52#define MSNP11_PROD_ID  "PROD0119GSJUC$18"
     53#define MSNP_VER        "MSNP15"
     54#define MSNP_BUILD      "8.5.1288"
    4355
    4456#define MSN_SB_NEW         -24062002
     
    6173#define PROFILE_URL "http://members.msn.com/"
    6274
     75typedef enum
     76{
     77        MSN_GOT_PROFILE = 1,
     78        MSN_GOT_PROFILE_DN = 2,
     79        MSN_DONE_ADL = 4,
     80} msn_flags_t;
     81
    6382struct msn_data
    6483{
     
    6786        int fd;
    6887        struct msn_handler_data *handler;
     88        msn_flags_t flags;
    6989       
    7090        int trId;
     91        char *tokens[4];
     92        char *lock_key;
    7193       
    7294        GSList *msgq, *grpq;
     
    7496        int sb_failures;
    7597        time_t first_sb_failure;
    76         GSList *filetransfers;
    7798       
    7899        const struct msn_away_state *away_state;
    79         int buddycount;
    80         int groupcount;
    81         char **grouplist;
     100        GSList *groups;
     101       
     102        /* Mostly used for sending the ADL command; since MSNP13 the client
     103           is responsible for downloading the contact list and then sending
     104           it to the MSNP server. */
     105        GTree *domaintree;
     106        int adl_todo;
    82107};
    83108
     
    140165        int (*exec_command) ( gpointer data, char **cmd, int count );
    141166        int (*exec_message) ( gpointer data, char *msg, int msglen, char **cmd, int count );
     167};
     168
     169typedef enum
     170{
     171        MSN_BUDDY_FL = 1,   /* Warning: FL,AL,BL *must* be 1,2,4. */
     172        MSN_BUDDY_AL = 2,
     173        MSN_BUDDY_BL = 4,
     174        MSN_BUDDY_RL = 8,
     175        MSN_BUDDY_PL = 16,
     176        MSN_BUDDY_ADL_SYNCED = 256,
     177} msn_buddy_flags_t;
     178
     179struct msn_buddy_data
     180{
     181        char *cid;
     182        msn_buddy_flags_t flags;
     183};
     184
     185struct msn_group
     186{
     187        char *name;
     188        char *id;
    142189};
    143190
     
    162209/* ns.c */
    163210gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond );
     211void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error );
     212void msn_auth_got_contact_list( struct im_connection *ic );
     213int msn_ns_finish_login( struct im_connection *ic );
    164214
    165215/* msn_util.c */
    166216int msn_write( struct im_connection *ic, char *s, int len );
    167217int 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 );
     218int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname_, const char *group );
     219int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group );
     220void msn_buddy_ask( bee_user_t *bu );
    171221char *msn_findheader( char *text, char *header, int len );
    172222char **msn_linesplit( char *line );
    173223int msn_handler( struct msn_handler_data *h );
    174 char *msn_http_encode( const char *input );
    175224void msn_msgq_purge( struct im_connection *ic, GSList **list );
    176 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname );
     225char *msn_p11_challenge( char *challenge );
     226gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ );
     227struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name );
     228struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id );
     229int msn_ns_set_display_name( struct im_connection *ic, const char *value );
    177230
    178231/* tables.c */
     
    196249void msn_sb_stop_keepalives( struct msn_switchboard *sb );
    197250
    198 /* invitation.c */
    199 void msn_ftp_transfer_request( struct im_connection *ic, file_transfer_t *ft, char *who );
    200 
    201251#endif //_MSN_H
  • protocols/msn/msn_util.c

    rc00dd71 r4022b68  
    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
     
    3234        struct msn_data *md = ic->proto_data;
    3335        int st;
     36       
     37        if( getenv( "BITLBEE_DEBUG" ) )
     38        {
     39                write( 2, "->NS:", 5 );
     40                write( 2, s, len );
     41        }
    3442       
    3543        st = write( md->fd, s, len );
     
    5159}
    5260
    53 int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group )
     61static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list )
     62{
     63        char *domain, handle[strlen(handle_)+1];
     64       
     65        strcpy( handle, handle_ );
     66        if( ( domain = strchr( handle, '@' ) ) )
     67                *(domain++) = '\0';
     68        else
     69                return NULL;
     70       
     71        return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>",
     72                domain, handle, list );
     73}
     74
     75int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group )
    5476{
    5577        struct msn_data *md = ic->proto_data;
    56         char buf[1024], *realname, groupid[8];
     78        char buf[1024], groupid[8];
     79        bee_user_t *bu;
     80        struct msn_buddy_data *bd;
     81        char *adl;
    5782       
    5883        *groupid = '\0';
     84#if 0
    5985        if( group )
    6086        {
     
    87113                        if( l == NULL )
    88114                        {
    89                                 char *groupname = msn_http_encode( group );
     115                                char groupname[strlen(group)+1];
     116                                strcpy( groupname, group );
     117                                http_encode( groupname );
    90118                                g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 );
    91                                 g_free( groupname );
    92119                                return msn_write( ic, buf, strlen( buf ) );
    93120                        }
     
    101128                }
    102129        }
    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 )
     130#endif
     131       
     132        if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
     133               ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) ||
     134            !( bd = bu->data ) || bd->flags & list )
     135                return 1;
     136       
     137        bd->flags |= list;
     138       
     139        if( list == MSN_BUDDY_FL )
     140                msn_soap_ab_contact_add( ic, bu );
     141        else
     142                msn_soap_memlist_edit( ic, who, TRUE, list );
     143       
     144        if( ( adl = adlrml_entry( who, list ) ) )
     145        {
     146                g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n%s",
     147                            ++md->trId, strlen( adl ), adl );
     148                g_free( adl );
     149               
     150                return msn_write( ic, buf, strlen( buf ) );
     151        }
     152       
     153        return 1;
     154}
     155
     156int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group )
    112157{
    113158        struct msn_data *md = ic->proto_data;
    114159        char buf[1024], groupid[8];
     160        bee_user_t *bu;
     161        struct msn_buddy_data *bd;
     162        char *adl;
    115163       
    116164        *groupid = '\0';
     165#if 0
    117166        if( group )
    118167        {
     
    125174                        }
    126175        }
    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 );
     176#endif
     177       
     178        if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
     179            !( bd = bu->data ) || !( bd->flags & list ) )
     180                return 1;
     181       
     182        bd->flags &= ~list;
     183       
     184        if( list == MSN_BUDDY_FL )
     185                msn_soap_ab_contact_del( ic, bu );
     186        else
     187                msn_soap_memlist_edit( ic, who, FALSE, list );
     188       
     189        if( ( adl = adlrml_entry( who, list ) ) )
     190        {
     191                g_snprintf( buf, sizeof( buf ), "RML %d %zd\r\n%s",
     192                            ++md->trId, strlen( adl ), adl );
     193                g_free( adl );
     194               
     195                return msn_write( ic, buf, strlen( buf ) );
     196        }
     197       
     198        return 1;
    133199}
    134200
     
    144210        struct msn_buddy_ask_data *bla = data;
    145211       
    146         msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL );
     212        msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL );
    147213       
    148214        imcb_ask_add( bla->ic, bla->handle, NULL );
     
    157223        struct msn_buddy_ask_data *bla = data;
    158224       
    159         msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL );
     225        msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL );
    160226       
    161227        g_free( bla->handle );
     
    164230}
    165231
    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 );
     232void msn_buddy_ask( bee_user_t *bu )
     233{
     234        struct msn_buddy_ask_data *bla;
     235        struct msn_buddy_data *bd = bu->data;
    169236        char buf[1024];
    170237       
    171         bla->ic = ic;
    172         bla->handle = g_strdup( handle );
    173         bla->realname = g_strdup( realname );
     238        if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 )
     239                return;
     240       
     241        bla = g_new0( struct msn_buddy_ask_data, 1 );
     242        bla->ic = bu->ic;
     243        bla->handle = g_strdup( bu->handle );
     244        bla->realname = g_strdup( bu->fullname );
    174245       
    175246        g_snprintf( buf, sizeof( buf ),
    176247                    "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 );
     248                    bu->handle, bu->fullname );
     249        imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );
    179250}
    180251
     
    279350        if( st <= 0 )
    280351                return( -1 );
     352       
     353        if( getenv( "BITLBEE_DEBUG" ) )
     354        {
     355                write( 2, "->C:", 4 );
     356                write( 2, h->rxq + h->rxlen - st, st );
     357        }
    281358       
    282359        while( st )
     
    367444}
    368445
    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 
    395446void msn_msgq_purge( struct im_connection *ic, GSList **list )
    396447{
     
    433484}
    434485
    435 gboolean msn_set_display_name( struct im_connection *ic, const char *rawname )
    436 {
    437         char *fn = msn_http_encode( rawname );
     486/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */
     487char *msn_p11_challenge( char *challenge )
     488{
     489        char *output, buf[256];
     490        md5_state_t md5c;
     491        unsigned char md5Hash[16], *newHash;
     492        unsigned int *md5Parts, *chlStringParts, newHashParts[5];
     493        long long nHigh = 0, nLow = 0;
     494        int i, n;
     495
     496        /* Create the MD5 hash */
     497        md5_init(&md5c);
     498        md5_append(&md5c, (unsigned char*) challenge, strlen(challenge));
     499        md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY));
     500        md5_finish(&md5c, md5Hash);
     501
     502        /* Split it into four integers */
     503        md5Parts = (unsigned int *)md5Hash;
     504        for (i = 0; i < 4; i ++)
     505        { 
     506                md5Parts[i] = GUINT32_TO_LE(md5Parts[i]);
     507               
     508                /* & each integer with 0x7FFFFFFF */
     509                /* and save one unmodified array for later */
     510                newHashParts[i] = md5Parts[i];
     511                md5Parts[i] &= 0x7FFFFFFF;
     512        }
     513       
     514        /* make a new string and pad with '0' */
     515        n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID);
     516        /* truncate at an 8-byte boundary */
     517        buf[n&=~7] = '\0';
     518       
     519        /* split into integers */
     520        chlStringParts = (unsigned int *)buf;
     521       
     522        /* this is magic */
     523        for (i = 0; i < (n / 4) - 1; i += 2)
     524        {
     525                long long temp;
     526
     527                chlStringParts[i]   = GUINT32_TO_LE(chlStringParts[i]);
     528                chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]);
     529
     530                temp  = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF;
     531                nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF;
     532                nLow  = nLow + nHigh + temp;
     533        }
     534        nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF;
     535        nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF;
     536       
     537        newHashParts[0] ^= nHigh;
     538        newHashParts[1] ^= nLow;
     539        newHashParts[2] ^= nHigh;
     540        newHashParts[3] ^= nLow;
     541       
     542        /* swap more bytes if big endian */
     543        for (i = 0; i < 4; i ++)
     544                newHashParts[i] = GUINT32_TO_LE(newHashParts[i]);
     545       
     546        /* make a string of the parts */
     547        newHash = (unsigned char *)newHashParts;
     548       
     549        /* convert to hexadecimal */
     550        output = g_new(char, 33);
     551        for (i = 0; i < 16; i ++)
     552                sprintf(output + i * 2, "%02x", newHash[i]);
     553       
     554        return output;
     555}
     556
     557gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ )
     558{
     559        const char *a = a_, *b = b_;
     560        gint ret;
     561       
     562        if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) ||
     563            ( ret = strcmp( a, b ) ) == 0 )
     564                ret = strcmp( a_, b_ );
     565       
     566        return ret;
     567}
     568
     569struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name )
     570{
    438571        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 }
     572        GSList *l;
     573       
     574        for( l = md->groups; l; l = l->next )
     575        {
     576                struct msn_group *mg = l->data;
     577               
     578                if( g_strcasecmp( mg->name, name ) == 0 )
     579                        return mg;
     580        }
     581       
     582        return NULL;
     583}
     584
     585struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id )
     586{
     587        struct msn_data *md = ic->proto_data;
     588        GSList *l;
     589       
     590        for( l = md->groups; l; l = l->next )
     591        {
     592                struct msn_group *mg = l->data;
     593               
     594                if( g_strcasecmp( mg->id, id ) == 0 )
     595                        return mg;
     596        }
     597       
     598        return NULL;
     599}
     600
     601int msn_ns_set_display_name( struct im_connection *ic, const char *value )
     602{
     603        struct msn_data *md = ic->proto_data;
     604        char fn[strlen(value)*3+1];
     605        char buf[512];
     606       
     607        strcpy( fn, value );
     608        http_encode( fn );
     609        g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n",
     610                    ++md->trId, fn );
     611       
     612        /* Note: We don't actually know if the server accepted the new name,
     613           and won't give proper feedback yet if it doesn't. */
     614        return msn_write( ic, buf, strlen( buf ) );
     615}
  • protocols/msn/ns.c

    rc00dd71 r4022b68  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2004 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2010 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2727#include "nogaim.h"
    2828#include "msn.h"
    29 #include "passport.h"
    3029#include "md5.h"
     30#include "soap.h"
     31#include "xmltree.h"
    3132
    3233static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );
     
    3435static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
    3536
    36 static void msn_auth_got_passport_token( struct msn_auth_data *mad );
    37 static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name );
     37static void msn_ns_send_adl_start( struct im_connection *ic );
     38static void msn_ns_send_adl( struct im_connection *ic );
    3839
    3940gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
     
    7374        md->handler->rxq = g_new0( char, 1 );
    7475       
    75         g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
     76        g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER );
    7677        if( msn_write( ic, s, strlen( s ) ) )
    7778        {
     
    113114        if( strcmp( cmd[0], "VER" ) == 0 )
    114115        {
    115                 if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
     116                if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )
    116117                {
    117118                        imcb_error( ic, "Unsupported protocol" );
     
    127128        {
    128129                /* 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                g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user );
    130131                return( msn_write( ic, buf, strlen( buf ) ) );
    131132        }
     
    135136                int port;
    136137               
    137                 if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
     138                if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 )
    138139                {
    139140                        b_event_remove( ic->inpa );
     
    156157                        md->fd = proxy_connect( server, port, msn_ns_connected, ic );
    157158                }
    158                 else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
     159                else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 )
    159160                {
    160161                        struct msn_switchboard *sb;
     
    220221        else if( strcmp( cmd[0], "USR" ) == 0 )
    221222        {
    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                        
     223                if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 &&
     224                    strcmp( cmd[3], "S" ) == 0 )
     225                {
     226                        msn_soap_passport_sso_request( ic, cmd[4], cmd[5] );
     227                }
     228                else if( strcmp( cmd[2], "OK" ) == 0 )
     229                {
    239230                        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 ) ) );
     231                        msn_soap_memlist_request( ic );
    243232                }
    244233                else
     
    251240        else if( strcmp( cmd[0], "MSG" ) == 0 )
    252241        {
    253                 if( num_parts != 4 )
     242                if( num_parts < 4 )
    254243                {
    255244                        imcb_error( ic, "Syntax error" );
     
    267256                }
    268257        }
    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] );
     258        else if( strcmp( cmd[0], "BLP" ) == 0 )
     259        {
     260                msn_ns_send_adl_start( ic );
     261                return msn_ns_finish_login( ic );
     262        }
     263        else if( strcmp( cmd[0], "ADL" ) == 0 )
     264        {
     265                if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 )
     266                {
     267                        msn_ns_send_adl( ic );
     268                        return msn_ns_finish_login( ic );
     269                }
     270                else if( num_parts >= 3 )
     271                {
     272                        md->handler->msglen = atoi( cmd[2] );
     273                }
     274        }
     275        else if( strcmp( cmd[0], "PRP" ) == 0 )
     276        {
     277                imcb_connected( ic );
    372278        }
    373279        else if( strcmp( cmd[0], "CHL" ) == 0 )
    374280        {
    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] );
     281                char *resp;
     282               
     283                if( num_parts < 3 )
     284                {
     285                        imcb_error( ic, "Syntax error" );
     286                        imc_logout( ic, TRUE );
     287                        return( 0 );
     288                }
     289               
     290                resp = msn_p11_challenge( cmd[2] );
     291                g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s",
     292                            ++md->trId, MSNP11_PROD_ID,
     293                            strlen( resp ), resp );
     294                g_free( resp );
    394295               
    395296                return( msn_write( ic, buf, strlen( buf ) ) );
     
    399300                const struct msn_away_state *st;
    400301               
    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] );
     302                if( num_parts < 6 )
     303                {
     304                        imcb_error( ic, "Syntax error" );
     305                        imc_logout( ic, TRUE );
     306                        return( 0 );
     307                }
     308               
     309                http_decode( cmd[5] );
     310                imcb_rename_buddy( ic, cmd[3], cmd[5] );
    410311               
    411312                st = msn_away_state_by_code( cmd[2] );
     
    433334                const struct msn_away_state *st;
    434335               
    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] );
     336                if( num_parts < 5 )
     337                {
     338                        imcb_error( ic, "Syntax error" );
     339                        imc_logout( ic, TRUE );
     340                        return( 0 );
     341                }
     342               
     343                http_decode( cmd[4] );
     344                imcb_rename_buddy( ic, cmd[2], cmd[4] );
    444345               
    445346                st = msn_away_state_by_code( cmd[1] );
     
    462363                int session, port;
    463364               
    464                 if( num_parts != 7 )
     365                if( num_parts < 7 )
    465366                {
    466367                        imcb_error( ic, "Syntax error" );
     
    504405                }
    505406        }
    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         }
    546407        else if( strcmp( cmd[0], "OUT" ) == 0 )
    547408        {
     
    565426                return( 0 );
    566427        }
     428        else if( strcmp( cmd[0], "IPG" ) == 0 )
     429        {
     430                imcb_error( ic, "Received IPG command, we don't handle them yet." );
     431               
     432                md->handler->msglen = atoi( cmd[1] );
     433               
     434                if( md->handler->msglen <= 0 )
     435                {
     436                        imcb_error( ic, "Syntax error" );
     437                        imc_logout( ic, TRUE );
     438                        return( 0 );
     439                }
     440        }
    567441#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         }
    614442        else if( strcmp( cmd[0], "ADG" ) == 0 )
    615443        {
     
    655483                        }
    656484                }
     485        }
     486#endif
     487        else if( strcmp( cmd[0], "GCF" ) == 0 )
     488        {
     489                /* Coming up is cmd[2] bytes of stuff we're supposed to
     490                   censore. Meh. */
     491                md->handler->msglen = atoi( cmd[2] );
     492        }
     493        else if( strcmp( cmd[0], "UBX" ) == 0 )
     494        {
     495                /* Status message. */
     496                if( num_parts >= 4 )
     497                        md->handler->msglen = atoi( cmd[3] );
     498        }
     499        else if( strcmp( cmd[0], "NOT" ) == 0 )
     500        {
     501                /* Some kind of notification, poorly documented but
     502                   apparently used to announce address book changes. */
     503                if( num_parts >= 2 )
     504                        md->handler->msglen = atoi( cmd[1] );
    657505        }
    658506        else if( isdigit( cmd[0][0] ) )
     
    765613                }
    766614        }
     615        else if( strcmp( cmd[0], "UBX" ) == 0 )
     616        {
     617                struct xt_node *psm;
     618                char *psm_text = NULL;
     619               
     620                psm = xt_from_string( msg );
     621                if( psm && strcmp( psm->name, "Data" ) == 0 &&
     622                    ( psm = xt_find_node( psm->children, "PSM" ) ) )
     623                        psm_text = psm->text;
     624               
     625                imcb_buddy_status_msg( ic, cmd[1], psm_text );
     626                xt_free_node( psm );
     627        }
     628        else if( strcmp( cmd[0], "ADL" ) == 0 )
     629        {
     630                struct xt_node *adl, *d, *c;
     631               
     632                if( !( adl = xt_from_string( msg ) ) )
     633                        return 1;
     634               
     635                for( d = adl->children; d; d = d->next )
     636                {
     637                        char *dn;
     638                        if( strcmp( d->name, "d" ) != 0 ||
     639                            ( dn = xt_find_attr( d, "n" ) ) == NULL )
     640                                continue;
     641                        for( c = d->children; c; c = c->next )
     642                        {
     643                                bee_user_t *bu;
     644                                struct msn_buddy_data *bd;
     645                                char *cn, *handle, *f, *l;
     646                                int flags;
     647                               
     648                                if( strcmp( c->name, "c" ) != 0 ||
     649                                    ( l = xt_find_attr( c, "l" ) ) == NULL ||
     650                                    ( cn = xt_find_attr( c, "n" ) ) == NULL )
     651                                        continue;
     652                               
     653                                handle = g_strdup_printf( "%s@%s", cn, dn );
     654                                if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
     655                                       ( bu = bee_user_new( ic->bee, ic, handle, 0 ) ) ) )
     656                                {
     657                                        g_free( handle );
     658                                        continue;
     659                                }
     660                                g_free( handle );
     661                                bd = bu->data;
     662                               
     663                                if( ( f = xt_find_attr( c, "f" ) ) )
     664                                {
     665                                        http_decode( f );
     666                                        imcb_rename_buddy( ic, bu->handle, f );
     667                                }
     668                               
     669                                flags = atoi( l ) & 15;
     670                                if( bd->flags != flags )
     671                                {
     672                                        bd->flags = flags;
     673                                        msn_buddy_ask( bu );
     674                                }
     675                        }
     676                }
     677        }
    767678       
    768679        return( 1 );
    769680}
    770681
    771 static void msn_auth_got_passport_token( struct msn_auth_data *mad )
    772 {
    773         struct im_connection *ic = mad->data;
     682void msn_auth_got_passport_token( struct im_connection *ic, const char *token, const char *error )
     683{
    774684        struct msn_data *md;
    775685       
     
    779689       
    780690        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 );
     691       
     692        if( token )
     693        {
     694                char buf[1536];
     695               
     696                g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
    786697                msn_write( ic, buf, strlen( buf ) );
    787698        }
    788699        else
    789700        {
    790                 imcb_error( ic, "Error during Passport authentication: %s", mad->error );
     701                imcb_error( ic, "Error during Passport authentication: %s", error );
    791702                imc_logout( ic, TRUE );
    792703        }
    793704}
    794705
    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         }
     706void msn_auth_got_contact_list( struct im_connection *ic )
     707{
     708        char buf[64];
     709        struct msn_data *md;
     710       
     711        /* Dead connection? */
     712        if( g_slist_find( msn_connections, ic ) == NULL )
     713                return;
     714       
     715        md = ic->proto_data;
     716       
     717       
     718        g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" );
     719        msn_write( ic, buf, strlen( buf ) );
     720}
     721
     722static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data )
     723{
     724        struct xt_node *adl = data, *d, *c;
     725        struct bee_user *bu = value;
     726        struct msn_buddy_data *bd = bu->data;
     727        struct msn_data *md = bu->ic->proto_data;
     728        char handle[strlen(bu->handle)];
     729        char *domain;
     730        char l[4];
     731       
     732        if( ( bd->flags & 7 ) == 0 || ( bd->flags & MSN_BUDDY_ADL_SYNCED ) )
     733                return FALSE;
     734       
     735        strcpy( handle, bu->handle );
     736        if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */
     737                return FALSE;
     738        *domain = '\0';
     739        domain ++;
     740       
     741        if( ( d = adl->children ) == NULL ||
     742            g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 )
     743        {
     744                d = xt_new_node( "d", NULL, NULL );
     745                xt_add_attr( d, "n", domain );
     746                xt_insert_child( adl, d );
     747        }
     748       
     749        g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 );
     750        c = xt_new_node( "c", NULL, NULL );
     751        xt_add_attr( c, "n", handle );
     752        xt_add_attr( c, "l", l );
     753        xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */
     754        xt_insert_child( d, c );
     755       
     756        /* Do this in batches of 100. */
     757        bd->flags |= MSN_BUDDY_ADL_SYNCED;
     758        return (--md->adl_todo % 140) == 0;
     759}
     760
     761static void msn_ns_send_adl( struct im_connection *ic )
     762{
     763        struct xt_node *adl;
     764        struct msn_data *md = ic->proto_data;
     765        char *adls, buf[64];
     766       
     767        adl = xt_new_node( "ml", NULL, NULL );
     768        xt_add_attr( adl, "l", "1" );
     769        g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
     770        if( adl->children == NULL )
     771        {
     772                /* This tells the caller that we're done now. */
     773                md->adl_todo = -1;
     774                xt_free_node( adl );
     775                return;
     776        }
     777        adls = xt_to_string( adl );
     778       
     779        g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) );
     780        if( msn_write( ic, buf, strlen( buf ) ) )
     781                msn_write( ic, adls, strlen( adls ) );
     782       
     783        g_free( adls );
     784}
     785
     786static void msn_ns_send_adl_start( struct im_connection *ic )
     787{
     788        struct msn_data *md;
     789        GSList *l;
     790       
     791        /* Dead connection? */
     792        if( g_slist_find( msn_connections, ic ) == NULL )
     793                return;
     794       
     795        md = ic->proto_data;
     796        md->adl_todo = 0;
     797        for( l = ic->bee->users; l; l = l->next )
     798        {
     799                bee_user_t *bu = l->data;
     800                struct msn_buddy_data *bd = bu->data;
     801               
     802                if( bu->ic != ic || ( bd->flags & 7 ) == 0 )
     803                        continue;
     804               
     805                bd->flags &= ~MSN_BUDDY_ADL_SYNCED;
     806                md->adl_todo++;
     807        }
     808       
     809        msn_ns_send_adl( ic );
     810}
     811
     812int msn_ns_finish_login( struct im_connection *ic )
     813{
     814        struct msn_data *md = ic->proto_data;
     815       
     816        if( ic->flags & OPT_LOGGED_IN )
     817                return 1;
     818       
     819        if( md->adl_todo < 0 )
     820                md->flags |= MSN_DONE_ADL;
     821       
     822        if( ( md->flags & MSN_DONE_ADL ) && ( md->flags & MSN_GOT_PROFILE ) )
     823                return msn_ns_set_display_name( ic, set_getstr( &ic->acc->set, "display_name" ) );
    818824        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 }
     825                return 1;
     826}
  • protocols/msn/sb.c

    rc00dd71 r4022b68  
    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
     
    3838{
    3939        int st;
     40       
     41        if( getenv( "BITLBEE_DEBUG" ) )
     42        {
     43                write( 2, "->SB:", 5 );
     44                write( 2, s, len );
     45        }
    4046       
    4147        st = write( sb->fd, s, len );
     
    407413        else if( strcmp( cmd[0], "USR" ) == 0 )
    408414        {
    409                 if( num_parts != 5 )
     415                if( num_parts < 5 )
    410416                {
    411417                        msn_sb_destroy( sb );
     
    433439                int num, tot;
    434440               
    435                 if( num_parts != 6 )
     441                if( num_parts < 6 )
    436442                {
    437443                        msn_sb_destroy( sb );
     
    470476        else if( strcmp( cmd[0], "ANS" ) == 0 )
    471477        {
    472                 if( num_parts != 3 )
     478                if( num_parts < 3 )
    473479                {
    474480                        msn_sb_destroy( sb );
     
    489495        else if( strcmp( cmd[0], "CAL" ) == 0 )
    490496        {
    491                 if( num_parts != 4 || !isdigit( cmd[3][0] ) )
     497                if( num_parts < 4 || !isdigit( cmd[3][0] ) )
    492498                {
    493499                        msn_sb_destroy( sb );
     
    499505        else if( strcmp( cmd[0], "JOI" ) == 0 )
    500506        {
    501                 if( num_parts != 3 )
     507                if( num_parts < 3 )
    502508                {
    503509                        msn_sb_destroy( sb );
     
    560566        else if( strcmp( cmd[0], "MSG" ) == 0 )
    561567        {
    562                 if( num_parts != 4 )
     568                if( num_parts < 4 )
    563569                {
    564570                        msn_sb_destroy( sb );
     
    625631                const struct msn_status_code *err = msn_status_by_number( num );
    626632               
    627                 imcb_error( ic, "Error reported by switchboard server: %s", err->text );
     633                /* If the person is offline, send an offline message instead,
     634                   and don't report an error. */
     635                if( num == 217 )
     636                        msn_soap_oim_send_queue( ic, &sb->msgq );
     637                else
     638                        imcb_error( ic, "Error reported by switchboard server: %s", err->text );
    628639               
    629640                if( err->flags & STATUS_SB_FATAL )
  • protocols/msn/tables.c

    rc00dd71 r4022b68  
    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",             STATUS_FATAL },
    8587        { 280, "Switchboard failed",                                    STATUS_SB_FATAL },
    8688        { 281, "Transfer to switchboard failed",                        0 },
  • protocols/nogaim.c

    rc00dd71 r4022b68  
    326326        imcb_log( ic, "Signing off.." );
    327327       
    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;
    335        
    336328        for( l = bee->users; l; )
    337329        {
     
    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

    rc00dd71 r4022b68  
    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

    rc00dd71 r4022b68  
    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.