Ignore:
Timestamp:
2011-12-26T10:51:19Z (12 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
199fea6
Parents:
96f954d (diff), 644b808 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merging oauth-xmpp branch, which adds support for OAuth2 authentication
against some XMPP services (Google Talk, Facebook and Microsoft's MSN-XMPP
gateway).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • protocols/jabber/jabber.c

    r96f954d r5f40da7  
    3232#include "bitlbee.h"
    3333#include "jabber.h"
     34#include "oauth.h"
    3435#include "md5.h"
    3536
     
    6061        s = set_add( &acc->set, "activity_timeout", "600", set_eval_int, acc );
    6162       
     63        s = set_add( &acc->set, "oauth", "false", set_eval_oauth, acc );
     64
    6265        g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] );
    6366        s = set_add( &acc->set, "port", str, set_eval_int, acc );
     
    7376        s = set_add( &acc->set, "resource_select", "activity", NULL, acc );
    7477       
     78        s = set_add( &acc->set, "sasl", "true", set_eval_bool, acc );
     79        s->flags |= ACC_SET_OFFLINE_ONLY | SET_HIDDEN_DEFAULT;
     80       
    7581        s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
    7682        s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
     
    8490        s = set_add( &acc->set, "tls_verify", "true", set_eval_bool, acc );
    8591        s->flags |= ACC_SET_OFFLINE_ONLY;
    86        
    87         s = set_add( &acc->set, "sasl", "true", set_eval_bool, acc );
    88         s->flags |= ACC_SET_OFFLINE_ONLY | SET_HIDDEN_DEFAULT;
    8992
    9093        s = set_add( &acc->set, "user_agent", "BitlBee", NULL, acc );
     
    102105        struct im_connection *ic = imcb_new( acc );
    103106        struct jabber_data *jd = g_new0( struct jabber_data, 1 );
    104         struct ns_srv_reply **srvl = NULL, *srv = NULL;
    105         char *connect_to, *s;
    106         int i;
     107        char *s;
    107108       
    108109        /* For now this is needed in the _connected() handlers if using
     
    114115        ic->proto_data = jd;
    115116       
    116         jd->username = g_strdup( acc->user );
    117         jd->server = strchr( jd->username, '@' );
     117        jabber_set_me( ic, acc->user );
    118118       
    119119        jd->fd = jd->r_inpa = jd->w_inpa = -1;
     
    125125                return;
    126126        }
    127        
    128         /* So don't think of free()ing jd->server.. :-) */
    129         *jd->server = 0;
    130         jd->server ++;
    131127       
    132128        if( ( s = strchr( jd->server, '/' ) ) )
     
    141137        }
    142138       
    143         /* This code isn't really pretty. Backwards compatibility never is... */
    144         s = acc->server;
    145         while( s )
    146         {
    147                 static int had_port = 0;
    148                
    149                 if( strncmp( s, "ssl", 3 ) == 0 )
    150                 {
    151                         set_setstr( &acc->set, "ssl", "true" );
    152                        
    153                         /* Flush this part so that (if this was the first
    154                            part of the server string) acc->server gets
    155                            flushed. We don't want to have to do this another
    156                            time. :-) */
    157                         *s = 0;
    158                         s ++;
    159                        
    160                         /* Only set this if the user didn't specify a custom
    161                            port number already... */
    162                         if( !had_port )
    163                                 set_setint( &acc->set, "port", 5223 );
    164                 }
    165                 else if( isdigit( *s ) )
    166                 {
    167                         int i;
    168                        
    169                         /* The first character is a digit. It could be an
    170                            IP address though. Only accept this as a port#
    171                            if there are only digits. */
    172                         for( i = 0; isdigit( s[i] ); i ++ );
    173                        
    174                         /* If the first non-digit character is a colon or
    175                            the end of the string, save the port number
    176                            where it should be. */
    177                         if( s[i] == ':' || s[i] == 0 )
    178                         {
    179                                 sscanf( s, "%d", &i );
    180                                 set_setint( &acc->set, "port", i );
    181                                
    182                                 /* See above. */
    183                                 *s = 0;
    184                                 s ++;
    185                         }
    186                        
    187                         had_port = 1;
    188                 }
    189                
    190                 s = strchr( s, ':' );
    191                 if( s )
    192                 {
    193                         *s = 0;
    194                         s ++;
    195                 }
    196         }
    197        
    198139        jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free );
    199140        jd->buddies = g_hash_table_new( g_str_hash, g_str_equal );
     141       
     142        if( set_getbool( &acc->set, "oauth" ) )
     143        {
     144                GSList *p_in = NULL;
     145                const char *tok;
     146               
     147                jd->fd = jd->r_inpa = jd->w_inpa = -1;
     148               
     149                if( strstr( jd->server, ".live.com" ) )
     150                        jd->oauth2_service = &oauth2_service_mslive;
     151                else if( strstr( jd->server, ".facebook.com" ) )
     152                        jd->oauth2_service = &oauth2_service_facebook;
     153                else
     154                        jd->oauth2_service = &oauth2_service_google;
     155               
     156                oauth_params_parse( &p_in, ic->acc->pass );
     157               
     158                /* First see if we have a refresh token, in which case any
     159                   access token we *might* have has probably expired already
     160                   anyway. */
     161                if( ( tok = oauth_params_get( &p_in, "refresh_token" ) ) )
     162                {
     163                        sasl_oauth2_refresh( ic, tok );
     164                }
     165                /* If we don't have a refresh token, let's hope the access
     166                   token is still usable. */
     167                else if( ( tok = oauth_params_get( &p_in, "access_token" ) ) )
     168                {
     169                        jd->oauth2_access_token = g_strdup( tok );
     170                        jabber_connect( ic );
     171                }
     172                /* If we don't have any, start the OAuth process now. Don't
     173                   even open an XMPP connection yet. */
     174                else
     175                {
     176                        sasl_oauth2_init( ic );
     177                        ic->flags |= OPT_SLOW_LOGIN;
     178                }
     179               
     180                oauth_params_free( &p_in );
     181        }
     182        else
     183                jabber_connect( ic );
     184}
     185
     186/* Separate this from jabber_login() so we can do OAuth first if necessary.
     187   Putting this in io.c would probably be more correct. */
     188void jabber_connect( struct im_connection *ic )
     189{
     190        account_t *acc = ic->acc;
     191        struct jabber_data *jd = ic->proto_data;
     192        int i;
     193        char *connect_to;
     194        struct ns_srv_reply **srvl = NULL, *srv = NULL;
    200195       
    201196        /* Figure out the hostname to connect to. */
     
    322317        xt_free( jd->xt );
    323318       
     319        g_free( jd->oauth2_access_token );
    324320        g_free( jd->away_message );
    325321        g_free( jd->username );
     322        g_free( jd->me );
    326323        g_free( jd );
    327324       
     
    339336        if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 )
    340337                return jabber_write( ic, message, strlen( message ) );
     338       
     339        if( g_strcasecmp( who, JABBER_OAUTH_HANDLE ) == 0 &&
     340            !( jd->flags & OPT_LOGGED_IN ) && jd->fd == -1 )
     341        {
     342                if( sasl_oauth2_get_refresh_token( ic, message ) )
     343                {
     344                        return 1;
     345                }
     346                else
     347                {
     348                        imcb_error( ic, "OAuth failure" );
     349                        imc_logout( ic, TRUE );
     350                        return 0;
     351                }
     352        }
    341353       
    342354        if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) )
     
    491503static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg )
    492504{
     505        struct jabber_data *jd = c->ic->proto_data;
    493506        struct jabber_chat *jc = c->data;
    494507        gchar *msg_alt = NULL;
    495508
    496509        if( msg == NULL )
    497                 msg_alt = g_strdup_printf( "%s invited you to %s", c->ic->acc->user, jc->name );
     510                msg_alt = g_strdup_printf( "%s invited you to %s", jd->me, jc->name );
    498511       
    499512        if( c && who )
Note: See TracChangeset for help on using the changeset viewer.