Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/msn/ns.c

    reb54f56 re132b60  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2010 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    2525
    2626#include <ctype.h>
     27#include <sys/utsname.h>
    2728#include "nogaim.h"
    2829#include "msn.h"
    2930#include "md5.h"
     31#include "sha1.h"
    3032#include "soap.h"
    3133#include "xmltree.h"
     
    110112        handler->rxlen = 0;
    111113        handler->rxq = g_new0( char, 1 );
     114       
     115        if( md->uuid == NULL )
     116        {
     117                struct utsname name;
     118                sha1_state_t sha[1];
     119               
     120                /* UUID == SHA1("BitlBee" + my hostname + MSN username) */
     121                sha1_init( sha );
     122                sha1_append( sha, (void*) "BitlBee", 7 );
     123                if( uname( &name ) == 0 )
     124                {
     125                        sha1_append( sha, (void*) name.nodename, strlen( name.nodename ) );
     126                }
     127                sha1_append( sha, (void*) ic->acc->user, strlen( ic->acc->user ) );
     128                md->uuid = sha1_random_uuid( sha );
     129                memcpy( md->uuid, "b171be3e", 8 ); /* :-P */
     130        }
    112131       
    113132        if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) )
     
    353372                return st;
    354373        }
    355         else if( strcmp( cmd[0], "ILN" ) == 0 )
     374        else if( strcmp( cmd[0], "ILN" ) == 0 || strcmp( cmd[0], "NLN" ) == 0 )
    356375        {
    357376                const struct msn_away_state *st;
     377                const char *handle;
     378                int cap = 0;
    358379               
    359380                if( num_parts < 6 )
     
    363384                        return( 0 );
    364385                }
    365                
    366                 http_decode( cmd[5] );
    367                 imcb_rename_buddy( ic, cmd[3], cmd[5] );
    368                
    369                 st = msn_away_state_by_code( cmd[2] );
     386                /* ILN and NLN are more or less the same, except ILN has a trId
     387                   at the start, and NLN has a capability field at the end.
     388                   Does ILN still exist BTW? */
     389                if( cmd[0][1] == 'I' )
     390                        cmd ++;
     391                else
     392                        cap = atoi( cmd[4] );
     393
     394                handle = msn_normalize_handle( cmd[2] );
     395                if( strcmp( handle, ic->acc->user ) == 0 )
     396                        return 1; /* That's me! */
     397               
     398                http_decode( cmd[3] );
     399                imcb_rename_buddy( ic, handle, cmd[3] );
     400               
     401                st = msn_away_state_by_code( cmd[1] );
    370402                if( !st )
    371403                {
     
    374406                }
    375407               
    376                 imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN |
    377                                    ( st != msn_away_state_list ? OPT_AWAY : 0 ),
    378                                    st->name, NULL );
    379         }
    380         else if( strcmp( cmd[0], "FLN" ) == 0 )
    381         {
    382                 if( cmd[1] == NULL )
    383                         return 1;
    384                
    385                 imcb_buddy_status( ic, cmd[1], 0, NULL, NULL );
    386                
    387                 msn_sb_start_keepalives( msn_sb_by_handle( ic, cmd[1] ), TRUE );
    388         }
    389         else if( strcmp( cmd[0], "NLN" ) == 0 )
    390         {
    391                 const struct msn_away_state *st;
    392                 int cap;
    393                
    394                 if( num_parts < 6 )
    395                 {
    396                         imcb_error( ic, "Syntax error" );
    397                         imc_logout( ic, TRUE );
    398                         return( 0 );
    399                 }
    400                
    401                 http_decode( cmd[4] );
    402                 cap = atoi( cmd[5] );
    403                 imcb_rename_buddy( ic, cmd[2], cmd[4] );
    404                
    405                 st = msn_away_state_by_code( cmd[1] );
    406                 if( !st )
    407                 {
    408                         /* FIXME: Warn/Bomb about unknown away state? */
    409                         st = msn_away_state_list + 1;
    410                 }
    411                
    412                 imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |
     408                imcb_buddy_status( ic, handle, OPT_LOGGED_IN |
    413409                                   ( st != msn_away_state_list ? OPT_AWAY : 0 ) |
    414410                                   ( cap & 1 ? OPT_MOBILE : 0 ),
    415411                                   st->name, NULL );
    416412               
    417                 msn_sb_stop_keepalives( msn_sb_by_handle( ic, cmd[2] ) );
     413                msn_sb_stop_keepalives( msn_sb_by_handle( ic, handle ) );
     414        }
     415        else if( strcmp( cmd[0], "FLN" ) == 0 )
     416        {
     417                const char *handle;
     418               
     419                if( cmd[1] == NULL )
     420                        return 1;
     421               
     422                handle = msn_normalize_handle( cmd[1] );
     423                imcb_buddy_status( ic, handle, 0, NULL, NULL );
     424                msn_sb_start_keepalives( msn_sb_by_handle( ic, handle ), TRUE );
    418425        }
    419426        else if( strcmp( cmd[0], "RNG" ) == 0 )
     
    462469                else
    463470                {
    464                         sb->who = g_strdup( cmd[5] );
     471                        sb->who = g_strdup( msn_normalize_handle( cmd[5] ) );
    465472                }
    466473        }
     
    555562        {
    556563                /* Status message. */
    557                 if( num_parts >= 4 )
    558                         handler->msglen = atoi( cmd[3] );
     564                if( num_parts >= 3 )
     565                        handler->msglen = atoi( cmd[2] );
    559566        }
    560567        else if( strcmp( cmd[0], "NOT" ) == 0 )
     
    564571                if( num_parts >= 2 )
    565572                        handler->msglen = atoi( cmd[1] );
     573        }
     574        else if( strcmp( cmd[0], "UBM" ) == 0 )
     575        {
     576                if( num_parts >= 7 )
     577                        handler->msglen = atoi( cmd[6] );
     578        }
     579        else if( strcmp( cmd[0], "QNG" ) == 0 )
     580        {
     581                ic->flags |= OPT_PONGED;
    566582        }
    567583        else if( isdigit( cmd[0][0] ) )
     
    668684                        else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 )
    669685                        {
    670                                 /* Sorry, but this one really is *USELESS* */
     686                        }
     687                        else if( g_strncasecmp( ct, "text/x-msmsgsinitialmdatanotification", 37 ) == 0 ||
     688                                 g_strncasecmp( ct, "text/x-msmsgsoimnotification", 28 ) == 0 )
     689                        {
     690                                /* We received an offline message. Or at least notification
     691                                   that there is one waiting for us. Fetching the message(s)
     692                                   and purging them from the server is a lot of SOAPy work
     693                                   not worth doing IMHO. Also I thought it was possible to
     694                                   have the notification server send them directly, I was
     695                                   pretty sure I saw Pidgin do it..
     696                                   
     697                                   At least give a notification for now, seems like a
     698                                   reasonable thing to do. Only problem is, they'll keep
     699                                   coming back at login time until you read them using a
     700                                   different client. :-( */
     701                               
     702                                char *xml = get_rfc822_header( body, "Mail-Data:", blen );
     703                                struct xt_node *md, *m;
     704                               
     705                                if( !xml )
     706                                        return 1;
     707                                md = xt_from_string( xml, 0 );
     708                                if( !md )
     709                                        return 1;
     710                               
     711                                for( m = md->children; ( m = xt_find_node( m, "M" ) ); m = m->next )
     712                                {
     713                                        struct xt_node *e = xt_find_node( m->children, "E" );
     714                                        struct xt_node *rt = xt_find_node( m->children, "RT" );
     715                                        struct tm tp;
     716                                        time_t msgtime = 0;
     717                                       
     718                                        if( !e || !e->text )
     719                                                continue;
     720                                       
     721                                        memset( &tp, 0, sizeof( tp ) );
     722                                        if( rt && rt->text &&
     723                                            sscanf( rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.",
     724                                                    &tp.tm_year, &tp.tm_mon, &tp.tm_mday,
     725                                                    &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) == 6 )
     726                                        {
     727                                                tp.tm_year -= 1900;
     728                                                tp.tm_mon --;
     729                                                msgtime = mktime_utc( &tp );
     730                                               
     731                                        }
     732                                        imcb_buddy_msg( ic, e->text, "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, msgtime );
     733                                }
     734                               
     735                                g_free( xml );
     736                                xt_free_node( md );
    671737                        }
    672738                        else
     
    683749                char *psm_text = NULL;
    684750               
    685                 ubx = xt_from_string( msg );
     751                ubx = xt_from_string( msg, msglen );
    686752                if( ubx && strcmp( ubx->name, "Data" ) == 0 &&
    687753                    ( psm = xt_find_node( ubx->children, "PSM" ) ) )
    688754                        psm_text = psm->text;
    689755               
    690                 imcb_buddy_status_msg( ic, cmd[1], psm_text );
     756                imcb_buddy_status_msg( ic, msn_normalize_handle( cmd[1] ), psm_text );
    691757                xt_free_node( ubx );
    692758        }
     
    695761                struct xt_node *adl, *d, *c;
    696762               
    697                 if( !( adl = xt_from_string( msg ) ) )
     763                if( !( adl = xt_from_string( msg, msglen ) ) )
    698764                        return 1;
    699765               
     
    716782                                        continue;
    717783                               
     784                                /* FIXME: Use "t" here, guess I should just add it
     785                                   as a prefix like elsewhere in the protocol. */
    718786                                handle = g_strdup_printf( "%s@%s", cn, dn );
    719787                                if( !( ( bu = bee_user_by_handle( ic->bee, ic, handle ) ) ||
     
    741809                }
    742810        }
    743        
    744         return( 1 );
     811        else if( strcmp( cmd[0], "UBM" ) == 0 )
     812        {
     813                /* This one will give us msgs from federated networks. Technically
     814                   it should also get us offline messages, but I don't know how
     815                   I can signal MSN servers to use it. */
     816                char *ct, *handle;
     817               
     818                if( strcmp( cmd[1], ic->acc->user ) == 0 )
     819                {
     820                        /* With MPOP, you'll get copies of your own msgs from other
     821                           sessions. Discard those at least for now. */
     822                        return 1;
     823                }
     824               
     825                ct = get_rfc822_header( msg, "Content-Type", msglen );
     826                if( strncmp( ct, "text/plain", 10 ) != 0 )
     827                {
     828                        /* Typing notification or something? */
     829                        g_free( ct );
     830                        return 1;
     831                }
     832                if( strcmp( cmd[2], "1" ) != 0 )
     833                        handle = g_strdup_printf( "%s:%s", cmd[2], cmd[1] );
     834                else
     835                        handle = g_strdup( cmd[1] );
     836               
     837                imcb_buddy_msg( ic, handle, body, 0, 0 );
     838                g_free( handle );
     839        }
     840       
     841        return 1;
    745842}
    746843
     
    757854        if( token )
    758855        {
    759                 msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
     856                msn_ns_write( ic, -1, "USR %d SSO S %s %s {%s}\r\n", ++md->trId, md->tokens[0], token, md->uuid );
    760857        }
    761858        else
     
    809906        xt_add_attr( c, "n", handle );
    810907        xt_add_attr( c, "l", l );
    811         xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */
     908        xt_add_attr( c, "t", "1" ); /* FIXME: Network type, i.e. 32 for Y!MSG */
    812909        xt_insert_child( d, c );
    813910       
     
    886983        return 1;
    887984}
     985
     986int msn_ns_sendmessage( struct im_connection *ic, bee_user_t *bu, const char *text )
     987{
     988        struct msn_data *md = ic->proto_data;
     989        int type = 0;
     990        char *buf, *handle;
     991       
     992        if( strncmp( text, "\r\r\r", 3 ) == 0 )
     993                /* Err. Shouldn't happen but I guess it can. Don't send others
     994                   any of the "SHAKE THAT THING" messages. :-D */
     995                return 1;
     996       
     997        /* This might be a federated contact. Get its network number,
     998           prefixed to bu->handle with a colon. Default is 1. */
     999        for( handle = bu->handle; isdigit( *handle ); handle ++ )
     1000                type = type * 10 + *handle - '0';
     1001        if( *handle == ':' )
     1002                handle ++;
     1003        else
     1004                type = 1;
     1005       
     1006        buf = g_strdup_printf( "%s%s", MSN_MESSAGE_HEADERS, text );
     1007       
     1008        if( msn_ns_write( ic, -1, "UUM %d %s %d %d %zd\r\n%s",
     1009                                  ++md->trId, handle, type,
     1010                                  1, /* type == IM (not nudge/typing) */
     1011                                  strlen( buf ), buf ) )
     1012                return 1;
     1013        else
     1014                return 0;
     1015}
     1016
     1017void msn_ns_oim_send_queue( struct im_connection *ic, GSList **msgq )
     1018{
     1019        GSList *l;
     1020       
     1021        for( l = *msgq; l; l = l->next )
     1022        {
     1023                struct msn_message *m = l->data;
     1024                bee_user_t *bu = bee_user_by_handle( ic->bee, ic, m->who );
     1025               
     1026                if( bu )
     1027                        if( !msn_ns_sendmessage( ic, bu, m->text ) )
     1028                                return;
     1029        }
     1030       
     1031        while( *msgq != NULL )
     1032        {
     1033                struct msn_message *m = (*msgq)->data;
     1034               
     1035                g_free( m->who );
     1036                g_free( m->text );
     1037                g_free( m );
     1038               
     1039                *msgq = g_slist_remove( *msgq, m );
     1040        }
     1041}
Note: See TracChangeset for help on using the changeset viewer.