From 718e05f842c1af043eb4efded8b0afe429377f70 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 29 Jul 2008 00:44:58 +0100 Subject: ext_yahoo_error() shouldn't close the connection if the error is fatal, the caller will do it already. --- protocols/yahoo/yahoo.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'protocols') diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 197d76a1..8d9e95d8 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -664,9 +664,6 @@ void ext_yahoo_error( int id, const char *err, int fatal, int num ) struct im_connection *ic = byahoo_get_ic_by_id( id ); imcb_error( ic, "%s", err ); - - if( fatal ) - imc_logout( ic, TRUE ); } /* TODO: Clear up the mess of inp and d structures */ -- cgit v1.2.3 From 0f4c2734cd78168c42700d773cca666fab363f66 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 31 Jul 2008 21:44:43 +0100 Subject: Reverting to the old MSN/Passport authentication mechanism, the new one is "broken". (Bug #439) --- protocols/msn/ns.c | 30 +++-- protocols/msn/passport.c | 281 ++++++++++++++++++++++++++++------------------- protocols/msn/passport.h | 93 +++------------- 3 files changed, 197 insertions(+), 207 deletions(-) (limited to 'protocols') diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index fe48f96d..96363778 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -33,7 +33,7 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_token( struct msn_auth_data *mad ); +static void msn_auth_got_passport_id( struct passport_reply *rep ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { @@ -221,7 +221,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { /* Time for some Passport black magic... */ - if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) + if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) { imcb_error( ic, "Error while contacting Passport server" ); imc_logout( ic, TRUE ); @@ -708,26 +708,22 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -static void msn_auth_got_passport_token( struct msn_auth_data *mad ) +static void msn_auth_got_passport_id( struct passport_reply *rep ) { - struct im_connection *ic = mad->data; - struct msn_data *md; - - /* Dead connection? */ - if( g_slist_find( msn_connections, ic ) == NULL ) - return; + struct im_connection *ic = rep->data; + struct msn_data *md = ic->proto_data; + char *key = rep->result; + char buf[1024]; - md = ic->proto_data; - if( mad->token ) + if( key == NULL ) { - char buf[1024]; - - g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); - msn_write( ic, buf, strlen( buf ) ); + imcb_error( ic, "Error during Passport authentication (%s)", + rep->error_string ? rep->error_string : "Unknown error" ); + imc_logout( ic, TRUE ); } else { - imcb_error( ic, "Error during Passport authentication: %s", mad->error ); - imc_logout( ic, TRUE ); + g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); + msn_write( ic, buf, strlen( buf ) ); } } diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 565d15f3..673b488d 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -1,7 +1,8 @@ -/** passport.c +/* passport.c * - * Functions to login to Microsoft Passport service for Messenger - * Copyright (C) 2004-2008 Wilmer van der Gaast + * Functions to login to microsoft passport service for Messenger + * Copyright (C) 2004 Wouter Paesen + * Copyright (C) 2004 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -22,149 +23,209 @@ #include "passport.h" #include "msn.h" #include "bitlbee.h" -#include "url.h" -#include "misc.h" -#include "xmltree.h" #include #include -static int passport_get_token_real( struct msn_auth_data *mad ); -static void passport_get_token_ready( struct http_request *req ); +#define MSN_BUF_LEN 8192 -int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) +static char *prd_cached = NULL; + +static int passport_get_id_real( gpointer func, gpointer data, char *header ); +static void passport_get_id_ready( struct http_request *req ); + +static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); +static void passport_retrieve_dalogin_ready( struct http_request *req ); + +static char *passport_create_header( char *cookie, char *email, char *pwd ); +static void destroy_reply( struct passport_reply *rep ); + +int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) { - struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); - int i; - - mad->username = g_strdup( username ); - mad->password = g_strdup( password ); - mad->cookie = g_strdup( cookie ); - - mad->callback = func; - mad->data = data; - - mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); - mad->ttl = 3; /* Max. # of redirects. */ + char *header = passport_create_header( cookie, username, password ); - /* HTTP-escape stuff and s/,/&/ */ - http_decode( mad->cookie ); - for( i = 0; mad->cookie[i]; i ++ ) - if( mad->cookie[i] == ',' ) - mad->cookie[i] = '&'; - - /* Microsoft doesn't allow password longer than 16 chars and silently - fails authentication if you give the "full version" of your passwd. */ - if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) - mad->password[MAX_PASSPORT_PWLEN] = 0; - - return passport_get_token_real( mad ); + if( prd_cached == NULL ) + return passport_retrieve_dalogin( func, data, header ); + else + return passport_get_id_real( func, data, header ); } -static int passport_get_token_real( struct msn_auth_data *mad ) +static int passport_get_id_real( gpointer func, gpointer data, char *header ) { - char *post_payload, *post_request; + struct passport_reply *rep; + char *server, *dummy, *reqs; struct http_request *req; - url_t url; - url_set( &url, mad->url ); + rep = g_new0( struct passport_reply, 1 ); + rep->data = data; + rep->func = func; + rep->header = header; + + server = g_strdup( prd_cached ); + dummy = strchr( server, '/' ); + + if( dummy == NULL ) + { + destroy_reply( rep ); + return( 0 ); + } + + reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); - post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, - mad->username, - mad->password, - mad->cookie ); + *dummy = 0; + req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); - post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, - url.file, url.host, - (int) strlen( post_payload ), - post_payload ); - - req = http_dorequest( url.host, url.port, 1, post_request, - passport_get_token_ready, mad ); + g_free( server ); + g_free( reqs ); - g_free( post_request ); - g_free( post_payload ); + if( req == NULL ) + destroy_reply( rep ); - return req != NULL; + return( req != NULL ); } -static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); -static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); - -static const struct xt_handler_entry passport_xt_handlers[] = { - { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, - { "S:Fault", "S:Envelope", passport_xt_handle_fault }, - { NULL, NULL, NULL } -}; - -static void passport_get_token_ready( struct http_request *req ) +static void passport_get_id_ready( struct http_request *req ) { - struct msn_auth_data *mad = req->data; - struct xt_parser *parser; - - g_free( mad->url ); - g_free( mad->error ); - mad->url = mad->error = NULL; + struct passport_reply *rep = req->data; - if( req->status_code == 200 ) - { - parser = xt_new( passport_xt_handlers, mad ); - xt_feed( parser, req->reply_body, req->body_size ); - xt_handle( parser, NULL, -1 ); - xt_free( parser ); - } - else + if( !g_slist_find( msn_connections, rep->data ) ) { - mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, - req->status_string ? req->status_string : "unknown" ); + destroy_reply( rep ); + return; } - if( mad->error == NULL && mad->token == NULL ) - mad->error = g_strdup( "Could not parse Passport server response" ); - - if( mad->url && mad->token == NULL ) + if( req->finished && req->reply_headers && req->status_code == 200 ) { - passport_get_token_real( mad ); + char *dummy; + + if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) + { + char *responseend; + + dummy += strlen( "from-PP='" ); + responseend = strchr( dummy, '\'' ); + if( responseend ) + *responseend = 0; + + rep->result = g_strdup( dummy ); + } + else + { + rep->error_string = g_strdup( "Could not parse Passport server response" ); + } } else { - mad->callback( mad ); - - g_free( mad->url ); - g_free( mad->username ); - g_free( mad->password ); - g_free( mad->cookie ); - g_free( mad->token ); - g_free( mad->error ); - g_free( mad ); + rep->error_string = g_strdup_printf( "HTTP error: %s", + req->status_string ? req->status_string : "Unknown error" ); } + + rep->func( rep ); + destroy_reply( rep ); } -static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) +static char *passport_create_header( char *cookie, char *email, char *pwd ) { - struct msn_auth_data *mad = data; - char *s; + char *buffer; + char *currenttoken; + char *email_enc, *pwd_enc; + + currenttoken = strstr( cookie, "lc=" ); + if( currenttoken == NULL ) + return NULL; + + email_enc = g_new0( char, strlen( email ) * 3 + 1 ); + strcpy( email_enc, email ); + http_encode( email_enc ); + + pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); + g_snprintf( pwd_enc, 17, "%s", pwd ); /* Passwords >16 chars never succeed. (Bug #360) */ + strcpy( pwd_enc, pwd ); + http_encode( pwd_enc ); - if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) - mad->token = g_memdup( node->text, node->text_len + 1 ); + buffer = g_strdup_printf( "Authorization: Passport1.4 OrgVerb=GET," + "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," + "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, + currenttoken ); - return XT_HANDLED; + g_free( email_enc ); + g_free( pwd_enc ); + + return buffer; } -static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) +static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) { - struct msn_auth_data *mad = data; - struct xt_node *code = xt_find_node( node->children, "faultcode" ); - struct xt_node *string = xt_find_node( node->children, "faultstring" ); - struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); + struct passport_reply *rep = g_new0( struct passport_reply, 1 ); + struct http_request *req; - if( redirect && redirect->text_len && mad->ttl-- > 0 ) - mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); + rep->data = data; + rep->func = func; + rep->header = header; - if( code == NULL || code->text_len == 0 ) - mad->error = g_strdup( "Unknown error" ); - else - mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? - string->text : "no description available" ); + req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep ); + + if( !req ) + destroy_reply( rep ); + + return( req != NULL ); +} + +static void passport_retrieve_dalogin_ready( struct http_request *req ) +{ + struct passport_reply *rep = req->data; + char *dalogin; + char *urlend; + + if( !g_slist_find( msn_connections, rep->data ) ) + { + destroy_reply( rep ); + return; + } + + if( !req->finished || !req->reply_headers || req->status_code != 200 ) + { + rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s", + req->status_string ? req->status_string : "Unknown error" ); + goto failure; + } - return XT_HANDLED; + dalogin = strstr( req->reply_headers, "DALogin=" ); + + if( !dalogin ) + { + rep->error_string = g_strdup( "Parse error while fetching DALogin" ); + goto failure; + } + + dalogin += strlen( "DALogin=" ); + urlend = strchr( dalogin, ',' ); + if( urlend ) + *urlend = 0; + + /* strip the http(s):// part from the url */ + urlend = strstr( urlend, "://" ); + if( urlend ) + dalogin = urlend + strlen( "://" ); + + if( prd_cached == NULL ) + prd_cached = g_strdup( dalogin ); + + if( passport_get_id_real( rep->func, rep->data, rep->header ) ) + { + rep->header = NULL; + destroy_reply( rep ); + return; + } + +failure: + rep->func( rep ); + destroy_reply( rep ); +} + +static void destroy_reply( struct passport_reply *rep ) +{ + g_free( rep->result ); + g_free( rep->header ); + g_free( rep->error_string ); + g_free( rep ); } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 517d2e91..9fd81a82 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -1,7 +1,10 @@ +#ifndef __PASSPORT_H__ +#define __PASSPORT_H__ /* passport.h * - * Functions to login to Microsoft Passport service for Messenger - * Copyright (C) 2004-2008 Wilmer van der Gaast + * Functions to login to Microsoft Passport Service for Messenger + * Copyright (C) 2004 Wouter Paesen , + * Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -14,15 +17,9 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener - for the specs! */ - -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__ - #include #include #include @@ -35,79 +32,15 @@ #endif #include "nogaim.h" -#define MAX_PASSPORT_PWLEN 16 - -struct msn_auth_data +struct passport_reply { - char *url; - int ttl; - - char *username; - char *password; - char *cookie; - - /* The end result, the only thing we'll really be interested in - once finished. */ - char *token; - char *error; /* Yeah, or that... */ - - void (*callback)( struct msn_auth_data *mad ); - gpointer data; + void (*func)( struct passport_reply * ); + void *data; + char *result; + char *header; + char *error_string; }; -#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" - -#define SOAP_AUTHENTICATION_REQUEST \ -"POST %s HTTP/1.0\r\n" \ -"Accept: text/*\r\n" \ -"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ -"Host: %s\r\n" \ -"Content-Length: %d\r\n" \ -"Cache-Control: no-cache\r\n" \ -"\r\n" \ -"%s" - -#define SOAP_AUTHENTICATION_PAYLOAD \ -"" \ -"" \ - "
" \ - "" \ - "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" \ - "4" \ - "1" \ - "" \ - "AQAAAAIAAABsYwQAAAAzMDg0" \ - "" \ - "" \ - "" \ - "%s" \ - "%s" \ - "" \ - "" \ - "
" \ - "" \ - "" \ - "" \ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ - "" \ - "" \ - "http://Passport.NET/tb" \ - "" \ - "" \ - "" \ - "" \ - "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ - "" \ - "" \ - "messenger.msn.com" \ - "" \ - "" \ - "" \ - "" \ - "" \ - "" \ -"
" - -int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ); +int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); #endif /* __PASSPORT_H__ */ -- cgit v1.2.3 From d84e2a93feae8db909dfbe63b55066cb4e8160dc Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 2 Aug 2008 12:21:36 +0100 Subject: Microsoft, I hate you. --- protocols/msn/ns.c | 30 ++--- protocols/msn/passport.c | 281 +++++++++++++++++++---------------------------- protocols/msn/passport.h | 93 +++++++++++++--- 3 files changed, 207 insertions(+), 197 deletions(-) (limited to 'protocols') diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 96363778..fe48f96d 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -33,7 +33,7 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_id( struct passport_reply *rep ); +static void msn_auth_got_passport_token( struct msn_auth_data *mad ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { @@ -221,7 +221,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { /* Time for some Passport black magic... */ - if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) + if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) { imcb_error( ic, "Error while contacting Passport server" ); imc_logout( ic, TRUE ); @@ -708,22 +708,26 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -static void msn_auth_got_passport_id( struct passport_reply *rep ) +static void msn_auth_got_passport_token( struct msn_auth_data *mad ) { - struct im_connection *ic = rep->data; - struct msn_data *md = ic->proto_data; - char *key = rep->result; - char buf[1024]; + struct im_connection *ic = mad->data; + struct msn_data *md; - if( key == NULL ) + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + if( mad->token ) { - imcb_error( ic, "Error during Passport authentication (%s)", - rep->error_string ? rep->error_string : "Unknown error" ); - imc_logout( ic, TRUE ); + char buf[1024]; + + g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); + msn_write( ic, buf, strlen( buf ) ); } else { - g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); - msn_write( ic, buf, strlen( buf ) ); + imcb_error( ic, "Error during Passport authentication: %s", mad->error ); + imc_logout( ic, TRUE ); } } diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 673b488d..565d15f3 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -1,8 +1,7 @@ -/* passport.c +/** passport.c * - * Functions to login to microsoft passport service for Messenger - * Copyright (C) 2004 Wouter Paesen - * Copyright (C) 2004 Wilmer van der Gaast + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -23,209 +22,149 @@ #include "passport.h" #include "msn.h" #include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "xmltree.h" #include #include -#define MSN_BUF_LEN 8192 +static int passport_get_token_real( struct msn_auth_data *mad ); +static void passport_get_token_ready( struct http_request *req ); -static char *prd_cached = NULL; - -static int passport_get_id_real( gpointer func, gpointer data, char *header ); -static void passport_get_id_ready( struct http_request *req ); - -static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); -static void passport_retrieve_dalogin_ready( struct http_request *req ); - -static char *passport_create_header( char *cookie, char *email, char *pwd ); -static void destroy_reply( struct passport_reply *rep ); - -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) -{ - char *header = passport_create_header( cookie, username, password ); - - if( prd_cached == NULL ) - return passport_retrieve_dalogin( func, data, header ); - else - return passport_get_id_real( func, data, header ); -} - -static int passport_get_id_real( gpointer func, gpointer data, char *header ) +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) { - struct passport_reply *rep; - char *server, *dummy, *reqs; - struct http_request *req; - - rep = g_new0( struct passport_reply, 1 ); - rep->data = data; - rep->func = func; - rep->header = header; - - server = g_strdup( prd_cached ); - dummy = strchr( server, '/' ); - - if( dummy == NULL ) - { - destroy_reply( rep ); - return( 0 ); - } - - reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); + struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); + int i; - *dummy = 0; - req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); + mad->username = g_strdup( username ); + mad->password = g_strdup( password ); + mad->cookie = g_strdup( cookie ); - g_free( server ); - g_free( reqs ); + mad->callback = func; + mad->data = data; - if( req == NULL ) - destroy_reply( rep ); + mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); + mad->ttl = 3; /* Max. # of redirects. */ - return( req != NULL ); -} - -static void passport_get_id_ready( struct http_request *req ) -{ - struct passport_reply *rep = req->data; - - if( !g_slist_find( msn_connections, rep->data ) ) - { - destroy_reply( rep ); - return; - } + /* HTTP-escape stuff and s/,/&/ */ + http_decode( mad->cookie ); + for( i = 0; mad->cookie[i]; i ++ ) + if( mad->cookie[i] == ',' ) + mad->cookie[i] = '&'; - if( req->finished && req->reply_headers && req->status_code == 200 ) - { - char *dummy; - - if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) - { - char *responseend; - - dummy += strlen( "from-PP='" ); - responseend = strchr( dummy, '\'' ); - if( responseend ) - *responseend = 0; - - rep->result = g_strdup( dummy ); - } - else - { - rep->error_string = g_strdup( "Could not parse Passport server response" ); - } - } - else - { - rep->error_string = g_strdup_printf( "HTTP error: %s", - req->status_string ? req->status_string : "Unknown error" ); - } + /* Microsoft doesn't allow password longer than 16 chars and silently + fails authentication if you give the "full version" of your passwd. */ + if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) + mad->password[MAX_PASSPORT_PWLEN] = 0; - rep->func( rep ); - destroy_reply( rep ); + return passport_get_token_real( mad ); } -static char *passport_create_header( char *cookie, char *email, char *pwd ) +static int passport_get_token_real( struct msn_auth_data *mad ) { - char *buffer; - char *currenttoken; - char *email_enc, *pwd_enc; - - currenttoken = strstr( cookie, "lc=" ); - if( currenttoken == NULL ) - return NULL; + char *post_payload, *post_request; + struct http_request *req; + url_t url; - email_enc = g_new0( char, strlen( email ) * 3 + 1 ); - strcpy( email_enc, email ); - http_encode( email_enc ); + url_set( &url, mad->url ); - pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); - g_snprintf( pwd_enc, 17, "%s", pwd ); /* Passwords >16 chars never succeed. (Bug #360) */ - strcpy( pwd_enc, pwd ); - http_encode( pwd_enc ); + post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, + mad->username, + mad->password, + mad->cookie ); - buffer = g_strdup_printf( "Authorization: Passport1.4 OrgVerb=GET," - "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," - "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, - currenttoken ); + post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, + url.file, url.host, + (int) strlen( post_payload ), + post_payload ); + + req = http_dorequest( url.host, url.port, 1, post_request, + passport_get_token_ready, mad ); - g_free( email_enc ); - g_free( pwd_enc ); + g_free( post_request ); + g_free( post_payload ); - return buffer; + return req != NULL; } -static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) -{ - struct passport_reply *rep = g_new0( struct passport_reply, 1 ); - struct http_request *req; - - rep->data = data; - rep->func = func; - rep->header = header; - - req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep ); - - if( !req ) - destroy_reply( rep ); - - return( req != NULL ); -} +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); -static void passport_retrieve_dalogin_ready( struct http_request *req ) +static const struct xt_handler_entry passport_xt_handlers[] = { + { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, + { "S:Fault", "S:Envelope", passport_xt_handle_fault }, + { NULL, NULL, NULL } +}; + +static void passport_get_token_ready( struct http_request *req ) { - struct passport_reply *rep = req->data; - char *dalogin; - char *urlend; + struct msn_auth_data *mad = req->data; + struct xt_parser *parser; + + g_free( mad->url ); + g_free( mad->error ); + mad->url = mad->error = NULL; - if( !g_slist_find( msn_connections, rep->data ) ) + if( req->status_code == 200 ) { - destroy_reply( rep ); - return; + parser = xt_new( passport_xt_handlers, mad ); + xt_feed( parser, req->reply_body, req->body_size ); + xt_handle( parser, NULL, -1 ); + xt_free( parser ); } - - if( !req->finished || !req->reply_headers || req->status_code != 200 ) + else { - rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s", - req->status_string ? req->status_string : "Unknown error" ); - goto failure; + mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, + req->status_string ? req->status_string : "unknown" ); } - dalogin = strstr( req->reply_headers, "DALogin=" ); + if( mad->error == NULL && mad->token == NULL ) + mad->error = g_strdup( "Could not parse Passport server response" ); - if( !dalogin ) + if( mad->url && mad->token == NULL ) { - rep->error_string = g_strdup( "Parse error while fetching DALogin" ); - goto failure; + passport_get_token_real( mad ); } - - dalogin += strlen( "DALogin=" ); - urlend = strchr( dalogin, ',' ); - if( urlend ) - *urlend = 0; - - /* strip the http(s):// part from the url */ - urlend = strstr( urlend, "://" ); - if( urlend ) - dalogin = urlend + strlen( "://" ); - - if( prd_cached == NULL ) - prd_cached = g_strdup( dalogin ); - - if( passport_get_id_real( rep->func, rep->data, rep->header ) ) + else { - rep->header = NULL; - destroy_reply( rep ); - return; + mad->callback( mad ); + + g_free( mad->url ); + g_free( mad->username ); + g_free( mad->password ); + g_free( mad->cookie ); + g_free( mad->token ); + g_free( mad->error ); + g_free( mad ); } +} + +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) +{ + struct msn_auth_data *mad = data; + char *s; + + if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) + mad->token = g_memdup( node->text, node->text_len + 1 ); -failure: - rep->func( rep ); - destroy_reply( rep ); + return XT_HANDLED; } -static void destroy_reply( struct passport_reply *rep ) +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) { - g_free( rep->result ); - g_free( rep->header ); - g_free( rep->error_string ); - g_free( rep ); + struct msn_auth_data *mad = data; + struct xt_node *code = xt_find_node( node->children, "faultcode" ); + struct xt_node *string = xt_find_node( node->children, "faultstring" ); + struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); + + if( redirect && redirect->text_len && mad->ttl-- > 0 ) + mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); + + if( code == NULL || code->text_len == 0 ) + mad->error = g_strdup( "Unknown error" ); + else + mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? + string->text : "no description available" ); + + return XT_HANDLED; } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 9fd81a82..517d2e91 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -1,10 +1,7 @@ -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__ /* passport.h * - * Functions to login to Microsoft Passport Service for Messenger - * Copyright (C) 2004 Wouter Paesen , - * Wilmer van der Gaast + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -17,9 +14,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener + for the specs! */ + +#ifndef __PASSPORT_H__ +#define __PASSPORT_H__ + #include #include #include @@ -32,15 +35,79 @@ #endif #include "nogaim.h" -struct passport_reply +#define MAX_PASSPORT_PWLEN 16 + +struct msn_auth_data { - void (*func)( struct passport_reply * ); - void *data; - char *result; - char *header; - char *error_string; + char *url; + int ttl; + + char *username; + char *password; + char *cookie; + + /* The end result, the only thing we'll really be interested in + once finished. */ + char *token; + char *error; /* Yeah, or that... */ + + void (*callback)( struct msn_auth_data *mad ); + gpointer data; }; -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); +#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" + +#define SOAP_AUTHENTICATION_REQUEST \ +"POST %s HTTP/1.0\r\n" \ +"Accept: text/*\r\n" \ +"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ +"Host: %s\r\n" \ +"Content-Length: %d\r\n" \ +"Cache-Control: no-cache\r\n" \ +"\r\n" \ +"%s" + +#define SOAP_AUTHENTICATION_PAYLOAD \ +"" \ +"" \ + "
" \ + "" \ + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" \ + "4" \ + "1" \ + "" \ + "AQAAAAIAAABsYwQAAAAzMDg0" \ + "" \ + "" \ + "" \ + "%s" \ + "%s" \ + "" \ + "" \ + "
" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "http://Passport.NET/tb" \ + "" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "messenger.msn.com" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ +"
" + +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ); #endif /* __PASSPORT_H__ */ -- cgit v1.2.3 From 280e655722c8660ec2dff9b08f82b10d5559bfd9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 6 Aug 2008 00:07:07 +0100 Subject: Simple exponential backoff code. Have to add a maximum delay setting, something like 5*5<300: 5s, multiply by 5 on each failure, but stop increasing once we hit 5m. --- protocols/nogaim.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 7466e93a..eb3fc2ad 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -266,6 +266,10 @@ void imcb_connected( struct im_connection *ic ) /* Also necessary when we're not away, at least for some of the protocols. */ imc_set_away( ic, u->away ); + + /* Apparently we're connected successfully, so reset the + exponential backoff timer. */ + ic->acc->auto_reconnect_delay = 0; } gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ) @@ -330,7 +334,7 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) && set_getbool( &a->set, "auto_reconnect" ) ) { - int delay = set_getint( &irc->set, "auto_reconnect_delay" ); + int delay = account_reconnect_delay( a ); imcb_log( ic, "Reconnecting in %d seconds..", delay ); a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a ); -- cgit v1.2.3 From 4230221725b0cd0f6a9b84f726759d20ff9f0e62 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 10 Aug 2008 00:00:38 +0100 Subject: Added ceiling to auto-reconnect delay, changed the default to 5*3<900 and added documentation. --- protocols/nogaim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index eb3fc2ad..b6f8d6e4 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -293,6 +293,7 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) irc_t *irc = ic->irc; user_t *t, *u; account_t *a; + int delay; /* Nested calls might happen sometimes, this is probably the best place to catch them. */ @@ -332,10 +333,9 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) /* Uhm... This is very sick. */ } else if( allow_reconnect && set_getbool( &irc->set, "auto_reconnect" ) && - set_getbool( &a->set, "auto_reconnect" ) ) + set_getbool( &a->set, "auto_reconnect" ) && + ( delay = account_reconnect_delay( a ) ) > 0 ) { - int delay = account_reconnect_delay( a ); - imcb_log( ic, "Reconnecting in %d seconds..", delay ); a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a ); } -- cgit v1.2.3 From a8305126a38eb977c51046dd4ec3ac258a20a98f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 10 Aug 2008 10:15:26 +0100 Subject: Added msn_sb_write_msg() (patch from ulim). --- protocols/msn/msn.c | 61 +++-------------------------------------------------- protocols/msn/msn.h | 6 ++++++ protocols/msn/sb.c | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 58 deletions(-) (limited to 'protocols') diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index a2e8519a..046b2772 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -112,7 +112,6 @@ static void msn_logout( struct im_connection *ic ) static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away ) { struct msn_switchboard *sb; - struct msn_data *md = ic->proto_data; if( ( sb = msn_sb_by_handle( ic, who ) ) ) { @@ -121,47 +120,13 @@ static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, in else { struct msn_message *m; - char buf[1024]; /* Create a message. We have to arrange a usable switchboard, and send the message later. */ m = g_new0( struct msn_message, 1 ); m->who = g_strdup( who ); m->text = g_strdup( message ); - /* FIXME: *CHECK* the reliability of using spare sb's! */ - if( ( sb = msn_sb_spare( ic ) ) ) - { - debug( "Trying to use a spare switchboard to message %s", who ); - - sb->who = g_strdup( who ); - g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who ); - if( msn_sb_write( sb, buf, strlen( buf ) ) ) - { - /* He/She should join the switchboard soon, let's queue the message. */ - sb->msgq = g_slist_append( sb->msgq, m ); - return( 1 ); - } - } - - debug( "Creating a new switchboard to message %s", who ); - - /* If we reach this line, there was no spare switchboard, so let's make one. */ - g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( ic, buf, strlen( buf ) ) ) - { - g_free( m->who ); - g_free( m->text ); - g_free( m ); - - return( 0 ); - } - - /* And queue the message to md. We'll pick it up when the switchboard comes up. */ - md->msgq = g_slist_append( md->msgq, m ); - - /* FIXME: If the switchboard creation fails, the message will not be sent. */ - - return( 1 ); + return msn_sb_write_msg( ic, m ); } return( 0 ); @@ -251,8 +216,6 @@ static void msn_chat_leave( struct groupchat *c ) static struct groupchat *msn_chat_with( struct im_connection *ic, char *who ) { struct msn_switchboard *sb; - struct msn_data *md = ic->proto_data; - char buf[1024]; if( ( sb = msn_sb_by_handle( ic, who ) ) ) { @@ -263,31 +226,13 @@ static struct groupchat *msn_chat_with( struct im_connection *ic, char *who ) { struct msn_message *m; - if( ( sb = msn_sb_spare( ic ) ) ) - { - debug( "Trying to reuse an existing switchboard as a groupchat with %s", who ); - g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who ); - if( msn_sb_write( sb, buf, strlen( buf ) ) ) - return msn_sb_to_chat( sb ); - } - - /* If the stuff above failed for some reason: */ - debug( "Creating a new switchboard to groupchat with %s", who ); - - /* Request a new switchboard. */ - g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( ic, buf, strlen( buf ) ) ) - return( 0 ); - /* Create a magic message. This is quite hackish, but who cares? :-P */ m = g_new0( struct msn_message, 1 ); m->who = g_strdup( who ); m->text = g_strdup( GROUPCHAT_SWITCHBOARD_MESSAGE ); - /* Queue the magic message and cross your fingers. */ - md->msgq = g_slist_append( md->msgq, m ); - - /* FIXME: Can I try to return something here already? */ + msn_sb_write_msg( ic, m ); + return NULL; } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 63759303..7c849acf 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -23,6 +23,9 @@ Suite 330, Boston, MA 02111-1307 USA */ +#ifndef _MSN_H +#define _MSN_H + /* Some hackish magicstrings to make special-purpose messages/switchboards. */ #define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r" @@ -175,3 +178,6 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ); struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ); void msn_sb_destroy( struct msn_switchboard *sb ); gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ); +int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m ); + +#endif //_MSN_H diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 18c41ef5..e9526234 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -47,6 +47,48 @@ int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) return( 1 ); } +int msn_sb_write_msg( struct im_connection *ic, struct msn_message *m ) +{ + struct msn_data *md = ic->proto_data; + struct msn_switchboard *sb; + char buf[1024]; + + /* FIXME: *CHECK* the reliability of using spare sb's! */ + if( ( sb = msn_sb_spare( ic ) ) ) + { + debug( "Trying to use a spare switchboard to message %s", m->who ); + + sb->who = g_strdup( m->who ); + g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, m->who ); + if( msn_sb_write( sb, buf, strlen( buf ) ) ) + { + /* He/She should join the switchboard soon, let's queue the message. */ + sb->msgq = g_slist_append( sb->msgq, m ); + return( 1 ); + } + } + + debug( "Creating a new switchboard to message %s", m->who ); + + /* If we reach this line, there was no spare switchboard, so let's make one. */ + g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); + if( !msn_write( ic, buf, strlen( buf ) ) ) + { + g_free( m->who ); + g_free( m->text ); + g_free( m ); + + return( 0 ); + } + + /* And queue the message to md. We'll pick it up when the switchboard comes up. */ + md->msgq = g_slist_append( md->msgq, m ); + + /* FIXME: If the switchboard creation fails, the message will not be sent. */ + + return( 1 ); +} + struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ) { struct msn_data *md = ic->proto_data; -- cgit v1.2.3 From 7125cb3775a0e384c0f2fc08fd56df9582199502 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 24 Aug 2008 19:01:05 +0100 Subject: Added SET_INVALID, which set evaluators should now return instead of NULL when the given value is not accepted. This to allow certain variables actually be set to NULL (server, for example). This should fully close #444. --- protocols/jabber/jabber.c | 2 +- protocols/jabber/jabber_util.c | 4 ++-- protocols/nogaim.c | 12 ++++-------- 3 files changed, 7 insertions(+), 11 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index c9c1d0a0..ac8638cf 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -69,7 +69,7 @@ static void jabber_init( account_t *acc ) s = set_add( &acc->set, "resource_select", "priority", NULL, acc ); s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); - s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; + s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 1bee5009..19a73b6a 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -36,10 +36,10 @@ char *set_eval_priority( set_t *set, char *value ) { /* Priority is a signed 8-bit integer, according to RFC 3921. */ if( i < -128 || i > 127 ) - return NULL; + return SET_INVALID; } else - return NULL; + return SET_INVALID; /* Only run this stuff if the account is online ATM, and if the setting seems to be acceptable. */ diff --git a/protocols/nogaim.c b/protocols/nogaim.c index b6f8d6e4..6a267adf 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -927,14 +927,10 @@ char *set_eval_away_devoice( set_t *set, char *value ) irc_t *irc = set->data; int st; - if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) - st = 1; - else if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) - st = 0; - else if( sscanf( value, "%d", &st ) != 1 ) - return( NULL ); + if( !is_bool( value ) ) + return SET_INVALID; - st = st != 0; + st = bool2int( value ); /* Horror.... */ @@ -978,7 +974,7 @@ char *set_eval_away_devoice( set_t *set, char *value ) irc->channel, pm, v, list ); } - return( set_eval_bool( set, value ) ); + return value; } -- cgit v1.2.3 From 3611717156f4c9ebfdf829319840d49e59b827ce Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 16:00:35 +0100 Subject: Added auto_join code. --- protocols/nogaim.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 6a267adf..20d2f3f1 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -248,6 +248,8 @@ static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond ) void imcb_connected( struct im_connection *ic ) { + irc_t *irc = ic->irc; + struct chat *c; user_t *u; /* MSN servers sometimes redirect you to a different server and do @@ -270,6 +272,15 @@ void imcb_connected( struct im_connection *ic ) /* Apparently we're connected successfully, so reset the exponential backoff timer. */ ic->acc->auto_reconnect_delay = 0; + + for( c = irc->chatrooms; c; c = c->next ) + { + if( c->acc != ic->acc ) + continue; + + if( set_getbool( &c->set, "auto_join" ) ) + chat_join( irc, c ); + } } gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ) -- cgit v1.2.3 From 2bebe15b447b84fd5705a021f73db609c336fd73 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 01:18:21 +0100 Subject: Fixed one crash bug in Yahoo! chatroom invitation handling. --- protocols/yahoo/yahoo.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 8d9e95d8..fa36de39 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -789,9 +789,22 @@ int ext_yahoo_connect(const char *host, int port) static void byahoo_accept_conf( void *data ) { struct byahoo_conf_invitation *inv = data; + struct groupchat *b; + + for( b = inv->ic->groupchats; b; b = b->next ) + if( b == inv->c ) + break; + + if( b != NULL ) + { + yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); + imcb_chat_add_buddy( inv->c, inv->ic->acc->user ); + } + else + { + imcb_log( inv->ic, "Duplicate/corrupted invitation to `%s'.", inv->name ); + } - yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); - imcb_chat_add_buddy( inv->c, inv->ic->acc->user ); g_free( inv->name ); g_free( inv ); } -- cgit v1.2.3 From 94acdd0d7beaa659a5f6b26673c5dea5dbcc4496 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 12:18:19 +0100 Subject: Restored support for password-protected chatrooms (for now only by accepting a password in the IRC JOIN command). --- protocols/jabber/conference.c | 2 +- protocols/jabber/jabber.c | 2 +- protocols/jabber/jabber.h | 2 +- protocols/nogaim.c | 4 ++-- protocols/nogaim.h | 4 ++-- protocols/oscar/oscar.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 79fdd053..ce2c0b86 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -25,7 +25,7 @@ static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); -struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ) +struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password ) { struct jabber_chat *jc; struct xt_node *node; diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ac8638cf..b8e88c26 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -424,7 +424,7 @@ static void jabber_remove_buddy( struct im_connection *ic, char *who, char *grou presence_send_request( ic, who, "unsubscribe" ); } -static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password ) +static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password ) { if( strchr( room, '@' ) == NULL ) imcb_error( ic, "Invalid room name: %s", room ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 904bf0c4..ee453144 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -239,7 +239,7 @@ xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); gboolean sasl_supported( struct im_connection *ic ); /* conference.c */ -struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password ); struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ); void jabber_chat_free( struct groupchat *c ); int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 20d2f3f1..bec80c25 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -279,7 +279,7 @@ void imcb_connected( struct im_connection *ic ) continue; if( set_getbool( &c->set, "auto_join" ) ) - chat_join( irc, c ); + chat_join( irc, c, NULL ); } } @@ -709,7 +709,7 @@ void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ) } } -struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) +struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle ) { struct groupchat *c; diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 9fe843b5..d828de4c 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -208,7 +208,7 @@ struct prpl { * your protocol does not support publicly named group chats, then do * not implement this. */ struct groupchat * - (* chat_join) (struct im_connection *, char *room, char *nick, char *password); + (* chat_join) (struct im_connection *, const char *room, const char *nick, const char *password); /* Change the topic, if supported. Note that BitlBee expects the IM server to confirm the topic change with a regular topic change event. If it doesn't do that, you have to fake it to make it @@ -289,7 +289,7 @@ G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, * - After you have a groupchat pointer, you should add the handles, finally * the user her/himself. At that point the group chat will be visible to the * user, too. */ -G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ); +G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle ); G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); /* To remove a handle from a group chat. Reason can be NULL. */ G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 36e03166..8be04259 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2580,7 +2580,7 @@ void oscar_chat_leave(struct groupchat *c) oscar_chat_kill(c->ic, c->data); } -struct groupchat *oscar_chat_join(struct im_connection * ic, char * room, char * nick, char * password ) +struct groupchat *oscar_chat_join(struct im_connection * ic, const char * room, const char * nick, const char * password ) { struct oscar_data * od = (struct oscar_data *)ic->proto_data; aim_conn_t * cur; -- cgit v1.2.3 From b2c062d609becdffc8c8542f68e260ab7b36dbcd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 12:21:55 +0100 Subject: Adding the password to the right part of the stanza so joining password-protected rooms *really* works. --- protocols/jabber/conference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'protocols') diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index ce2c0b86..480006bd 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -35,9 +35,9 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, roomjid = g_strdup_printf( "%s/%s", room, nick ); node = xt_new_node( "x", NULL, NULL ); xt_add_attr( node, "xmlns", XMLNS_MUC ); - node = jabber_make_packet( "presence", NULL, roomjid, node ); if( password ) xt_add_child( node, xt_new_node( "password", password, NULL ) ); + node = jabber_make_packet( "presence", NULL, roomjid, node ); jabber_cache_add( ic, node, jabber_chat_join_failed ); if( !jabber_write_packet( ic, node ) ) -- cgit v1.2.3 From c0c43fba49da3d14097f2c7cf3569a829b84125a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 10:31:49 +0000 Subject: Fixed ic->away leaking memory. This var is only used by OSCAR and should maybe be killed. Also fixed some completely broken indentation in those functions. --- protocols/nogaim.c | 3 +++ protocols/nogaim.h | 2 +- protocols/oscar/oscar.c | 37 +++++++++++++++++-------------------- protocols/yahoo/yahoo.c | 13 +++++++------ 4 files changed, 28 insertions(+), 27 deletions(-) (limited to 'protocols') diff --git a/protocols/nogaim.c b/protocols/nogaim.c index bec80c25..fd445324 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -320,6 +320,9 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) ic->acc->prpl->logout( ic ); b_event_remove( ic->inpa ); + g_free( ic->away ); + ic->away = NULL; + u = irc->users; while( u ) { diff --git a/protocols/nogaim.h b/protocols/nogaim.h index d828de4c..ddfff07e 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -238,7 +238,7 @@ G_MODULE_EXPORT void register_protocol( struct prpl * ); /* You will need this function in prpl->login() to get an im_connection from * the account_t parameter. */ G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc ); -G_MODULE_EXPORT void imcb_free( struct im_connection *ic ); +G_MODULE_EXPORT void imc_free( struct im_connection *ic ); /* Once you're connected, you should call this function, so that the user will * see the success. */ G_MODULE_EXPORT void imcb_connected( struct im_connection *ic ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 8be04259..4142c046 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1938,8 +1938,7 @@ static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); - if (ic->away) - g_free(ic->away); + g_free(ic->away); ic->away = NULL; if (!message) { @@ -1959,55 +1958,53 @@ static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message) { - const char *msg = NULL; + const char *msg = NULL; gboolean no_message = FALSE; /* clean old states */ - if (ic->away) { - g_free(ic->away); - ic->away = NULL; - } + g_free(ic->away); + ic->away = NULL; od->sess->aim_icq_state = 0; /* if no message, then use an empty message */ - if (message) { - msg = message; - } else { - msg = ""; + if (message) { + msg = message; + } else { + msg = ""; no_message = TRUE; - } + } if (!g_strcasecmp(state, "Online")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else if (!g_strcasecmp(state, "Away")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY; } else if (!g_strcasecmp(state, "Do Not Disturb")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTODND; } else if (!g_strcasecmp(state, "Not Available")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTONA; } else if (!g_strcasecmp(state, "Occupied")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY; } else if (!g_strcasecmp(state, "Free For Chat")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC; } else if (!g_strcasecmp(state, "Invisible")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) { if (no_message) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY; } } @@ -2019,7 +2016,7 @@ static void oscar_set_away(struct im_connection *ic, char *state, char *message) { struct oscar_data *od = (struct oscar_data *)ic->proto_data; - oscar_set_away_aim(ic, od, state, message); + oscar_set_away_aim(ic, od, state, message); if (od->icq) oscar_set_away_icq(ic, od, state, message); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index fa36de39..3e844c55 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -196,13 +196,14 @@ static int byahoo_send_typing( struct im_connection *ic, char *who, int typing ) static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) { struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; + char *away; - ic->away = NULL; + away = NULL; if( state && msg && g_strcasecmp( state, msg ) != 0 ) { yd->current_status = YAHOO_STATUS_CUSTOM; - ic->away = ""; + away = ""; } else if( state ) { @@ -211,11 +212,11 @@ static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) away state. */ msg = NULL; - ic->away = ""; + away = ""; if( g_strcasecmp( state, "Available" ) == 0 ) { yd->current_status = YAHOO_STATUS_AVAILABLE; - ic->away = NULL; + away = NULL; } else if( g_strcasecmp( state, "Be Right Back" ) == 0 ) yd->current_status = YAHOO_STATUS_BRB; @@ -241,13 +242,13 @@ static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) { yd->current_status = YAHOO_STATUS_AVAILABLE; - ic->away = NULL; + away = NULL; } } else yd->current_status = YAHOO_STATUS_AVAILABLE; - yahoo_set_away( yd->y2_id, yd->current_status, msg, ic->away != NULL ? 2 : 0 ); + yahoo_set_away( yd->y2_id, yd->current_status, msg, away != NULL ? 2 : 0 ); } static GList *byahoo_away_states( struct im_connection *ic ) -- cgit v1.2.3 From 71d45c298e0757b5f92f0302b987e368ee75891a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 13:39:02 +0000 Subject: Dropping warnings about unknown JIDs since they're spammy (mostly show up when the user logs in from mulitple locations) and the irc->debug setting shouldn't be read from inside the IM modules. --- protocols/jabber/presence.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'protocols') diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 6fc360b7..939bc888 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -48,8 +48,9 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) { if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) { - if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); + /* + imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); + */ return XT_HANDLED; } @@ -105,8 +106,9 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) { if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) { - if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); + /* + imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); + */ return XT_HANDLED; } -- cgit v1.2.3 From 54699524eda49bb287d5998e443deefd81fce8fc Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 15:04:48 +0000 Subject: Detect disconnects caused by concurrent logins or rate limiting, and disable auto-reconnect in those cases to prevent loops. --- protocols/oscar/oscar.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'protocols') diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 4142c046..1118c26d 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -90,7 +90,7 @@ struct oscar_data { GSList *oscar_chats; - gboolean killme; + gboolean killme, no_reconnect; gboolean icq; GSList *evilhack; @@ -180,6 +180,7 @@ static struct chat_connection *find_oscar_chat_by_conn(struct im_connection *ic, static int gaim_parse_auth_resp (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_login (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_logout (aim_session_t *, aim_frame_t *, ...); static int gaim_handle_redirect (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_oncoming (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_offgoing (aim_session_t *, aim_frame_t *, ...); @@ -293,7 +294,7 @@ static gboolean oscar_callback(gpointer data, gint source, if (aim_get_command(odata->sess, conn) >= 0) { aim_rxdispatch(odata->sess); if (odata->killme) - imc_logout(ic, TRUE); + imc_logout(ic, !odata->no_reconnect); } else { if ((conn->type == AIM_CONN_TYPE_BOS) || !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) { @@ -519,6 +520,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { break; case 0x18: /* connecting too frequently */ + od->no_reconnect = TRUE; imcb_error(ic, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); break; case 0x1c: @@ -571,6 +573,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK, gaim_ssi_parseack, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_parse_logout, 0); ((struct oscar_data *)ic->proto_data)->conn = bosconn; for (i = 0; i < (int)strlen(info->bosip); i++) { @@ -750,6 +753,30 @@ static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; } +static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...) { + struct im_connection *ic = sess->aux_data; + struct oscar_data *odata = ic->proto_data; + int code; + va_list ap; + + va_start(ap, fr); + code = va_arg(ap, int); + va_end(ap); + + imcb_error( ic, "Connection aborted by server: %s", code == 1 ? + "someone else logged in with your account" : + "unknown reason" ); + + /* Tell BitlBee to disable auto_reconnect if code == 1, since that + means a concurrent login somewhere else. */ + odata->no_reconnect = code == 1; + + /* DO NOT log out here! Just tell the callback to do it. */ + odata->killme = TRUE; + + return 1; +} + static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) { struct im_connection *ic = sess->aux_data; struct chat_connection *chatcon; -- cgit v1.2.3