diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Makefile | 2 | ||||
| -rw-r--r-- | lib/events.h | 6 | ||||
| -rw-r--r-- | lib/events_glib.c | 17 | ||||
| -rw-r--r-- | lib/events_libevent.c | 16 | ||||
| -rw-r--r-- | lib/http_client.c | 6 | ||||
| -rw-r--r-- | lib/misc.c | 38 | ||||
| -rw-r--r-- | lib/misc.h | 1 | ||||
| -rw-r--r-- | lib/oauth.c | 453 | ||||
| -rw-r--r-- | lib/oauth.h | 90 | ||||
| -rw-r--r-- | lib/proxy.c | 64 | ||||
| -rw-r--r-- | lib/ssl_bogus.c | 2 | ||||
| -rw-r--r-- | lib/ssl_client.h | 2 | ||||
| -rw-r--r-- | lib/ssl_gnutls.c | 4 | ||||
| -rw-r--r-- | lib/ssl_nss.c | 2 | ||||
| -rw-r--r-- | lib/ssl_openssl.c | 4 | ||||
| -rw-r--r-- | lib/ssl_sspi.c | 2 | ||||
| -rw-r--r-- | lib/url.c | 2 | ||||
| -rw-r--r-- | lib/url.h | 2 | ||||
| -rw-r--r-- | lib/xmltree.c | 22 | 
19 files changed, 672 insertions, 63 deletions
| diff --git a/lib/Makefile b/lib/Makefile index 3d128b5a..b686f886 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@  -include ../Makefile.settings  # [SH] Program variables -objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o ftutil.o +objects = arc.o base64.o $(EVENT_HANDLER) ftutil.o http_client.o ini.o md5.o misc.o oauth.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o  CFLAGS += -Wall  LFLAGS += -r diff --git a/lib/events.h b/lib/events.h index 4baea7b6..fa30cf27 100644 --- a/lib/events.h +++ b/lib/events.h @@ -47,8 +47,10 @@  /* The conditions you can pass to b_input_add()/that will be passed to     the given callback function. */  typedef enum { -	GAIM_INPUT_READ = 1 << 1, -	GAIM_INPUT_WRITE = 1 << 2 +	B_EV_IO_READ = 1 << 0, +	B_EV_IO_WRITE = 1 << 1, +	B_EV_FLAG_FORCE_ONCE = 1 << 16, +	B_EV_FLAG_FORCE_REPEAT = 1 << 17,  } b_input_condition;  typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); diff --git a/lib/events_glib.c b/lib/events_glib.c index 3e194e98..d6ac82cc 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -48,6 +48,7 @@  typedef struct _GaimIOClosure {  	b_event_handler function;  	gpointer data; +	guint flags;  } GaimIOClosure;  static GMainLoop *loop = NULL; @@ -75,9 +76,9 @@ static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpoin  	gboolean st;  	if (condition & GAIM_READ_COND) -		gaim_cond |= GAIM_INPUT_READ; +		gaim_cond |= B_EV_IO_READ;  	if (condition & GAIM_WRITE_COND) -		gaim_cond |= GAIM_INPUT_WRITE; +		gaim_cond |= B_EV_IO_WRITE;  	event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data ); @@ -86,7 +87,12 @@ static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpoin  	if( !st )  		event_debug( "Returned FALSE, cancelling.\n" ); -	return st; +	if (closure->flags & B_EV_FLAG_FORCE_ONCE) +		return FALSE; +	else if (closure->flags & B_EV_FLAG_FORCE_REPEAT) +		return TRUE; +	else +		return st;  }  static void gaim_io_destroy(gpointer data) @@ -104,10 +110,11 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct  	closure->function = function;  	closure->data = data; +	closure->flags = condition; -	if (condition & GAIM_INPUT_READ) +	if (condition & B_EV_IO_READ)  		cond |= GAIM_READ_COND; -	if (condition & GAIM_INPUT_WRITE) +	if (condition & B_EV_IO_WRITE)  		cond |= GAIM_WRITE_COND;  	channel = g_io_channel_unix_new(source); diff --git a/lib/events_libevent.c b/lib/events_libevent.c index cf616576..43d770ea 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -59,6 +59,7 @@ struct b_event_data  	gint timeout;  	b_event_handler function;  	void *data; +	guint flags;  };  void b_main_init() @@ -125,9 +126,9 @@ static void b_event_passthrough( int fd, short event, void *data )  	if( fd >= 0 )  	{  		if( event & EV_READ ) -			cond |= GAIM_INPUT_READ; +			cond |= B_EV_IO_READ;  		if( event & EV_WRITE ) -			cond |= GAIM_INPUT_WRITE; +			cond |= B_EV_IO_WRITE;  	}  	event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); @@ -149,7 +150,7 @@ static void b_event_passthrough( int fd, short event, void *data )  		/* This event was killed already, don't touch it! */  		return;  	} -	else if( !st ) +	else if( !st && !( b_ev->flags & B_EV_FLAG_FORCE_REPEAT ) )  	{  		event_debug( "Handler returned FALSE: " );  		b_event_remove( id_cur ); @@ -173,8 +174,8 @@ gint b_input_add( gint fd, b_input_condition condition, b_event_handler function  	event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data ); -	if( ( condition & GAIM_INPUT_READ  && ( b_ev = g_hash_table_lookup( read_hash,  &fd ) ) ) || -	    ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) ) +	if( ( condition & B_EV_IO_READ  && ( b_ev = g_hash_table_lookup( read_hash,  &fd ) ) ) || +	    ( condition & B_EV_IO_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) )  	{  		/* We'll stick with this libevent entry, but give it a new BitlBee id. */  		g_hash_table_remove( id_hash, &b_ev->id ); @@ -197,9 +198,9 @@ gint b_input_add( gint fd, b_input_condition condition, b_event_handler function  		b_ev->data = data;  		out_cond = EV_PERSIST; -		if( condition & GAIM_INPUT_READ ) +		if( condition & B_EV_IO_READ )  			out_cond |= EV_READ; -		if( condition & GAIM_INPUT_WRITE ) +		if( condition & B_EV_IO_WRITE )  			out_cond |= EV_WRITE;  		event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev ); @@ -211,6 +212,7 @@ gint b_input_add( gint fd, b_input_condition condition, b_event_handler function  			g_hash_table_insert( write_hash, &b_ev->evinfo.ev_fd, b_ev );  	} +	b_ev->flags = condition;  	g_hash_table_insert( id_hash, &b_ev->id, b_ev );  	return b_ev->id;  } diff --git a/lib/http_client.c b/lib/http_client.c index aae5645b..e9d3c1bb 100644 --- a/lib/http_client.c +++ b/lib/http_client.c @@ -148,10 +148,10 @@ static gboolean http_connected( gpointer data, int source, b_input_condition con  	if( req->bytes_written < req->request_length )  		req->inpa = b_input_add( source, -		                         req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, +		                         req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_WRITE,  	        	                 http_connected, req );  	else -		req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); +		req->inpa = b_input_add( source, B_EV_IO_READ, http_incoming_data, req );  	return FALSE; @@ -233,7 +233,7 @@ static gboolean http_incoming_data( gpointer data, int source, b_input_condition  	/* There will be more! */  	req->inpa = b_input_add( req->fd, -	                         req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, +	                         req->ssl ? ssl_getdirection( req->ssl ) : B_EV_IO_READ,  	                         http_incoming_data, req );  	return FALSE; @@ -78,6 +78,41 @@ time_t get_time(int year, int month, int day, int hour, int min, int sec)  	return mktime(&tm);  } +time_t mktime_utc( struct tm *tp ) +{ +	struct tm utc; +	time_t res, tres; +	 +	tp->tm_isdst = -1; +	res = mktime( tp ); +	/* Problem is, mktime() just gave us the GMT timestamp for the +	   given local time... While the given time WAS NOT local. So +	   we should fix this now. +	    +	   Now I could choose between messing with environment variables +	   (kludgy) or using timegm() (not portable)... Or doing the +	   following, which I actually prefer... +	    +	   tzset() may also work but in other places I actually want to +	   use local time. +	    +	   FFFFFFFFFFFFFFFFFFFFFUUUUUUUUUUUUUUUUUUUU!! */ +	gmtime_r( &res, &utc ); +	utc.tm_isdst = -1; +	if( utc.tm_hour == tp->tm_hour && utc.tm_min == tp->tm_min ) +		/* Sweet! We're in UTC right now... */ +		return res; +	 +	tres = mktime( &utc ); +	res += res - tres; +	 +	/* Yes, this is a hack. And it will go wrong around DST changes. +	   BUT this is more likely to be threadsafe than messing with +	   environment variables, and possibly more portable... */ +	 +	return res; +} +  typedef struct htmlentity  {  	char code[7]; @@ -270,8 +305,7 @@ void http_encode( char *s )  	for( i = j = 0; t[i]; i ++, j ++ )  	{ -		/* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ -		if( !isalnum( t[i] ) ) +		if( !isalnum( t[i] ) && !strchr( "._-~", t[i] ) )  		{  			sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] );  			j += 2; @@ -42,6 +42,7 @@ G_MODULE_EXPORT char *add_cr( char *text );  G_MODULE_EXPORT char *strip_newlines(char *source);  G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); +G_MODULE_EXPORT time_t mktime_utc( struct tm *tp );  double gettime( void );  G_MODULE_EXPORT void strip_html( char *msg ); diff --git a/lib/oauth.c b/lib/oauth.c new file mode 100644 index 00000000..c60a5a52 --- /dev/null +++ b/lib/oauth.c @@ -0,0 +1,453 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Simple OAuth client (consumer) implementation.                           * +*                                                                           * +*  Copyright 2010 Wilmer van der Gaast <wilmer@gaast.net>                   * +*                                                                           * +*  This library is free software; you can redistribute it and/or            * +*  modify it under the terms of the GNU Lesser General Public               * +*  License as published by the Free Software Foundation, version            * +*  2.1.                                                                     * +*                                                                           * +*  This library 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        * +*  Lesser General Public License for more details.                          * +*                                                                           * +*  You should have received a copy of the GNU Lesser General Public License * +*  along with this library; if not, write to the Free Software Foundation,  * +*  Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA           * +*                                                                           * +\***************************************************************************/ + +#include <glib.h> +#include <gmodule.h> +#include <stdlib.h> +#include <string.h> +#include "http_client.h" +#include "base64.h" +#include "misc.h" +#include "sha1.h" +#include "url.h" +#include "oauth.h" + +#define HMAC_BLOCK_SIZE 64 + +static char *oauth_sign( const char *method, const char *url, +                         const char *params, struct oauth_info *oi ) +{ +	sha1_state_t sha1; +	uint8_t hash[sha1_hash_size]; +	uint8_t key[HMAC_BLOCK_SIZE+1]; +	char *s; +	int i; +	 +	/* Create K. If our current key is >64 chars we have to hash it, +	   otherwise just pad. */ +	memset( key, 0, HMAC_BLOCK_SIZE ); +	i = strlen( oi->sp->consumer_secret ) + 1 + ( oi->token_secret ? strlen( oi->token_secret ) : 0 ); +	if( i > HMAC_BLOCK_SIZE ) +	{ +		sha1_init( &sha1 ); +		sha1_append( &sha1, (uint8_t*) oi->sp->consumer_secret, strlen( oi->sp->consumer_secret ) ); +		sha1_append( &sha1, (uint8_t*) "&", 1 ); +		if( oi->token_secret ) +			sha1_append( &sha1, (uint8_t*) oi->token_secret, strlen( oi->token_secret ) ); +		sha1_finish( &sha1, key ); +	} +	else +	{ +		g_snprintf( (gchar*) key, HMAC_BLOCK_SIZE + 1, "%s&%s", +		            oi->sp->consumer_secret, oi->token_secret ? : "" ); +	} +	 +	/* Inner part: H(K XOR 0x36, text) */ +	sha1_init( &sha1 ); +	 +	for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) +		key[i] ^= 0x36; +	sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); +	 +	/* OAuth: text = method&url¶ms, all http_encoded. */ +	sha1_append( &sha1, (const uint8_t*) method, strlen( method ) ); +	sha1_append( &sha1, (const uint8_t*) "&", 1 ); +	 +	s = g_new0( char, strlen( url ) * 3 + 1 ); +	strcpy( s, url ); +	http_encode( s ); +	sha1_append( &sha1, (const uint8_t*) s, strlen( s ) ); +	sha1_append( &sha1, (const uint8_t*) "&", 1 ); +	g_free( s ); +	 +	s = g_new0( char, strlen( params ) * 3 + 1 ); +	strcpy( s, params ); +	http_encode( s ); +	sha1_append( &sha1, (const uint8_t*) s, strlen( s ) ); +	g_free( s ); +	 +	sha1_finish( &sha1, hash ); +	 +	/* Final result: H(K XOR 0x5C, inner stuff) */ +	sha1_init( &sha1 ); +	for( i = 0; i < HMAC_BLOCK_SIZE; i ++ ) +		key[i] ^= 0x36 ^ 0x5c; +	sha1_append( &sha1, key, HMAC_BLOCK_SIZE ); +	sha1_append( &sha1, hash, sha1_hash_size ); +	sha1_finish( &sha1, hash ); +	 +	/* base64_encode + HTTP escape it (both consumers  +	   need it that away) and we're done. */ +	s = base64_encode( hash, sha1_hash_size ); +	s = g_realloc( s, strlen( s ) * 3 + 1 ); +	http_encode( s ); +	 +	return s; +} + +static char *oauth_nonce() +{ +	unsigned char bytes[9]; +	 +	random_bytes( bytes, sizeof( bytes ) ); +	return base64_encode( bytes, sizeof( bytes ) ); +} + +void oauth_params_add( GSList **params, const char *key, const char *value ) +{ +	char *item; +	 +	item = g_strdup_printf( "%s=%s", key, value ); +	*params = g_slist_insert_sorted( *params, item, (GCompareFunc) strcmp ); +} + +void oauth_params_del( GSList **params, const char *key ) +{ +	int key_len = strlen( key ); +	GSList *l, *n; +	 +	for( l = *params; l; l = n ) +	{ +		n = l->next; +		 +		if( strncmp( (char*) l->data, key, key_len ) == 0 && +		    ((char*)l->data)[key_len] == '=' ) +		{ +			g_free( l->data ); +			*params = g_slist_remove( *params, l->data ); +		} +	} +} + +void oauth_params_set( GSList **params, const char *key, const char *value ) +{ +	oauth_params_del( params, key ); +	oauth_params_add( params, key, value ); +} + +const char *oauth_params_get( GSList **params, const char *key ) +{ +	int key_len = strlen( key ); +	GSList *l; +	 +	for( l = *params; l; l = l->next ) +	{ +		if( strncmp( (char*) l->data, key, key_len ) == 0 && +		    ((char*)l->data)[key_len] == '=' ) +			return (const char*) l->data + key_len + 1; +	} +	 +	return NULL; +} + +static void oauth_params_parse( GSList **params, char *in ) +{ +	char *amp, *eq, *s; +	 +	while( in && *in ) +	{ +		eq = strchr( in, '=' ); +		if( !eq ) +			break; +		 +		*eq = '\0'; +		if( ( amp = strchr( eq + 1, '&' ) ) ) +			*amp = '\0'; +		 +		s = g_strdup( eq + 1 ); +		http_decode( s ); +		oauth_params_add( params, in, s ); +		g_free( s ); +		 +		*eq = '='; +		if( amp == NULL ) +			break; +		 +		*amp = '&'; +		in = amp + 1; +	} +} + +void oauth_params_free( GSList **params ) +{ +	while( params && *params ) +	{ +		g_free( (*params)->data ); +		*params = g_slist_remove( *params, (*params)->data ); +	} +} + +char *oauth_params_string( GSList *params ) +{ +	GSList *l; +	GString *str = g_string_new( "" ); +	 +	for( l = params; l; l = l->next ) +	{ +		char *s, *eq; +		 +		s = g_malloc( strlen( l->data ) * 3 + 1 ); +		strcpy( s, l->data ); +		if( ( eq = strchr( s, '=' ) ) ) +			http_encode( eq + 1 ); +		g_string_append( str, s ); +		g_free( s ); +		 +		if( l->next ) +			g_string_append_c( str, '&' ); +	} +	 +	return g_string_free( str, FALSE ); +} + +void oauth_info_free( struct oauth_info *info ) +{ +	if( info ) +	{ +		g_free( info->auth_url ); +		g_free( info->request_token ); +		g_free( info->token ); +		g_free( info->token_secret ); +		g_free( info ); +	} +} + +static void oauth_add_default_params( GSList **params, const struct oauth_service *sp ) +{ +	char *s; +	 +	oauth_params_set( params, "oauth_consumer_key", sp->consumer_key ); +	oauth_params_set( params, "oauth_signature_method", "HMAC-SHA1" ); +	 +	s = g_strdup_printf( "%d", (int) time( NULL ) ); +	oauth_params_set( params, "oauth_timestamp", s ); +	g_free( s ); +	 +	s = oauth_nonce(); +	oauth_params_set( params, "oauth_nonce", s ); +	g_free( s ); +	 +	oauth_params_set( params, "oauth_version", "1.0" ); +} + +static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, struct oauth_info *oi ) +{ +	GSList *params = NULL; +	char *s, *params_s, *post; +	void *req; +	url_t url_p; +	 +	if( !url_set( &url_p, url ) ) +	{ +		oauth_params_free( params_ ); +		return NULL; +	} +	 +	if( params_ ) +		params = *params_; +	 +	oauth_add_default_params( ¶ms, oi->sp ); +	 +	params_s = oauth_params_string( params ); +	oauth_params_free( ¶ms ); +	 +	s = oauth_sign( "POST", url, params_s, oi ); +	post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); +	g_free( params_s ); +	g_free( s ); +	 +	s = g_strdup_printf( "POST %s HTTP/1.0\r\n" +	                     "Host: %s\r\n" +	                     "Content-Type: application/x-www-form-urlencoded\r\n" +	                     "Content-Length: %zd\r\n" +	                     "\r\n" +	                     "%s", url_p.file, url_p.host, strlen( post ), post ); +	g_free( post ); +	 +	req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS, +	                      s, func, oi ); +	g_free( s ); +	 +	return req; +} + +static void oauth_request_token_done( struct http_request *req ); + +struct oauth_info *oauth_request_token( const struct oauth_service *sp, oauth_cb func, void *data ) +{ +	struct oauth_info *st = g_new0( struct oauth_info, 1 ); +	GSList *params = NULL; +	 +	st->func = func; +	st->data = data; +	st->sp = sp; +	 +	oauth_params_add( ¶ms, "oauth_callback", "oob" ); +	 +	if( !oauth_post_request( sp->url_request_token, ¶ms, oauth_request_token_done, st ) ) +	{ +		oauth_info_free( st ); +		return NULL; +	} +	 +	return st; +} + +static void oauth_request_token_done( struct http_request *req ) +{ +	struct oauth_info *st = req->data; +	 +	st->http = req; +	 +	if( req->status_code == 200 ) +	{ +		GSList *params = NULL; +		 +		st->auth_url = g_strdup_printf( "%s?%s", st->sp->url_authorize, req->reply_body ); +		oauth_params_parse( ¶ms, req->reply_body ); +		st->request_token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); +		oauth_params_free( ¶ms ); +	} +	 +	st->stage = OAUTH_REQUEST_TOKEN; +	st->func( st ); +} + +static void oauth_access_token_done( struct http_request *req ); + +gboolean oauth_access_token( const char *pin, struct oauth_info *st ) +{ +	GSList *params = NULL; +	 +	oauth_params_add( ¶ms, "oauth_token", st->request_token ); +	oauth_params_add( ¶ms, "oauth_verifier", pin ); +	 +	return oauth_post_request( st->sp->url_access_token, ¶ms, oauth_access_token_done, st ) != NULL; +} + +static void oauth_access_token_done( struct http_request *req ) +{ +	struct oauth_info *st = req->data; +	 +	st->http = req; +	 +	if( req->status_code == 200 ) +	{ +		GSList *params = NULL; +		 +		oauth_params_parse( ¶ms, req->reply_body ); +		st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); +		st->token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); +		oauth_params_free( ¶ms ); +	} +	 +	st->stage = OAUTH_ACCESS_TOKEN; +	if( st->func( st ) ) +	{ +		/* Don't need these anymore, but keep the rest. */ +		g_free( st->auth_url ); +		st->auth_url = NULL; +		g_free( st->request_token ); +		st->request_token = NULL; +	} +} + +char *oauth_http_header( struct oauth_info *oi, const char *method, const char *url, char *args ) +{ +	GSList *params = NULL, *l; +	char *sig = NULL, *params_s, *s; +	GString *ret = NULL; +	 +	oauth_params_add( ¶ms, "oauth_token", oi->token ); +	oauth_add_default_params( ¶ms, oi->sp ); +	 +	/* Start building the OAuth header. 'key="value", '... */ +	ret = g_string_new( "OAuth " ); +	for( l = params; l; l = l->next ) +	{ +		char *kv = l->data; +		char *eq = strchr( kv, '=' ); +		char esc[strlen(kv)*3+1]; +		 +		if( eq == NULL ) +			break; /* WTF */ +		 +		strcpy( esc, eq + 1 ); +		http_encode( esc ); +		 +		g_string_append_len( ret, kv, eq - kv + 1 ); +		g_string_append_c( ret, '"' ); +		g_string_append( ret, esc ); +		g_string_append( ret, "\", " ); +	} +	 +	/* Now, before generating the signature, add GET/POST arguments to params +	   since they should be included in the base signature string (but not in +	   the HTTP header). */ +	if( args ) +		oauth_params_parse( ¶ms, args ); +	if( ( s = strchr( url, '?' ) ) ) +	{ +		s = g_strdup( s + 1 ); +		oauth_params_parse( ¶ms, s ); +		g_free( s ); +	} +	 +	/* Append the signature and we're done! */ +	params_s = oauth_params_string( params ); +	sig = oauth_sign( method, url, params_s, oi ); +	g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); +	g_free( params_s ); +	 +	oauth_params_free( ¶ms ); +	g_free( sig ); +	 +	return ret ? g_string_free( ret, FALSE ) : NULL; +} + +char *oauth_to_string( struct oauth_info *oi ) +{ +	GSList *params = NULL; +	char *ret; +	 +	oauth_params_add( ¶ms, "oauth_token", oi->token ); +	oauth_params_add( ¶ms, "oauth_token_secret", oi->token_secret ); +	ret = oauth_params_string( params ); +	oauth_params_free( ¶ms ); +	 +	return ret; +} + +struct oauth_info *oauth_from_string( char *in, const struct oauth_service *sp ) +{ +	struct oauth_info *oi = g_new0( struct oauth_info, 1 ); +	GSList *params = NULL; +	 +	oauth_params_parse( ¶ms, in ); +	oi->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); +	oi->token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); +	oauth_params_free( ¶ms ); +	oi->sp = sp; +	 +	return oi; +} diff --git a/lib/oauth.h b/lib/oauth.h new file mode 100644 index 00000000..5dfe0ae5 --- /dev/null +++ b/lib/oauth.h @@ -0,0 +1,90 @@ +/***************************************************************************\ +*                                                                           * +*  BitlBee - An IRC to IM gateway                                           * +*  Simple OAuth client (consumer) implementation.                           * +*                                                                           * +*  Copyright 2010 Wilmer van der Gaast <wilmer@gaast.net>                   * +*                                                                           * +*  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 along  * +*  with this program; if not, write to the Free Software Foundation, Inc.,  * +*  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.              * +*                                                                           * +\***************************************************************************/ + +/* http://oauth.net/core/1.0a/ */ + +struct oauth_info; + +/* Callback function called twice during the access token request process. +   Return FALSE if something broke and the process must be aborted. */ +typedef gboolean (*oauth_cb)( struct oauth_info * ); + +typedef enum +{ +	OAUTH_INIT, +	OAUTH_REQUEST_TOKEN, +	OAUTH_ACCESS_TOKEN, +} oauth_stage_t; + +struct oauth_info +{ +	oauth_stage_t stage; +	const struct oauth_service *sp; +	 +	oauth_cb func; +	void *data; +	 +	struct http_request *http; +	 +	char *auth_url; +	char *request_token; +	 +	char *token; +	char *token_secret; +}; + +struct oauth_service +{ +	char *url_request_token; +	char *url_access_token; +	char *url_authorize; +	 +	char *consumer_key; +	char *consumer_secret; +}; + +/* http://oauth.net/core/1.0a/#auth_step1 (section 6.1)  +   Request an initial anonymous token which can be used to construct an +   authorization URL for the user. This is passed to the callback function +   in a struct oauth_info. */ +struct oauth_info *oauth_request_token( const struct oauth_service *sp, oauth_cb func, void *data ); + +/* http://oauth.net/core/1.0a/#auth_step3 (section 6.3) +   The user gets a PIN or so which we now exchange for the final access +   token. This is passed to the callback function in the same +   struct oauth_info. */ +gboolean oauth_access_token( const char *pin, struct oauth_info *st ); + +/* http://oauth.net/core/1.0a/#anchor12 (section 7) +   Generate an OAuth Authorization: HTTP header. access_token should be +   saved/fetched using the functions above. args can be a string with +   whatever's going to be in the POST body of the request. GET args will +   automatically be grabbed from url. */ +char *oauth_http_header( struct oauth_info *oi, const char *method, const char *url, char *args ); + +/* Shouldn't normally be required unless the process is aborted by the user. */ +void oauth_info_free( struct oauth_info *info ); + +/* Convert to and back from strings, for easier saving. */ +char *oauth_to_string( struct oauth_info *oi ); +struct oauth_info *oauth_from_string( char *in, const struct oauth_service *sp ); diff --git a/lib/proxy.c b/lib/proxy.c index e52837fe..baf5823a 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -90,9 +90,9 @@ static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition  		closesocket(source);  		b_event_remove(phb->inpa);  		if( phb->proxy_func ) -			phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); +			phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ);  		else { -			phb->func(phb->data, -1, GAIM_INPUT_READ); +			phb->func(phb->data, -1, B_EV_IO_READ);  			g_free(phb);  		}  		return FALSE; @@ -101,9 +101,9 @@ static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition  	sock_make_blocking(source);  	b_event_remove(phb->inpa);  	if( phb->proxy_func ) -		phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); +		phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ);  	else { -		phb->func(phb->data, source, GAIM_INPUT_READ); +		phb->func(phb->data, source, B_EV_IO_READ);  		g_free(phb);  	} @@ -146,7 +146,7 @@ static int proxy_connect_none(const char *host, unsigned short port, struct PHB  		return -1;  	} else { -		phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); +		phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb);  		phb->fd = fd;  		return fd; @@ -178,14 +178,14 @@ static gboolean http_canread(gpointer data, gint source, b_input_condition cond)  	if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) ||  	    (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { -		phb->func(phb->data, source, GAIM_INPUT_READ); +		phb->func(phb->data, source, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	}  	close(source); -	phb->func(phb->data, -1, GAIM_INPUT_READ); +	phb->func(phb->data, -1, B_EV_IO_READ);  	g_free(phb->host);  	g_free(phb); @@ -203,7 +203,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  	len = sizeof(error);  	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -214,7 +214,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  		   phb->host, phb->port);  	if (send(source, cmd, strlen(cmd), 0) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -229,7 +229,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  		g_free(t2);  		if (send(source, cmd, strlen(cmd), 0) < 0) {  			close(source); -			phb->func(phb->data, -1, GAIM_INPUT_READ); +			phb->func(phb->data, -1, B_EV_IO_READ);  			g_free(phb->host);  			g_free(phb);  			return FALSE; @@ -239,13 +239,13 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond  	g_snprintf(cmd, sizeof(cmd), "\r\n");  	if (send(source, cmd, strlen(cmd), 0) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, http_canread, phb);  	return FALSE;  } @@ -272,14 +272,14 @@ static gboolean s4_canread(gpointer data, gint source, b_input_condition cond)  	memset(packet, 0, sizeof(packet));  	if (read(source, packet, 9) >= 4 && packet[1] == 90) { -		phb->func(phb->data, source, GAIM_INPUT_READ); +		phb->func(phb->data, source, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	}  	close(source); -	phb->func(phb->data, -1, GAIM_INPUT_READ); +	phb->func(phb->data, -1, B_EV_IO_READ);  	g_free(phb->host);  	g_free(phb); @@ -298,7 +298,7 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)  	len = sizeof(error);  	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -308,7 +308,7 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)  	/* XXX does socks4 not support host name lookups by the proxy? */  	if (!(hp = gethostbyname(phb->host))) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -325,13 +325,13 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)  	packet[8] = 0;  	if (write(source, packet, 9) != 9) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, s4_canread, phb);  	return FALSE;  } @@ -358,20 +358,20 @@ static gboolean s5_canread_again(gpointer data, gint source, b_input_condition c  	if (read(source, buf, 10) < 10) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	}  	if ((buf[0] != 0x05) || (buf[1] != 0x00)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->func(phb->data, source, GAIM_INPUT_READ); +	phb->func(phb->data, source, B_EV_IO_READ);  	g_free(phb->host);  	g_free(phb); @@ -395,13 +395,13 @@ static void s5_sendconnect(gpointer data, gint source)  	if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread_again, phb);  }  static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond) @@ -413,7 +413,7 @@ static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)  	if (read(source, buf, 2) < 2) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -421,7 +421,7 @@ static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)  	if ((buf[0] != 0x01) || (buf[1] != 0x00)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -441,7 +441,7 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)  	if (read(source, buf, 2) < 2) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -449,7 +449,7 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)  	if ((buf[0] != 0x05) || (buf[1] == 0xff)) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -464,13 +464,13 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)  		memcpy(buf + 2 + i + 1, proxypass, j);  		if (write(source, buf, 3 + i + j) < 3 + i + j) {  			close(source); -			phb->func(phb->data, -1, GAIM_INPUT_READ); +			phb->func(phb->data, -1, B_EV_IO_READ);  			g_free(phb->host);  			g_free(phb);  			return FALSE;  		} -		phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); +		phb->inpa = b_input_add(source, B_EV_IO_READ, s5_readauth, phb);  	} else {  		s5_sendconnect(phb, source);  	} @@ -490,7 +490,7 @@ static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond)  	len = sizeof(error);  	if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE; @@ -512,13 +512,13 @@ static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond)  	if (write(source, buf, i) < i) {  		close(source); -		phb->func(phb->data, -1, GAIM_INPUT_READ); +		phb->func(phb->data, -1, B_EV_IO_READ);  		g_free(phb->host);  		g_free(phb);  		return FALSE;  	} -	phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); +	phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread, phb);  	return FALSE;  } diff --git a/lib/ssl_bogus.c b/lib/ssl_bogus.c index a07ea752..9c368c66 100644 --- a/lib/ssl_bogus.c +++ b/lib/ssl_bogus.c @@ -58,7 +58,7 @@ void *ssl_starttls( int fd, ssl_input_function func, gpointer data )  b_input_condition ssl_getdirection( void *conn )  { -	return GAIM_INPUT_READ; +	return B_EV_IO_READ;  }  int ssl_pending( void *conn ) diff --git a/lib/ssl_client.h b/lib/ssl_client.h index f91d0d70..0a8e82d8 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -70,7 +70,7 @@ G_MODULE_EXPORT void ssl_disconnect( void *conn_ );     handling. */  G_MODULE_EXPORT int ssl_getfd( void *conn ); -/* This function returns GAIM_INPUT_READ/WRITE. With SSL connections it's +/* This function returns B_EV_IO_READ/WRITE. With SSL connections it's     possible that something has to be read while actually were trying to     write something (think about key exchange/refresh/etc). So when an     SSL operation returned SSL_AGAIN, *always* use this function when diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index f5945442..5a14b825 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -105,7 +105,7 @@ static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition  {  	struct scd *conn = data; -	return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE ); +	return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );  }  static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) @@ -243,5 +243,5 @@ int ssl_getfd( void *conn )  b_input_condition ssl_getdirection( void *conn )  {  	return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? -	        GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +	        B_EV_IO_WRITE : B_EV_IO_READ );  } diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c index eba3c441..de6e7ec6 100644 --- a/lib/ssl_nss.c +++ b/lib/ssl_nss.c @@ -192,5 +192,5 @@ int ssl_getfd( void *conn )  b_input_condition ssl_getdirection( void *conn )  {  	/* Just in case someone calls us, let's return the most likely case: */ -	return GAIM_INPUT_READ; +	return B_EV_IO_READ;  } diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index fc6d433e..8abff390 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -101,7 +101,7 @@ static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition  {  	struct scd *conn = data; -	return ssl_connected( conn, conn->fd, GAIM_INPUT_WRITE ); +	return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );  }  static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) @@ -269,5 +269,5 @@ int ssl_getfd( void *conn )  b_input_condition ssl_getdirection( void *conn )  { -	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );  } diff --git a/lib/ssl_sspi.c b/lib/ssl_sspi.c index a16423b1..e14c451e 100644 --- a/lib/ssl_sspi.c +++ b/lib/ssl_sspi.c @@ -274,5 +274,5 @@ int ssl_getfd(void *conn)  GaimInputCondition ssl_getdirection( void *conn )  { -	return GAIM_INPUT_WRITE; /* FIXME: or GAIM_INPUT_READ */ +	return B_EV_IO_WRITE; /* FIXME: or B_EV_IO_READ */  } @@ -26,7 +26,7 @@  #include "url.h"  /* Convert an URL to a url_t structure */ -int url_set( url_t *url, char *set_url ) +int url_set( url_t *url, const char *set_url )  {  	char s[MAX_STRING+1];  	char *i; @@ -41,4 +41,4 @@ typedef struct url  	char pass[MAX_STRING+1];  } url_t; -int url_set( url_t *url, char *set_url ); +int url_set( url_t *url, const char *set_url ); diff --git a/lib/xmltree.c b/lib/xmltree.c index 67fe46e1..31f8ee9c 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -448,7 +448,11 @@ struct xt_node *xt_find_node( struct xt_node *node, const char *name )  {  	while( node )  	{ -		if( g_strcasecmp( node->name, name ) == 0 ) +		char *colon; +		 +		if( g_strcasecmp( node->name, name ) == 0 || +		    ( ( colon = strchr( node->name, ':' ) ) && +		      g_strcasecmp( colon + 1, name ) == 0 ) )  			break;  		node = node->next; @@ -460,6 +464,7 @@ struct xt_node *xt_find_node( struct xt_node *node, const char *name )  char *xt_find_attr( struct xt_node *node, const char *key )  {  	int i; +	char *colon;  	if( !node )  		return NULL; @@ -468,6 +473,21 @@ char *xt_find_attr( struct xt_node *node, const char *key )  		if( g_strcasecmp( node->attr[i].key, key ) == 0 )  			break; +	/* This is an awful hack that only takes care of namespace prefixes +	   inside a tag. Since IMHO excessive namespace usage in XMPP is +	   massive overkill anyway (this code exists for almost four years +	   now and never really missed it): Meh. */ +	if( !node->attr[i].key && strcmp( key, "xmlns" ) == 0 && +	    ( colon = strchr( node->name, ':' ) ) ) +	{ +		*colon = '\0'; +		for( i = 0; node->attr[i].key; i ++ ) +			if( strncmp( node->attr[i].key, "xmlns:", 6 ) == 0 && +			    strcmp( node->attr[i].key + 6, node->name ) == 0 ) +				break; +		*colon = ':'; +	} +	  	return node->attr[i].value;  } | 
