diff options
Diffstat (limited to 'protocols')
| -rw-r--r-- | protocols/Makefile | 2 | ||||
| -rw-r--r-- | protocols/http_client.c | 382 | ||||
| -rw-r--r-- | protocols/http_client.h | 54 | ||||
| -rw-r--r-- | protocols/jabber/Makefile | 8 | ||||
| -rw-r--r-- | protocols/msn/Makefile | 8 | ||||
| -rw-r--r-- | protocols/msn/msn.h | 2 | ||||
| -rw-r--r-- | protocols/msn/ns.c | 2 | ||||
| -rw-r--r-- | protocols/msn/passport.c | 308 | ||||
| -rw-r--r-- | protocols/msn/passport.h | 6 | ||||
| -rw-r--r-- | protocols/msn/sb.c | 26 | ||||
| -rw-r--r-- | protocols/msn/tables.c | 8 | ||||
| -rw-r--r-- | protocols/oscar/Makefile | 8 | ||||
| -rw-r--r-- | protocols/proxy.c | 2 | ||||
| -rw-r--r-- | protocols/ssl_bogus.c | 2 | ||||
| -rw-r--r-- | protocols/ssl_client.h | 5 | ||||
| -rw-r--r-- | protocols/ssl_gnutls.c | 39 | ||||
| -rw-r--r-- | protocols/ssl_nss.c | 4 | ||||
| -rw-r--r-- | protocols/ssl_openssl.c | 84 | ||||
| -rw-r--r-- | protocols/yahoo/Makefile | 8 | 
19 files changed, 703 insertions, 255 deletions
| diff --git a/protocols/Makefile b/protocols/Makefile index c5f938fd..1ed6b52e 100644 --- a/protocols/Makefile +++ b/protocols/Makefile @@ -9,7 +9,7 @@  -include ../Makefile.settings  # [SH] Program variables -objects = md5.o nogaim.o proxy.o sha.o util.o $(SSL_CLIENT) +objects = http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) util.o  # [SH] The next two lines should contain the directory name (in $(subdirs))  #      and the name of the object file, which should be linked into diff --git a/protocols/http_client.c b/protocols/http_client.c new file mode 100644 index 00000000..51424e1c --- /dev/null +++ b/protocols/http_client.c @@ -0,0 +1,382 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2005 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* HTTP(S) module                                                       */ + +/* +  This program is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published by +  the Free Software Foundation; either version 2 of the License, or +  (at your option) any later version. + +  This program is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License with +  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; +  if not, write to the Free Software Foundation, Inc., 59 Temple Place, +  Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <string.h> +#include <stdio.h> + +#include "sock.h" +#include "http_client.h" +#include "url.h" + + +static void http_connected( gpointer data, int source, GaimInputCondition cond ); +static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond ); +static void http_incoming_data( gpointer data, int source, GaimInputCondition cond ); + + +void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) +{ +	struct http_request *req; +	int error = 0; +	 +	req = g_new0( struct http_request, 1 ); +	 +	if( ssl ) +	{ +		req->ssl = ssl_connect( host, port, http_ssl_connected, req ); +		if( req->ssl == NULL ) +			error = 1; +	} +	else +	{ +		req->fd = proxy_connect( host, port, http_connected, req ); +		if( req->fd < 0 ) +			error = 1; +	} +	 +	if( error ) +	{ +		g_free( req ); +		return( NULL ); +	} +	 +	req->func = func; +	req->data = data; +	req->request = g_strdup( request ); +	req->request_length = strlen( request ); +	 +	return( req ); +} + +/* This one is actually pretty simple... Might get more calls if we can't write  +   the whole request at once. */ +static void http_connected( gpointer data, int source, GaimInputCondition cond ) +{ +	struct http_request *req = data; +	int st; +	 +	if( source < 0 ) +		goto error; +	 +	if( req->inpa > 0 ) +		gaim_input_remove( req->inpa ); +	 +	sock_make_nonblocking( req->fd ); +	 +	if( req->ssl ) +	{ +		st = ssl_write( req->ssl, req->request + req->bytes_written, +		                req->request_length - req->bytes_written ); +		if( st < 0 ) +		{ +			if( ssl_errno != SSL_AGAIN ) +			{ +				ssl_disconnect( req->ssl ); +				goto error; +			} +		} +	} +	else +	{ +		st = write( source, req->request + req->bytes_written, +		                    req->request_length - req->bytes_written ); +		if( st < 0 ) +		{ +			if( !sockerr_again() ) +			{ +				closesocket( req->fd ); +				goto error; +			} +		} +	} +	 +	if( st > 0 ) +		req->bytes_written += st; +	 +	if( req->bytes_written < req->request_length ) +		req->inpa = gaim_input_add( source, +		                            req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, +	        	                    http_connected, req ); +	else +		req->inpa = gaim_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); +	 +	return; +	 +error: +	req->func( req ); +	 +	g_free( req->request ); +	g_free( req ); +	 +	return; +} + +static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond ) +{ +	struct http_request *req = data; +	 +	if( source == NULL ) +		return http_connected( data, -1, cond ); +	 +	req->fd = ssl_getfd( source ); +	 +	return http_connected( data, req->fd, cond ); +} + +static void http_incoming_data( gpointer data, int source, GaimInputCondition cond ) +{ +	struct http_request *req = data; +	int evil_server = 0; +	char buffer[2048]; +	char *end1, *end2; +	int st; +	 +	if( req->inpa > 0 ) +		gaim_input_remove( req->inpa ); +	 +	if( req->ssl ) +	{ +		st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); +		if( st < 0 ) +		{ +			if( ssl_errno != SSL_AGAIN ) +			{ +				/* goto cleanup; */ +				 +				/* YAY! We have to deal with crappy Microsoft +				   servers that LOVE to send invalid TLS +				   packets that abort connections! \o/ */ +				 +				goto got_reply; +			} +		} +		else if( st == 0 ) +		{ +			goto got_reply; +		} +	} +	else +	{ +		st = read( req->fd, buffer, sizeof( buffer ) ); +		if( st < 0 ) +		{ +			if( !sockerr_again() ) +			{ +				goto cleanup; +			} +		} +		else if( st == 0 ) +		{ +			goto got_reply; +		} +	} +	 +	if( st > 0 ) +	{ +		req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); +		memcpy( req->reply_headers + req->bytes_read, buffer, st ); +		req->bytes_read += st; +	} +	 +	/* There will be more! */ +	req->inpa = gaim_input_add( req->fd, +	                            req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, +	                            http_incoming_data, req ); +	 +	return; + +got_reply: +	/* Zero termination is very convenient. */ +	req->reply_headers[req->bytes_read] = 0; +	 +	/* Find the separation between headers and body, and keep stupid +	   webservers in mind. */ +	end1 = strstr( req->reply_headers, "\r\n\r\n" ); +	end2 = strstr( req->reply_headers, "\n\n" ); +	 +	if( end2 && end2 < end1 ) +	{ +		end1 = end2 + 1; +		evil_server = 1; +	} +	else +	{ +		end1 += 2; +	} +	 +	if( end1 ) +	{ +		*end1 = 0; +		 +		if( evil_server ) +			req->reply_body = end1 + 1; +		else +			req->reply_body = end1 + 2; +	} +	 +	if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) +	{ +		if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) +			req->status_code = -1; +	} +	else +	{ +		req->status_code = -1; +	} +	 +	if( req->status_code == 301 || req->status_code == 302 ) +	{ +		char *loc, *new_request, *new_host; +		int error = 0, new_port, new_proto; +		 +		loc = strstr( req->reply_headers, "\nLocation: " ); +		if( loc == NULL ) /* We can't handle this redirect... */ +			goto cleanup; +		 +		loc += 11; +		while( *loc == ' ' ) +			loc ++; +		 +		/* TODO/FIXME: Possibly have to handle relative redirections, +		   and rewrite Host: headers. Not necessary for now, it's +		   enough for passport authentication like this. */ +		 +		if( *loc == '/' ) +		{ +			/* Just a different pathname... */ +			 +			/* Since we don't cache the servername, and since we +			   don't need this yet anyway, I won't implement it. */ +			 +			goto cleanup; +		} +		else +		{ +			/* A whole URL */ +			url_t *url; +			char *s; +			 +			s = strstr( loc, "\r\n" ); +			if( s == NULL ) +				goto cleanup; +			 +			url = g_new0( url_t, 1 ); +			*s = 0; +			 +			if( !url_set( url, loc ) ) +			{ +				g_free( url ); +				goto cleanup; +			} +			 +			/* Okay, this isn't fun! We have to rebuild the request... :-( */ +			new_request = g_malloc( req->request_length + strlen( url->file ) ); +			 +			/* So, now I just allocated enough memory, so I'm +			   going to use strcat(), whether you like it or not. :-) */ +			 +			/* First, find the GET/POST/whatever from the original request. */ +			s = strchr( req->request, ' ' ); +			if( s == NULL ) +			{ +				g_free( new_request ); +				g_free( url ); +				goto cleanup; +			} +			 +			*s = 0; +			sprintf( new_request, "%s %s HTTP/1.0\r\n", req->request, url->file ); +			*s = ' '; +			 +			s = strstr( req->request, "\r\n" ); +			if( s == NULL ) +			{ +				g_free( new_request ); +				g_free( url ); +				goto cleanup; +			} +			 +			strcat( new_request, s + 2 ); +			new_host = g_strdup( url->host ); +			new_port = url->port; +			new_proto = url->proto; +			 +			g_free( url ); +		} +		 +		if( req->ssl ) +			ssl_disconnect( req->ssl ); +		else +			closesocket( req->fd ); +		 +		req->fd = -1; +		req->ssl = 0; +		 +		if( new_proto == PROTO_HTTPS ) +		{ +			req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req ); +			if( req->ssl == NULL ) +				error = 1; +		} +		else +		{ +			req->fd = proxy_connect( new_host, new_port, http_connected, req ); +			if( req->fd < 0 ) +				error = 1; +		} +		g_free( new_host ); +		 +		if( error ) +		{ +			g_free( new_request ); +			goto cleanup; +		} +		 +		g_free( req->request ); +		g_free( req->reply_headers ); +		req->request = new_request; +		req->request_length = strlen( new_request ); +		req->bytes_read = req->bytes_written = req->inpa = 0; +		req->reply_headers = req->reply_body = NULL; +		 +		return; +	} +	 +	/* Assume that a closed connection means we're finished, this indeed +	   breaks with keep-alive connections and faulty connections. */ +	req->finished = 1; + +cleanup: +	if( req->ssl ) +		ssl_disconnect( req->ssl ); +	else +		closesocket( req->fd ); +	 +	req->func( req ); +	 +	g_free( req->request ); +	g_free( req->reply_headers ); +	g_free( req ); +} diff --git a/protocols/http_client.h b/protocols/http_client.h new file mode 100644 index 00000000..53c6fcd6 --- /dev/null +++ b/protocols/http_client.h @@ -0,0 +1,54 @@ +  /********************************************************************\ +  * BitlBee -- An IRC to other IM-networks gateway                     * +  *                                                                    * +  * Copyright 2002-2005 Wilmer van der Gaast and others                * +  \********************************************************************/ + +/* HTTP(S) module                                                       */ + +/* +  This program is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as published by +  the Free Software Foundation; either version 2 of the License, or +  (at your option) any later version. + +  This program is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License with +  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; +  if not, write to the Free Software Foundation, Inc., 59 Temple Place, +  Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <glib.h> + +#include "ssl_client.h" + +struct http_request; + +typedef void (*http_input_function)( struct http_request * ); + +struct http_request +{ +	char *request; +	int request_length; +	int status_code; +	char *reply_headers; +	char *reply_body; +	int finished; +	 +	void *ssl; +	int fd; +	 +	int inpa; +	int bytes_written; +	int bytes_read; +	 +	http_input_function func; +	gpointer data; +}; + +void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index df326fe6..9b414dc8 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -15,7 +15,7 @@ CFLAGS += -Wall  LFLAGS += -r  # [SH] Phony targets -all: jabberr.o +all: jabber_mod.o  .PHONY: all clean distclean @@ -32,6 +32,6 @@ $(objects): %.o: %.c  	@echo '*' Compiling $<  	@$(CC) -c $(CFLAGS) $< -o $@ -jabberr.o: $(objects) -	@echo '*' Linking jabberr.o -	@$(LD) $(LFLAGS) $(objects) -o jabberr.o +jabber_mod.o: $(objects) +	@echo '*' Linking jabber_mod.o +	@$(LD) $(LFLAGS) $(objects) -o jabber_mod.o diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index e6620323..873c831c 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -15,7 +15,7 @@ CFLAGS += -Wall  LFLAGS += -r  # [SH] Phony targets -all: msnn.o +all: msn_mod.o  .PHONY: all clean distclean @@ -32,8 +32,8 @@ $(objects): %.o: %.c  	@echo '*' Compiling $<  	@$(CC) -c $(CFLAGS) $< -o $@ -msnn.o: $(objects) -	@echo '*' Linking msnn.o -	@$(LD) $(LFLAGS) $(objects) -o msnn.o +msn_mod.o: $(objects) +	@echo '*' Linking msn_mod.o +	@$(LD) $(LFLAGS) $(objects) -o msn_mod.o diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 61231d8a..c8c7a788 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -126,6 +126,8 @@ struct msn_handler_data  /* Bitfield values for msn_status_code.flags */  #define STATUS_FATAL            1  #define STATUS_SB_FATAL         2 +#define STATUS_SB_IM_SPARE	4	/* Make one-to-one conversation switchboard available again, invite failed. */ +#define STATUS_SB_CHAT_SPARE	8	/* Same, but also for groupchats (not used yet). */  int msn_chat_id;  extern struct msn_away_state msn_away_state_list[]; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index f1bda1a4..2d90b2f3 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -207,7 +207,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( gc, gc->username, gc->password, cmd[4], msn_auth_got_passport_id ) ) +			if( !passport_get_id( msn_auth_got_passport_id, gc, gc->username, gc->password, cmd[4] ) )  			{  				hide_login_progress_error( gc, "Error while contacting Passport server" );  				signoff( gc ); diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 640126a0..34703432 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -19,7 +19,7 @@   *   */ -#include "ssl_client.h" +#include "http_client.h"  #include "passport.h"  #include "msn.h"  #include "bitlbee.h" @@ -30,34 +30,91 @@  static char *prd_cached = NULL; -static char *passport_create_header( char *reply, char *email, char *pwd ); +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_connected( gpointer data, void *ssl, GaimInputCondition cond ); -static int passport_get_id_from( gpointer data, gpointer func, char *header_i, char *url ); -static void passport_get_id_connected( gpointer data, void *ssl, GaimInputCondition cond ); -static void destroy_reply( struct passport_reply *rep ); +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 data, char *username, char *password, char *cookie, gpointer func ) +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 ) -	{ -		int st; -		 -		st = passport_get_id_from( data, func, header, prd_cached ); -		g_free( header ); -		return( st ); -	} +	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 ) +{ +	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; +	 +	server = g_strdup( prd_cached ); +	dummy = strchr( server, '/' ); +	 +	if( dummy == NULL )  	{ -		return( passport_retrieve_dalogin( data, func, header ) ); +		destroy_reply( rep ); +		return( 0 );  	} +	 +	reqs = g_malloc( strlen( header ) + strlen( dummy ) + 128 ); +	sprintf( reqs, "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); +	 +	*dummy = 0; +	req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); +	 +	g_free( server ); +	g_free( reqs ); +	 +	if( req == NULL ) +		destroy_reply( rep ); +	 +	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 ) || !req->finished || !req->reply_headers ) +	{ +		destroy_reply( rep ); +		return; +	} +	 +	if( 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 ); +		} +	} +	 +	rep->func( rep ); +	destroy_reply( rep ); +} -static char *passport_create_header( char *reply, char *email, char *pwd ) +static char *passport_create_header( char *cookie, char *email, char *pwd )  {  	char *buffer = g_new0( char, 2048 );  	char *currenttoken; @@ -71,7 +128,7 @@ static char *passport_create_header( char *reply, char *email, char *pwd )  	strcpy( pwd_enc, pwd );  	http_encode( pwd_enc ); -	currenttoken = strstr( reply, "lc=" ); +	currenttoken = strstr( cookie, "lc=" );  	if( currenttoken == NULL )  		return( NULL ); @@ -87,227 +144,68 @@ static char *passport_create_header( char *reply, char *email, char *pwd )  	return( buffer );  } - -static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ) +#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n" +static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header )  {  	struct passport_reply *rep = g_new0( struct passport_reply, 1 ); -	void *ssl; +	struct http_request *req;  	rep->data = data;  	rep->func = func;  	rep->header = header; -	ssl = ssl_connect( "nexus.passport.com", 443, passport_retrieve_dalogin_connected, rep ); +	req = http_dorequest( "nexus.passport.com", 443, 1, PPR_REQUEST, passport_retrieve_dalogin_ready, rep ); -	if( !ssl ) +	if( !req )  		destroy_reply( rep ); -	return( ssl != NULL ); +	return( req != NULL );  } -#define PPR_BUFFERSIZE 2048 -#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n" -static void passport_retrieve_dalogin_connected( gpointer data, void *ssl, GaimInputCondition cond ) +static void passport_retrieve_dalogin_ready( struct http_request *req )  { -	int ret; -	char buffer[PPR_BUFFERSIZE+1]; -	struct passport_reply *rep = data; +	struct passport_reply *rep = req->data; +	char *dalogin; +	char *urlend; -	if( !g_slist_find( msn_connections, rep->data ) ) +	if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers )  	{ -		if( ssl ) ssl_disconnect( ssl );  		destroy_reply( rep );  		return;  	} -	if( !ssl ) -	{ -		rep->func( rep ); -		destroy_reply( rep ); -		return; -	} -	 -	ssl_write( ssl, PPR_REQUEST, strlen( PPR_REQUEST ) ); +	dalogin = strstr( req->reply_headers, "DALogin=" );	 -	if( ( ret = ssl_read( ssl, buffer, PPR_BUFFERSIZE ) ) <= 0 ) -	{ +	if( !dalogin )  		goto failure; -	} - -	{ -		char *dalogin = strstr( buffer, "DALogin=" ); -		char *urlend; -		 -		if( !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_from( rep->data, rep->func, rep->header, prd_cached ) ) -	{ -		ssl_disconnect( ssl ); -		destroy_reply( rep ); -		return; -	} -failure:	 -	ssl_disconnect( ssl ); -	rep->func( rep ); -	destroy_reply( rep ); -} - - -static int passport_get_id_from( gpointer data, gpointer func, char *header_i, char *url ) -{ -	struct passport_reply *rep = g_new0( struct passport_reply, 1 ); -	char server[512], *dummy; -	void *ssl; -	 -	rep->data = data; -	rep->func = func; -	rep->redirects = 4; -	 -	strncpy( server, url, 512 ); -	dummy = strchr( server, '/' ); -	if( dummy ) -		*dummy = 0; -	 -	ssl = ssl_connect( server, 443, passport_get_id_connected, rep ); -	 -	if( ssl ) -	{ -		rep->header = g_strdup( header_i ); -		rep->url = g_strdup( url ); -	} -	else -	{ -		destroy_reply( rep ); -	} +	dalogin += strlen( "DALogin=" ); +	urlend = strchr( dalogin, ',' ); +	if( urlend ) +		*urlend = 0; -	return( ssl != NULL ); -} - -#define PPG_BUFFERSIZE 4096 -static void passport_get_id_connected( gpointer data, void *ssl, GaimInputCondition cond ) -{ -	struct passport_reply *rep = data; -	char server[512], buffer[PPG_BUFFERSIZE+1], *dummy; -	int ret; +	/* strip the http(s):// part from the url */ +	urlend = strstr( urlend, "://" ); +	if( urlend ) +		dalogin = urlend + strlen( "://" ); -	if( !g_slist_find( msn_connections, rep->data ) ) -	{ -		if( ssl ) ssl_disconnect( ssl ); -		destroy_reply( rep ); -		return; -	} +	if( prd_cached == NULL ) +		prd_cached = g_strdup( dalogin ); -	if( !ssl ) +	if( passport_get_id_real( rep->func, rep->data, rep->header ) )  	{ -		rep->func( rep );  		destroy_reply( rep );  		return;  	} -	memset( buffer, 0, PPG_BUFFERSIZE + 1 ); -	 -	strncpy( server, rep->url, 512 ); -	dummy = strchr( server, '/' ); -	if( dummy == NULL ) -		goto end; -	 -	g_snprintf( buffer, PPG_BUFFERSIZE - 1, "GET %s HTTP/1.0\r\n" -	            "%s\r\n\r\n", dummy, rep->header ); -	 -	ssl_write( ssl, buffer, strlen( buffer ) ); -	memset( buffer, 0, PPG_BUFFERSIZE + 1 ); -	 -	{ -		char *buffer2 = buffer; -		 -		while( ( ( ret = ssl_read( ssl, buffer2, 512 ) ) > 0 ) && -		       ( buffer + PPG_BUFFERSIZE - buffer2 - ret - 512 >= 0 ) ) -		{ -			buffer2 += ret; -		} -	} -	 -	if( *buffer == 0 ) -		goto end; -	 -	if( ( dummy = strstr( buffer, "Location:" ) ) ) -	{ -		char *urlend; -		 -		rep->redirects --; -		if( rep->redirects == 0 ) -			goto end; -		 -		dummy += strlen( "Location:" ); -		while( isspace( *dummy ) ) dummy ++; -		urlend = dummy; -		while( !isspace( *urlend ) ) urlend ++; -		*urlend = 0; -		if( ( urlend = strstr( dummy, "://" ) ) ) -			dummy = urlend + strlen( "://" ); -		 -		g_free( rep->url ); -		rep->url = g_strdup( dummy ); -		 -		strncpy( server, dummy, sizeof( server ) - 1 ); -		dummy = strchr( server, '/' ); -		if( dummy ) *dummy = 0; -		 -		ssl_disconnect( ssl ); -		 -		if( ssl_connect( server, 443, passport_get_id_connected, rep ) ) -		{ -			return; -		} -		else -		{ -			rep->func( rep ); -			destroy_reply( rep ); -			return; -		} -	} -	else if( strstr( buffer, "200 OK" ) ) -	{ -		if( ( dummy = strstr( buffer, "from-PP='" ) ) ) -		{ -			char *responseend; -			 -			dummy += strlen( "from-PP='" ); -			responseend = strchr( dummy, '\'' ); -			if( responseend ) -				*responseend = 0; -			 -			rep->result = g_strdup( dummy ); -		} -	} -	 -end: -	ssl_disconnect( ssl ); +failure:	  	rep->func( rep );  	destroy_reply( rep );  } -  static void destroy_reply( struct passport_reply *rep )  { -	if( rep->result ) g_free( rep->result ); -	if( rep->url ) g_free( rep->url ); -	if( rep->header ) g_free( rep->header ); -	if( rep ) g_free( rep ); +	g_free( rep->result ); +	g_free( rep->header ); +	g_free( rep );  } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 63fef2e9..f7e6ebb6 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -34,14 +34,12 @@  struct passport_reply  { +	void (*func)( struct passport_reply * );  	void *data;  	char *result; -	void (*func)( struct passport_reply * ); -	char *url;  	char *header; -	int redirects;  }; -int passport_get_id( gpointer data, char *username, char *password, char *cookie, gpointer func ); +int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie );  #endif /* __PASSPORT_H__ */ diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 2f4d05d5..11728f03 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -521,11 +521,35 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )  			msn_sb_destroy( sb );  			return( 0 );  		} -		else if( err->flags & STATUS_FATAL ) +		if( err->flags & STATUS_FATAL )  		{  			signoff( gc );  			return( 0 );  		} +		if( err->flags & STATUS_SB_IM_SPARE ) +		{ +			if( sb->who ) +			{ +				struct msn_message *m; +				GSList *l; +				 +				/* Apparently some invitation failed. We might want to use this +				   board later, so keep it as a spare. */ +				g_free( sb->who ); +				sb->who = NULL; +				 +				/* Also clear the msgq, otherwise someone else might get them. */ +				for( l = sb->msgq; l; l = l->next ) +				{ +					m = l->data; +					g_free( m->who ); +					g_free( m->text ); +					g_free( m ); +				} +				g_slist_free( sb->msgq ); +				sb->msgq = NULL; +			} +		}  	}  	else  	{ diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c index 0cd80c01..2741048a 100644 --- a/protocols/msn/tables.c +++ b/protocols/msn/tables.c @@ -79,12 +79,12 @@ struct msn_status_code msn_status_code_list[] =  	{ 205, "Invalid (non-existent) handle",                         0 },  	{ 206, "Domain name missing",                                   0 },  	{ 207, "Already logged in",                                     0 }, -	{ 208, "Invalid handle",                                        0 }, +	{ 208, "Invalid handle",                                        STATUS_SB_IM_SPARE },  	{ 209, "Forbidden nickname",                                    0 },  	{ 210, "Buddy list too long",                                   0 },  	{ 215, "Handle is already in list",                             0 }, -	{ 216, "Handle is not in list",                                 0 }, -	{ 217, "Person is off-line or non-existent",                    0 }, +	{ 216, "Handle is not in list",                                 STATUS_SB_IM_SPARE }, +	{ 217, "Person is off-line or non-existent",                    STATUS_SB_IM_SPARE },  	{ 218, "Already in that mode",                                  0 },  	{ 219, "Handle is already in opposite list",                    0 },  	{ 223, "Too many groups",                                       0 }, @@ -117,7 +117,7 @@ struct msn_status_code msn_status_code_list[] =  	{ 710, "Invalid CVR parameters",                                STATUS_FATAL },  	{ 711, "Write is blocking",                                     STATUS_FATAL },  	{ 712, "Session is overloaded",                                 STATUS_FATAL }, -	{ 713, "Calling too rapidly",                                   0 }, +	{ 713, "Calling too rapidly",                                   STATUS_SB_IM_SPARE },  	{ 714, "Too many sessions",                                     STATUS_FATAL },  	{ 715, "Not expected/Invalid argument/action",                  0 },  	{ 717, "Bad friend file",                                       STATUS_FATAL }, diff --git a/protocols/oscar/Makefile b/protocols/oscar/Makefile index 5ef996a1..97a27299 100644 --- a/protocols/oscar/Makefile +++ b/protocols/oscar/Makefile @@ -15,7 +15,7 @@ CFLAGS += -Wall  LFLAGS += -r  # [SH] Phony targets -all: oscarr.o +all: oscar_mod.o  .PHONY: all clean distclean @@ -32,6 +32,6 @@ $(objects): %.o: %.c  	@echo '*' Compiling $<  	@$(CC) -c $(CFLAGS) $< -o $@ -oscarr.o: $(objects) -	@echo '*' Linking oscarr.o -	@$(LD) $(LFLAGS) $(objects) -o oscarr.o +oscar_mod.o: $(objects) +	@echo '*' Linking oscar_mod.o +	@$(LD) $(LFLAGS) $(objects) -o oscar_mod.o diff --git a/protocols/proxy.c b/protocols/proxy.c index c658a163..1ca35dfe 100644 --- a/protocols/proxy.c +++ b/protocols/proxy.c @@ -105,8 +105,6 @@ static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpoin  		gaim_cond |= GAIM_INPUT_READ;  	if (condition & GAIM_WRITE_COND)  		gaim_cond |= GAIM_INPUT_WRITE; -//	if (condition & GAIM_ERR_COND) -//		fprintf( stderr, "ERROR! fd=%d\n", g_io_channel_unix_get_fd( source ) );  	closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c index 1ee0df4c..3766baaa 100644 --- a/protocols/ssl_bogus.c +++ b/protocols/ssl_bogus.c @@ -27,7 +27,7 @@  int ssl_errno; -void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )  {  	return( NULL );  } diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h index 719cd0c4..89189db9 100644 --- a/protocols/ssl_client.h +++ b/protocols/ssl_client.h @@ -32,10 +32,11 @@  extern int ssl_errno; -typedef void (*SslInputFunction)(gpointer, void*, GaimInputCondition); +typedef void (*ssl_input_function)(gpointer, void*, GaimInputCondition); -G_MODULE_EXPORT void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ); +G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data );  G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len );  G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len );  G_MODULE_EXPORT void ssl_disconnect( void *conn_ );  G_MODULE_EXPORT int ssl_getfd( void *conn ); +G_MODULE_EXPORT GaimInputCondition ssl_getdirection( void *conn ); diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c index c2eb6906..f2cb3e08 100644 --- a/protocols/ssl_gnutls.c +++ b/protocols/ssl_gnutls.c @@ -37,7 +37,7 @@ static gboolean initialized = FALSE;  struct scd  { -	SslInputFunction func; +	ssl_input_function func;  	gpointer data;  	int fd;  	gboolean established; @@ -50,7 +50,7 @@ struct scd  static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); -void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )  {  	struct scd *conn = g_new0( struct scd, 1 ); @@ -110,15 +110,16 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )  	int st;  	if( conn->inpa != -1 ) +	{  		gaim_input_remove( conn->inpa ); +		conn->inpa = -1; +	}  	if( ( st = gnutls_handshake( conn->session ) ) < 0 )  	{  		if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )  		{ -			conn->inpa = gaim_input_add( conn->fd, -			                             gnutls_record_get_direction( conn->session ) ? -			                                 GAIM_INPUT_WRITE : GAIM_INPUT_READ, +			conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ),  			                             ssl_handshake, data );  		}  		else @@ -144,31 +145,49 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )  int ssl_read( void *conn, char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established )  	{  		ssl_errno = SSL_NOHANDSHAKE;  		return( -1 );  	} -	return( gnutls_record_recv( ((struct scd*)conn)->session, buf, len ) ); +	st = gnutls_record_recv( ((struct scd*)conn)->session, buf, len ); +	ssl_errno = SSL_OK; +	if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) +		ssl_errno = SSL_AGAIN; +	 +	return st;  }  int ssl_write( void *conn, const char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established )  	{  		ssl_errno = SSL_NOHANDSHAKE;  		return( -1 );  	} -	return( gnutls_record_send( ((struct scd*)conn)->session, buf, len ) ); +	st = gnutls_record_send( ((struct scd*)conn)->session, buf, len ); +	 +	ssl_errno = SSL_OK; +	if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) +		ssl_errno = SSL_AGAIN; +	 +	return st;  }  void ssl_disconnect( void *conn_ )  {  	struct scd *conn = conn_; +	if( conn->inpa != -1 ) +		gaim_input_remove( conn->inpa ); +	  	if( conn->established )  		gnutls_bye( conn->session, GNUTLS_SHUT_WR ); @@ -183,3 +202,9 @@ int ssl_getfd( void *conn )  {  	return( ((struct scd*)conn)->fd );  } + +GaimInputCondition ssl_getdirection( void *conn ) +{ +	return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? +	        GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c index d28983fc..dfd32622 100644 --- a/protocols/ssl_nss.c +++ b/protocols/ssl_nss.c @@ -44,7 +44,7 @@ static gboolean initialized = FALSE;  struct scd  { -	SslInputFunction func; +	ssl_input_function func;  	gpointer data;  	int fd;  	PRFileDesc *prfd; @@ -90,7 +90,7 @@ static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket)  } -void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )  {  	struct scd *conn = g_new0( struct scd, 1 ); diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c index bf87ab73..ae55f3f9 100644 --- a/protocols/ssl_openssl.c +++ b/protocols/ssl_openssl.c @@ -40,11 +40,13 @@ static gboolean initialized = FALSE;  struct scd  { -	SslInputFunction func; +	ssl_input_function func;  	gpointer data;  	int fd;  	gboolean established; +	int inpa; +	int lasterr;		/* Necessary for SSL_get_error */  	SSL *ssl;  	SSL_CTX *ssl_ctx;  }; @@ -53,7 +55,7 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) -void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )  {  	struct scd *conn = g_new0( struct scd, 1 );  	SSL_METHOD *meth; @@ -92,19 +94,45 @@ void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )  	return( conn );  } +static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ); +  static void ssl_connected( gpointer data, gint source, GaimInputCondition cond )  {  	struct scd *conn = data;  	if( source == -1 ) -		goto ssl_connected_failure; +		return ssl_handshake( data, -1, cond ); +	/* Make it non-blocking at least during the handshake... */ +	sock_make_nonblocking( conn->fd );  	SSL_set_fd( conn->ssl, conn->fd ); -	if( SSL_connect( conn->ssl ) < 0 ) -		goto ssl_connected_failure; +	return ssl_handshake( data, source, cond ); +}	 + +static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) +{ +	struct scd *conn = data; +	int st; +	 +	if( conn->inpa != -1 ) +	{ +		gaim_input_remove( conn->inpa ); +		conn->inpa = -1; +	} +	 +	if( ( st = SSL_connect( conn->ssl ) ) < 0 ) +	{ +		conn->lasterr = SSL_get_error( conn->ssl, st ); +		if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) +			goto ssl_connected_failure; +		 +		conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); +		return; +	}  	conn->established = TRUE; +	sock_make_blocking( conn->fd );		/* For now... */  	conn->func( conn->data, conn, cond );  	return; @@ -126,24 +154,57 @@ ssl_connected_failure:  int ssl_read( void *conn, char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established ) -		return( 0 ); +	{ +		ssl_errno = SSL_NOHANDSHAKE; +		return -1; +	} +	 +	st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); -	return( SSL_read( ((struct scd*)conn)->ssl, buf, len ) ); +	ssl_errno = SSL_OK; +	if( st <= 0 ) +	{ +		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); +		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) +			ssl_errno = SSL_AGAIN; +	} +	 +	return st;  }  int ssl_write( void *conn, const char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established ) -		return( 0 ); +	{ +		ssl_errno = SSL_NOHANDSHAKE; +		return -1; +	} +	 +	st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); -	return( SSL_write( ((struct scd*)conn)->ssl, buf, len ) ); +	ssl_errno = SSL_OK; +	if( st <= 0 ) +	{ +		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); +		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) +			ssl_errno = SSL_AGAIN; +	} +	 +	return st;  }  void ssl_disconnect( void *conn_ )  {  	struct scd *conn = conn_; +	if( conn->inpa != -1 ) +		gaim_input_remove( conn->inpa ); +	  	if( conn->established )  		SSL_shutdown( conn->ssl ); @@ -158,3 +219,8 @@ int ssl_getfd( void *conn )  {  	return( ((struct scd*)conn)->fd );  } + +GaimInputCondition ssl_getdirection( void *conn ) +{ +	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} diff --git a/protocols/yahoo/Makefile b/protocols/yahoo/Makefile index 39a655a3..e594cc1f 100644 --- a/protocols/yahoo/Makefile +++ b/protocols/yahoo/Makefile @@ -15,7 +15,7 @@ CFLAGS += -Wall -DSTDC_HEADERS -DHAVE_STRING_H -DHAVE_STRCHR -DHAVE_MEMCPY -DHAV  LFLAGS += -r  # [SH] Phony targets -all: yahooo.o +all: yahoo_mod.o  .PHONY: all clean distclean @@ -32,6 +32,6 @@ $(objects): %.o: %.c  	@echo '*' Compiling $<  	@$(CC) -c $(CFLAGS) $< -o $@ -yahooo.o: $(objects) -	@echo '*' Linking yahooo.o -	@$(LD) $(LFLAGS) $(objects) -o yahooo.o +yahoo_mod.o: $(objects) +	@echo '*' Linking yahoo_mod.o +	@$(LD) $(LFLAGS) $(objects) -o yahoo_mod.o | 
