Changeset 5f40da7 for protocols/jabber
- Timestamp:
- 2011-12-26T10:51:19Z (13 years ago)
- 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. - Location:
- protocols/jabber
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/jabber/conference.c
r96f954d r5f40da7 211 211 struct xt_node *c; 212 212 char *type = xt_find_attr( node, "type" ); 213 struct jabber_data *jd = ic->proto_data; 213 214 struct jabber_chat *jc; 214 215 char *s; … … 252 253 if( bud == jc->me ) 253 254 { 254 bud->ext_jid = jabber_normalize( ic->acc->user);255 bud->ext_jid = g_strdup( jd->me ); 255 256 } 256 257 else -
protocols/jabber/iq.c
r96f954d r5f40da7 31 31 { 32 32 struct im_connection *ic = data; 33 struct jabber_data *jd = ic->proto_data; 33 34 struct xt_node *c, *reply = NULL; 34 35 char *type, *s; … … 170 171 was added to (or removed from) the buddy list. AFAIK they're 171 172 sent even if we added this buddy in our own session. */ 172 int bare_len = strlen( ic->acc->user);173 int bare_len = strlen( jd->me ); 173 174 174 175 if( ( s = xt_find_attr( node, "from" ) ) == NULL || 175 ( strncmp( s, ic->acc->user, bare_len ) == 0 &&176 ( strncmp( s, jd->me, bare_len ) == 0 && 176 177 ( s[bare_len] == 0 || s[bare_len] == '/' ) ) ) 177 178 { … … 343 344 { 344 345 c = xt_find_node( c->children, "jid" ); 345 if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && 346 strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 ) 346 if( !c || !c->text ) 347 { 348 /* Server is crap, but this is no disaster. */ 349 } 350 else if( strncmp( jd->me, c->text, strlen( jd->me ) ) != 0 ) 351 { 352 s = strchr( c->text, '/' ); 353 if( s ) 354 *s = '\0'; 355 jabber_set_me( ic, c->text ); 356 imcb_log( ic, "Server claims your JID is `%s' instead of `%s'. " 357 "This mismatch may cause problems with groupchats " 358 "and possibly other things.", 359 c->text, ic->acc->user ); 360 if( s ) 361 *s = '/'; 362 } 363 else if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && 364 strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 ) 347 365 imcb_log( ic, "Server changed session resource string to `%s'", s + 1 ); 348 366 } -
protocols/jabber/jabber.c
r96f954d r5f40da7 32 32 #include "bitlbee.h" 33 33 #include "jabber.h" 34 #include "oauth.h" 34 35 #include "md5.h" 35 36 … … 60 61 s = set_add( &acc->set, "activity_timeout", "600", set_eval_int, acc ); 61 62 63 s = set_add( &acc->set, "oauth", "false", set_eval_oauth, acc ); 64 62 65 g_snprintf( str, sizeof( str ), "%d", jabber_port_list[0] ); 63 66 s = set_add( &acc->set, "port", str, set_eval_int, acc ); … … 73 76 s = set_add( &acc->set, "resource_select", "activity", NULL, acc ); 74 77 78 s = set_add( &acc->set, "sasl", "true", set_eval_bool, acc ); 79 s->flags |= ACC_SET_OFFLINE_ONLY | SET_HIDDEN_DEFAULT; 80 75 81 s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); 76 82 s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; … … 84 90 s = set_add( &acc->set, "tls_verify", "true", set_eval_bool, acc ); 85 91 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;89 92 90 93 s = set_add( &acc->set, "user_agent", "BitlBee", NULL, acc ); … … 102 105 struct im_connection *ic = imcb_new( acc ); 103 106 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; 107 108 108 109 /* For now this is needed in the _connected() handlers if using … … 114 115 ic->proto_data = jd; 115 116 116 jd->username = g_strdup( acc->user ); 117 jd->server = strchr( jd->username, '@' ); 117 jabber_set_me( ic, acc->user ); 118 118 119 119 jd->fd = jd->r_inpa = jd->w_inpa = -1; … … 125 125 return; 126 126 } 127 128 /* So don't think of free()ing jd->server.. :-) */129 *jd->server = 0;130 jd->server ++;131 127 132 128 if( ( s = strchr( jd->server, '/' ) ) ) … … 141 137 } 142 138 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 first154 part of the server string) acc->server gets155 flushed. We don't want to have to do this another156 time. :-) */157 *s = 0;158 s ++;159 160 /* Only set this if the user didn't specify a custom161 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 an170 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 or175 the end of the string, save the port number176 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 198 139 jd->node_cache = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, jabber_cache_entry_free ); 199 140 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. */ 188 void 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; 200 195 201 196 /* Figure out the hostname to connect to. */ … … 322 317 xt_free( jd->xt ); 323 318 319 g_free( jd->oauth2_access_token ); 324 320 g_free( jd->away_message ); 325 321 g_free( jd->username ); 322 g_free( jd->me ); 326 323 g_free( jd ); 327 324 … … 339 336 if( g_strcasecmp( who, JABBER_XMLCONSOLE_HANDLE ) == 0 ) 340 337 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 } 341 353 342 354 if( ( s = strchr( who, '=' ) ) && jabber_chat_by_jid( ic, s + 1 ) ) … … 491 503 static void jabber_chat_invite_( struct groupchat *c, char *who, char *msg ) 492 504 { 505 struct jabber_data *jd = c->ic->proto_data; 493 506 struct jabber_chat *jc = c->data; 494 507 gchar *msg_alt = NULL; 495 508 496 509 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 ); 498 511 499 512 if( c && who ) -
protocols/jabber/jabber.h
r96f954d r5f40da7 47 47 JFLAG_XMLCONSOLE = 64, /* If the user added an xmlconsole buddy. */ 48 48 JFLAG_STARTTLS_DONE = 128, /* If a plaintext session was converted to TLS. */ 49 50 JFLAG_SASL_FB = 0x10000, /* Trying Facebook authentication. */ 49 51 } jabber_flags_t; 50 52 … … 92 94 char *username; /* USERNAME@server */ 93 95 char *server; /* username@SERVER -=> server/domain, not hostname */ 96 char *me; /* bare jid */ 97 98 const struct oauth2_service *oauth2_service; 99 char *oauth2_access_token; 94 100 95 101 /* After changing one of these two (or the priority setting), call … … 188 194 189 195 #define JABBER_XMLCONSOLE_HANDLE "xmlconsole" 196 #define JABBER_OAUTH_HANDLE "jabber_oauth" 190 197 191 198 /* Prefixes to use for packet IDs (mainly for IQ packets ATM). Usually the … … 232 239 #define XMLNS_IBB "http://jabber.org/protocol/ibb" /* XEP-0047 */ 233 240 241 /* jabber.c */ 242 void jabber_connect( struct im_connection *ic ); 243 234 244 /* iq.c */ 235 245 xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ); … … 300 310 struct jabber_error *jabber_error_parse( struct xt_node *node, char *xmlns ); 301 311 void jabber_error_free( struct jabber_error *err ); 312 gboolean jabber_set_me( struct im_connection *ic, const char *me ); 302 313 303 314 extern const struct jabber_away_state jabber_away_state_list[]; … … 316 327 xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); 317 328 gboolean sasl_supported( struct im_connection *ic ); 329 void sasl_oauth2_init( struct im_connection *ic ); 330 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ); 331 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ); 332 333 extern const struct oauth2_service oauth2_service_google; 334 extern const struct oauth2_service oauth2_service_facebook; 335 extern const struct oauth2_service oauth2_service_mslive; 318 336 319 337 /* conference.c */ -
protocols/jabber/jabber_util.c
r96f954d r5f40da7 761 761 g_free( err ); 762 762 } 763 764 gboolean jabber_set_me( struct im_connection *ic, const char *me ) 765 { 766 struct jabber_data *jd = ic->proto_data; 767 768 if( strchr( me, '@' ) == NULL ) 769 return FALSE; 770 771 g_free( jd->username ); 772 g_free( jd->me ); 773 774 jd->me = jabber_normalize( me ); 775 jd->server = strchr( jd->me, '@' ); 776 jd->username = g_strndup( jd->me, jd->server - jd->me ); 777 jd->server ++; 778 779 return TRUE; 780 } -
protocols/jabber/sasl.c
r96f954d r5f40da7 26 26 #include "jabber.h" 27 27 #include "base64.h" 28 #include "oauth2.h" 29 #include "oauth.h" 30 31 const struct oauth2_service oauth2_service_google = 32 { 33 "https://accounts.google.com/o/oauth2/auth", 34 "https://accounts.google.com/o/oauth2/token", 35 "urn:ietf:wg:oauth:2.0:oob", 36 "https://www.googleapis.com/auth/googletalk", 37 "783993391592.apps.googleusercontent.com", 38 "6C-Zgf7Tr7gEQTPlBhMUgo7R", 39 }; 40 const struct oauth2_service oauth2_service_facebook = 41 { 42 "https://www.facebook.com/dialog/oauth", 43 "https://graph.facebook.com/oauth/access_token", 44 "http://www.bitlbee.org/main.php/Facebook/oauth2.html", 45 "offline_access,xmpp_login", 46 "126828914005625", 47 "4b100f0f244d620bf3f15f8b217d4c32", 48 }; 49 const struct oauth2_service oauth2_service_mslive = 50 { 51 "https://oauth.live.com/authorize", 52 "https://oauth.live.com/token", 53 "http://www.bitlbee.org/main.php/Messenger/oauth2.html", 54 "wl.offline_access%20wl.messenger", 55 "000000004C06FCD1", 56 "IRKlBPzJJAWcY-TbZjiTEJu9tn7XCFaV", 57 }; 28 58 29 59 xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) … … 33 63 struct xt_node *c, *reply; 34 64 char *s; 35 int sup_plain = 0, sup_digest = 0; 65 int sup_plain = 0, sup_digest = 0, sup_gtalk = 0, sup_fb = 0, sup_ms = 0; 66 int want_oauth = FALSE; 67 GString *mechs; 36 68 37 69 if( !sasl_supported( ic ) ) … … 52 84 } 53 85 86 mechs = g_string_new( "" ); 54 87 c = node->children; 55 88 while( ( c = xt_find_node( c, "mechanism" ) ) ) … … 57 90 if( c->text && g_strcasecmp( c->text, "PLAIN" ) == 0 ) 58 91 sup_plain = 1; 59 if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 )92 else if( c->text && g_strcasecmp( c->text, "DIGEST-MD5" ) == 0 ) 60 93 sup_digest = 1; 94 else if( c->text && g_strcasecmp( c->text, "X-OAUTH2" ) == 0 ) 95 sup_gtalk = 1; 96 else if( c->text && g_strcasecmp( c->text, "X-FACEBOOK-PLATFORM" ) == 0 ) 97 sup_fb = 1; 98 else if( c->text && g_strcasecmp( c->text, "X-MESSENGER-OAUTH2" ) == 0 ) 99 sup_ms = 1; 100 101 if( c->text ) 102 g_string_append_printf( mechs, " %s", c->text ); 61 103 62 104 c = c->next; … … 65 107 if( !sup_plain && !sup_digest ) 66 108 { 67 imcb_error( ic, "No known SASL authentication schemes supported" ); 109 if( !sup_gtalk && !sup_fb && !sup_ms ) 110 imcb_error( ic, "This server requires OAuth " 111 "(supported schemes:%s)", mechs->str ); 112 else 113 imcb_error( ic, "BitlBee does not support any of the offered SASL " 114 "authentication schemes:%s", mechs->str ); 68 115 imc_logout( ic, FALSE ); 116 g_string_free( mechs, TRUE ); 69 117 return XT_ABORT; 70 118 } 119 g_string_free( mechs, TRUE ); 71 120 72 121 reply = xt_new_node( "auth", NULL, NULL ); 73 122 xt_add_attr( reply, "xmlns", XMLNS_SASL ); 74 75 if( sup_digest ) 123 want_oauth = set_getbool( &ic->acc->set, "oauth" ); 124 125 if( sup_gtalk && want_oauth ) 126 { 127 int len; 128 129 /* X-OAUTH2 is, not *the* standard OAuth2 SASL/XMPP implementation. 130 It's currently used by GTalk and vaguely documented on 131 http://code.google.com/apis/cloudprint/docs/rawxmpp.html . */ 132 xt_add_attr( reply, "mechanism", "X-OAUTH2" ); 133 134 len = strlen( jd->username ) + strlen( jd->oauth2_access_token ) + 2; 135 s = g_malloc( len + 1 ); 136 s[0] = 0; 137 strcpy( s + 1, jd->username ); 138 strcpy( s + 2 + strlen( jd->username ), jd->oauth2_access_token ); 139 reply->text = base64_encode( (unsigned char *)s, len ); 140 reply->text_len = strlen( reply->text ); 141 g_free( s ); 142 } 143 else if( sup_ms && want_oauth ) 144 { 145 xt_add_attr( reply, "mechanism", "X-MESSENGER-OAUTH2" ); 146 reply->text = g_strdup( jd->oauth2_access_token ); 147 reply->text_len = strlen( jd->oauth2_access_token ); 148 } 149 else if( sup_fb && want_oauth ) 150 { 151 xt_add_attr( reply, "mechanism", "X-FACEBOOK-PLATFORM" ); 152 jd->flags |= JFLAG_SASL_FB; 153 } 154 else if( want_oauth ) 155 { 156 imcb_error( ic, "OAuth requested, but not supported by server" ); 157 imc_logout( ic, FALSE ); 158 xt_free_node( reply ); 159 return XT_ABORT; 160 } 161 else if( sup_digest ) 76 162 { 77 163 xt_add_attr( reply, "mechanism", "DIGEST-MD5" ); … … 96 182 } 97 183 98 if( !jabber_write_packet( ic, reply ) )184 if( reply && !jabber_write_packet( ic, reply ) ) 99 185 { 100 186 xt_free_node( reply ); … … 197 283 struct im_connection *ic = data; 198 284 struct jabber_data *jd = ic->proto_data; 199 struct xt_node *reply = NULL;285 struct xt_node *reply_pkt = NULL; 200 286 char *nonce = NULL, *realm = NULL, *cnonce = NULL; 201 287 unsigned char cnonce_bin[30]; 202 288 char *digest_uri = NULL; 203 289 char *dec = NULL; 204 char *s = NULL ;290 char *s = NULL, *reply = NULL; 205 291 xt_status ret = XT_ABORT; 206 292 … … 210 296 dec = frombase64( node->text ); 211 297 212 if( !( s = sasl_get_part( dec, "rspauth" ) ) ) 298 if( jd->flags & JFLAG_SASL_FB ) 299 { 300 /* New-style Facebook OAauth2 support. Instead of sending a refresh 301 token, they just send an access token that should never expire. */ 302 GSList *p_in = NULL, *p_out = NULL; 303 char time[33]; 304 305 oauth_params_parse( &p_in, dec ); 306 oauth_params_add( &p_out, "nonce", oauth_params_get( &p_in, "nonce" ) ); 307 oauth_params_add( &p_out, "method", oauth_params_get( &p_in, "method" ) ); 308 oauth_params_free( &p_in ); 309 310 g_snprintf( time, sizeof( time ), "%lld", (long long) ( gettime() * 1000 ) ); 311 oauth_params_add( &p_out, "call_id", time ); 312 oauth_params_add( &p_out, "api_key", oauth2_service_facebook.consumer_key ); 313 oauth_params_add( &p_out, "v", "1.0" ); 314 oauth_params_add( &p_out, "format", "XML" ); 315 oauth_params_add( &p_out, "access_token", jd->oauth2_access_token ); 316 317 reply = oauth_params_string( p_out ); 318 oauth_params_free( &p_out ); 319 } 320 else if( !( s = sasl_get_part( dec, "rspauth" ) ) ) 213 321 { 214 322 /* See RFC 2831 for for information. */ … … 271 379 272 380 /* Now build the SASL response string: */ 273 g_free( dec ); 274 dec = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," 275 "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", 276 jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); 277 s = tobase64( dec ); 381 reply = g_strdup_printf( "username=\"%s\",realm=\"%s\",nonce=\"%s\",cnonce=\"%s\"," 382 "nc=%08x,qop=auth,digest-uri=\"%s\",response=%s,charset=%s", 383 jd->username, realm, nonce, cnonce, 1, digest_uri, Hh, "utf-8" ); 278 384 } 279 385 else 280 386 { 281 387 /* We found rspauth, but don't really care... */ 282 g_free( s ); 283 s = NULL; 284 } 285 286 reply = xt_new_node( "response", s, NULL ); 287 xt_add_attr( reply, "xmlns", XMLNS_SASL ); 288 289 if( !jabber_write_packet( ic, reply ) ) 388 } 389 390 s = reply ? tobase64( reply ) : NULL; 391 reply_pkt = xt_new_node( "response", s, NULL ); 392 xt_add_attr( reply_pkt, "xmlns", XMLNS_SASL ); 393 394 if( !jabber_write_packet( ic, reply_pkt ) ) 290 395 goto silent_error; 291 396 … … 301 406 g_free( cnonce ); 302 407 g_free( nonce ); 408 g_free( reply ); 303 409 g_free( realm ); 304 410 g_free( dec ); 305 411 g_free( s ); 306 xt_free_node( reply );412 xt_free_node( reply_pkt ); 307 413 308 414 return ret; … … 347 453 return ( jd->xt && jd->xt->root && xt_find_attr( jd->xt->root, "version" ) ) != 0; 348 454 } 455 456 void sasl_oauth2_init( struct im_connection *ic ) 457 { 458 struct jabber_data *jd = ic->proto_data; 459 char *msg, *url; 460 461 imcb_log( ic, "Starting OAuth authentication" ); 462 463 /* Temporary contact, just used to receive the OAuth response. */ 464 imcb_add_buddy( ic, JABBER_OAUTH_HANDLE, NULL ); 465 url = oauth2_url( jd->oauth2_service ); 466 msg = g_strdup_printf( "Open this URL in your browser to authenticate: %s", url ); 467 imcb_buddy_msg( ic, JABBER_OAUTH_HANDLE, msg, 0, 0 ); 468 imcb_buddy_msg( ic, JABBER_OAUTH_HANDLE, "Respond to this message with the returned " 469 "authorization token.", 0, 0 ); 470 471 g_free( msg ); 472 g_free( url ); 473 } 474 475 static gboolean sasl_oauth2_remove_contact( gpointer data, gint fd, b_input_condition cond ) 476 { 477 struct im_connection *ic = data; 478 if( g_slist_find( jabber_connections, ic ) ) 479 imcb_remove_buddy( ic, JABBER_OAUTH_HANDLE, NULL ); 480 return FALSE; 481 } 482 483 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token ); 484 485 int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg ) 486 { 487 struct jabber_data *jd = ic->proto_data; 488 char *code; 489 int ret; 490 491 imcb_log( ic, "Requesting OAuth access token" ); 492 493 /* Don't do it here because the caller may get confused if the contact 494 we're currently sending a message to is deleted. */ 495 b_timeout_add( 1, sasl_oauth2_remove_contact, ic ); 496 497 code = g_strdup( msg ); 498 g_strstrip( code ); 499 ret = oauth2_access_token( jd->oauth2_service, OAUTH2_AUTH_CODE, 500 code, sasl_oauth2_got_token, ic ); 501 502 g_free( code ); 503 return ret; 504 } 505 506 int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token ) 507 { 508 struct jabber_data *jd = ic->proto_data; 509 510 return oauth2_access_token( jd->oauth2_service, OAUTH2_AUTH_REFRESH, 511 refresh_token, sasl_oauth2_got_token, ic ); 512 } 513 514 static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token ) 515 { 516 struct im_connection *ic = data; 517 struct jabber_data *jd; 518 GSList *auth = NULL; 519 520 if( g_slist_find( jabber_connections, ic ) == NULL ) 521 return; 522 523 jd = ic->proto_data; 524 525 if( access_token == NULL ) 526 { 527 imcb_error( ic, "OAuth failure (missing access token)" ); 528 imc_logout( ic, TRUE ); 529 return; 530 } 531 532 oauth_params_parse( &auth, ic->acc->pass ); 533 if( refresh_token ) 534 oauth_params_set( &auth, "refresh_token", refresh_token ); 535 if( access_token ) 536 oauth_params_set( &auth, "access_token", access_token ); 537 538 g_free( ic->acc->pass ); 539 ic->acc->pass = oauth_params_string( auth ); 540 oauth_params_free( &auth ); 541 542 g_free( jd->oauth2_access_token ); 543 jd->oauth2_access_token = g_strdup( access_token ); 544 545 jabber_connect( ic ); 546 }
Note: See TracChangeset
for help on using the changeset viewer.