diff options
| author | Wilmer van der Gaast <wilmer@gaast.net> | 2005-12-17 21:56:50 +0100 | 
|---|---|---|
| committer | Wilmer van der Gaast <wilmer@gaast.net> | 2005-12-17 21:56:50 +0100 | 
| commit | 7c0a4975a538ab75405e64919bbdfee51b898b2e (patch) | |
| tree | 47d211522bbed3fda3b33b0233e91e3cf5cb9e23 | |
| parent | b5a22e33a1aa2500093e783e79de2f44bf53c150 (diff) | |
| parent | ad8b8a367c8e5dd2816096959682e2187df07c6c (diff) | |
Moved HTTP-stuff (right now only for passport) into a separate module. This
all works 100% asynchronous and non-blocking, so almost all I/O in BitlBee
should be completely non-blocking now!
Right now support for other modules than GnuTLS is probably broken, I'll fix
it later.
| -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/msn/ns.c | 2 | ||||
| -rw-r--r-- | protocols/msn/passport.c | 306 | ||||
| -rw-r--r-- | protocols/msn/passport.h | 6 | ||||
| -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 | 33 | ||||
| -rw-r--r-- | protocols/ssl_nss.c | 4 | ||||
| -rw-r--r-- | protocols/ssl_openssl.c | 4 | ||||
| -rw-r--r-- | sock.h | 3 | ||||
| -rw-r--r-- | url.c | 48 | ||||
| -rw-r--r-- | url.h | 3 | 
15 files changed, 592 insertions, 264 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/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..e04d14cb 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 ) ) +	{ +		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( 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/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..2e307aab 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 ); @@ -116,9 +116,7 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )  	{  		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,25 +142,40 @@ 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_ ) @@ -183,3 +196,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..5a107fc5 100644 --- a/protocols/ssl_openssl.c +++ b/protocols/ssl_openssl.c @@ -40,7 +40,7 @@ static gboolean initialized = FALSE;  struct scd  { -	SslInputFunction func; +	ssl_input_function func;  	gpointer data;  	int fd;  	gboolean established; @@ -53,7 +53,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; @@ -1,3 +1,6 @@ +#include <errno.h> +#include <fcntl.h> +  #ifndef _WIN32  #include <unistd.h>  #include <sys/socket.h> @@ -1,7 +1,7 @@    /********************************************************************\    * BitlBee -- An IRC to other IM-networks gateway                     *    *                                                                    * -  * Copyright 2001-2004 Wilmer van der Gaast and others                * +  * Copyright 2001-2005 Wilmer van der Gaast and others                *    \********************************************************************/  /* URL/mirror stuff - Stolen from Axel                                  */ @@ -29,7 +29,7 @@  int url_set( url_t *url, char *set_url )  {  	char s[MAX_STRING]; -	char *i, *j; +	char *i;  	/* protocol://							*/  	if( ( i = strstr( set_url, "://" ) ) == NULL ) @@ -39,7 +39,9 @@ int url_set( url_t *url, char *set_url )  	}  	else  	{ -		if( g_strncasecmp( set_url, "http", i - set_url ) == 0 ) +		if( g_strncasecmp( set_url, "https", i - set_url ) == 0 ) +			url->proto = PROTO_HTTPS; +		else if( g_strncasecmp( set_url, "http", i - set_url ) == 0 )  			url->proto = PROTO_HTTP;  		else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 )  			url->proto = PROTO_SOCKS4; @@ -55,33 +57,14 @@ int url_set( url_t *url, char *set_url )  	/* Split							*/  	if( ( i = strchr( s, '/' ) ) == NULL )  	{ -		strcpy( url->dir, "/" ); +		strcpy( url->file, "/" );  	}  	else  	{ +		strncpy( url->file, i, MAX_STRING );  		*i = 0; -		g_snprintf( url->dir, MAX_STRING, "/%s", i + 1 ); -		if( url->proto == PROTO_HTTP ) -			http_encode( url->dir );  	}  	strncpy( url->host, s, MAX_STRING ); -	j = strchr( url->dir, '?' ); -	if( j != NULL ) -		*j = 0; -	i = strrchr( url->dir, '/' ); -	*i = 0; -	if( j != NULL ) -		*j = '?'; -	if( i == NULL ) -	{ -		strcpy( url->file, url->dir ); -		strcpy( url->dir, "/" ); -	} -	else -	{ -		strcpy( url->file, i + 1 ); -		strcat( url->dir, "/" ); -	}  	/* Check for username in host field				*/  	if( strrchr( url->host, '@' ) != NULL ) @@ -95,15 +78,7 @@ int url_set( url_t *url, char *set_url )  	/* If not: Fill in defaults					*/  	else  	{ -		if( url->proto == PROTO_FTP ) -		{ -			strcpy( url->user, "anonymous" ); -			strcpy( url->pass, "-p.artmaps@lintux.cx" ); -		} -		else -		{ -			*url->user = *url->pass = 0; -		} +		*url->user = *url->pass = 0;  	}  	/* Password?							*/ @@ -116,13 +91,14 @@ int url_set( url_t *url, char *set_url )  	if( ( i = strchr( url->host, ':' ) ) != NULL )  	{  		*i = 0; -		sscanf( i + 1, "%i", &url->port ); +		sscanf( i + 1, "%d", &url->port );  	} -	/* Take default port numbers from /etc/services			*/  	else  	{  		if( url->proto == PROTO_HTTP ) -			url->port = 8080; +			url->port = 80; +		else if( url->proto == PROTO_HTTPS ) +			url->port = 443;  		else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS4 )  			url->port = 1080;  	} @@ -25,8 +25,8 @@  #include "bitlbee.h" -#define PROTO_FTP		1  #define PROTO_HTTP		2 +#define PROTO_HTTPS		5  #define PROTO_SOCKS4	3  #define PROTO_SOCKS5	4  #define PROTO_DEFAULT	PROTO_HTTP @@ -36,7 +36,6 @@ typedef struct url  	int proto;  	int port;  	char host[MAX_STRING]; -	char dir[MAX_STRING];  	char file[MAX_STRING];  	char user[MAX_STRING];  	char pass[MAX_STRING]; | 
