diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile | 8 | ||||
-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/ftutil.c | 144 | ||||
-rw-r--r-- | lib/ftutil.h | 40 | ||||
-rw-r--r-- | lib/http_client.c | 16 | ||||
-rw-r--r-- | lib/http_client.h | 8 | ||||
-rw-r--r-- | lib/md5.h | 4 | ||||
-rw-r--r-- | lib/misc.c | 104 | ||||
-rw-r--r-- | lib/misc.h | 3 | ||||
-rw-r--r-- | lib/oauth.c | 453 | ||||
-rw-r--r-- | lib/oauth.h | 90 | ||||
-rw-r--r-- | lib/proxy.c | 167 | ||||
-rw-r--r-- | lib/sha1.h | 4 | ||||
-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 | 27 |
24 files changed, 997 insertions, 130 deletions
diff --git a/lib/Makefile b/lib/Makefile index 03fef1ab..bebe3ba6 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,11 +7,13 @@ ### DEFINITIONS -include ../Makefile.settings +ifdef SRCDIR +SRCDIR := $(SRCDIR)lib/ +endif # [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 +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 # [SH] Phony targets @@ -36,6 +38,6 @@ lib.o: $(objects) $(subdirs) $(objects): ../Makefile.settings Makefile -$(objects): %.o: %.c +$(objects): %.o: $(SRCDIR)%.c @echo '*' Compiling $< @$(CC) -c $(CFLAGS) $< -o $@ 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/ftutil.c b/lib/ftutil.c new file mode 100644 index 00000000..71c09b50 --- /dev/null +++ b/lib/ftutil.c @@ -0,0 +1,144 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Utility functions for file transfer * +* * +* Copyright 2008 Uli Meis <a.sporto+bee@gmail.com> * +* * +* 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. * +* * +\***************************************************************************/ + +#define BITLBEE_CORE +#include "bitlbee.h" +#include <poll.h> +#include <netinet/tcp.h> +#include "lib/ftutil.h" + +#define ASSERTSOCKOP(op, msg) \ + if( (op) == -1 ) {\ + g_snprintf( errmsg, sizeof( errmsg ), msg ": %s", strerror( errno ) ); \ + return -1; } + +/* + * Creates a listening socket and returns it in saddr_ptr. + */ +int ft_listen( struct sockaddr_storage *saddr_ptr, char *host, char *port, int copy_fd, int for_bitlbee_client, char **errptr ) +{ + int fd, gret, saddrlen; + struct addrinfo hints, *rp; + socklen_t ssize = sizeof( struct sockaddr_storage ); + struct sockaddr_storage saddrs, *saddr = &saddrs; + static char errmsg[1024]; + char *ftlisten = global.conf->ft_listen; + + if( errptr ) + *errptr = errmsg; + + strcpy( port, "0" ); + + /* Format is <IP-A>[:<Port-A>];<IP-B>[:<Port-B>] where + * A is for connections with the bitlbee client (DCC) + * and B is for connections with IM peers. + */ + if( ftlisten ) + { + char *scolon = strchr( ftlisten, ';' ); + char *colon; + + if( scolon ) + { + if( for_bitlbee_client ) + { + *scolon = '\0'; + strncpy( host, ftlisten, HOST_NAME_MAX ); + *scolon = ';'; + } + else + { + strncpy( host, scolon + 1, HOST_NAME_MAX ); + } + } + else + { + strncpy( host, ftlisten, HOST_NAME_MAX ); + } + + if( ( colon = strchr( host, ':' ) ) ) + { + *colon = '\0'; + strncpy( port, colon + 1, 5 ); + } + } + else if( copy_fd >= 0 && getsockname( copy_fd, (struct sockaddr*) &saddrs, &ssize ) == 0 && + ( saddrs.ss_family == AF_INET || saddrs.ss_family == AF_INET6 ) && + getnameinfo( (struct sockaddr*) &saddrs, ssize, host, HOST_NAME_MAX, + NULL, 0, NI_NUMERICHOST ) == 0 ) + { + /* We just took our local address on copy_fd, which is likely to be a + sensible address from which we can do a file transfer now - the + most sensible we can get easily. */ + } + else + { + ASSERTSOCKOP( gethostname( host, HOST_NAME_MAX + 1 ), "gethostname()" ); + } + + memset( &hints, 0, sizeof( struct addrinfo ) ); + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICSERV; + + if ( ( gret = getaddrinfo( host, port, &hints, &rp ) ) != 0 ) + { + sprintf( errmsg, "getaddrinfo() failed: %s", gai_strerror( gret ) ); + return -1; + } + + saddrlen = rp->ai_addrlen; + + memcpy( saddr, rp->ai_addr, saddrlen ); + + freeaddrinfo( rp ); + + ASSERTSOCKOP( fd = socket( saddr->ss_family, SOCK_STREAM, 0 ), "Opening socket" ); + ASSERTSOCKOP( bind( fd, ( struct sockaddr *)saddr, saddrlen ), "Binding socket" ); + ASSERTSOCKOP( listen( fd, 1 ), "Making socket listen" ); + + if ( !inet_ntop( saddr->ss_family, saddr->ss_family == AF_INET ? + ( void * )&( ( struct sockaddr_in * ) saddr )->sin_addr.s_addr : + ( void * )&( ( struct sockaddr_in6 * ) saddr )->sin6_addr.s6_addr, + host, HOST_NAME_MAX ) ) + { + strcpy( errmsg, "inet_ntop failed on listening socket" ); + return -1; + } + + ssize = sizeof( struct sockaddr_storage ); + ASSERTSOCKOP( getsockname( fd, ( struct sockaddr *)saddr, &ssize ), "Getting socket name" ); + + if( saddr->ss_family == AF_INET ) + g_snprintf( port, 6, "%d", ntohs( ( (struct sockaddr_in *) saddr )->sin_port ) ); + else + g_snprintf( port, 6, "%d", ntohs( ( (struct sockaddr_in6 *) saddr )->sin6_port ) ); + + if( saddr_ptr ) + memcpy( saddr_ptr, saddr, saddrlen ); + + /* I hate static-length strings.. */ + host[HOST_NAME_MAX] = '\0'; + port[5] = '\0'; + + return fd; +} diff --git a/lib/ftutil.h b/lib/ftutil.h new file mode 100644 index 00000000..09c1104e --- /dev/null +++ b/lib/ftutil.h @@ -0,0 +1,40 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Utility functions for file transfer * +* * +* Copyright 2008 Uli Meis <a.sporto+bee@gmail.com> * +* * +* 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. * +* * +\***************************************************************************/ + +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV 0x0400 /* Don't use name resolution. */ +#endif + +/* Some ifdefs for ulibc and apparently also BSD (Thanks to Whoopie) */ +#ifndef HOST_NAME_MAX +#include <sys/param.h> +#ifdef MAXHOSTNAMELEN +#define HOST_NAME_MAX MAXHOSTNAMELEN +#else +#define HOST_NAME_MAX 255 +#endif +#endif + +/* This function should be used with care. host should be AT LEAST a + char[HOST_NAME_MAX+1] and port AT LEAST a char[6]. */ +int ft_listen( struct sockaddr_storage *saddr_ptr, char *host, char *port, int copy_fd, int for_bitlbee_client, char **errptr ); diff --git a/lib/http_client.c b/lib/http_client.c index aae5645b..69f06ec5 100644 --- a/lib/http_client.c +++ b/lib/http_client.c @@ -34,9 +34,10 @@ static gboolean http_connected( gpointer data, int source, b_input_condition cond ); static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ); static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ); +static void http_free( struct http_request *req ); -void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) +struct http_request *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) { struct http_request *req; int error = 0; @@ -66,11 +67,12 @@ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_f req->data = data; req->request = g_strdup( request ); req->request_length = strlen( request ); + req->redir_ttl = 3; return( req ); } -void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) +struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) { url_t *url = g_new0( url_t, 1 ); char *request; @@ -148,10 +150,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 +235,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; @@ -310,7 +312,7 @@ got_reply: req->status_code = -1; } - if( req->status_code == 301 || req->status_code == 302 ) + if( ( req->status_code == 301 || req->status_code == 302 ) && req->redir_ttl-- > 0 ) { char *loc, *new_request, *new_host; int error = 0, new_port, new_proto; @@ -444,7 +446,7 @@ cleanup: return FALSE; } -void http_free( struct http_request *req ) +static void http_free( struct http_request *req ) { g_free( req->request ); g_free( req->reply_headers ); diff --git a/lib/http_client.h b/lib/http_client.h index d73894a4..27c484ff 100644 --- a/lib/http_client.h +++ b/lib/http_client.h @@ -60,6 +60,8 @@ struct http_request int body_size; /* The number of bytes in reply_body. */ int finished; /* Set to non-0 if the request was completed successfully. */ + int redir_ttl; /* You can set it to 0 if you don't want + http_client to follow them. */ http_input_function func; gpointer data; @@ -78,7 +80,5 @@ struct http_request version is probably only useful if you want to do POST requests or if you want to add some extra headers. As you can see, HTTPS connections are also supported (using ssl_client). */ -void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); -void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); - -void http_free( struct http_request *req ); +struct http_request *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); +struct http_request *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); @@ -26,7 +26,11 @@ #include <sys/types.h> #include <gmodule.h> +#if(__sun) +#include <inttypes.h> +#else #include <stdint.h> +#endif typedef uint8_t md5_byte_t; typedef struct MD5Context { @@ -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]; @@ -118,11 +153,11 @@ static const htmlentity_t ent[] = void strip_html( char *in ) { char *start = in; - char *out = g_malloc( strlen( in ) + 1 ); + char out[strlen(in)+1]; char *s = out, *cs; int i, matched; - memset( out, 0, strlen( in ) + 1 ); + memset( out, 0, sizeof( out ) ); while( *in ) { @@ -184,7 +219,6 @@ void strip_html( char *in ) } strcpy( start, out ); - g_free( out ); } char *escape_html( const char *html ) @@ -269,15 +303,18 @@ void http_encode( char *s ) strcpy( t, s ); for( i = j = 0; t[i]; i ++, j ++ ) { - /* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ - if( !isalnum( t[i] ) ) + /* Warning: isalnum() is locale-aware, so don't use it here! */ + if( ( t[i] >= 'A' && t[i] <= 'Z' ) || + ( t[i] >= 'a' && t[i] <= 'z' ) || + ( t[i] >= '0' && t[i] <= '9' ) || + strchr( "._-~", t[i] ) ) { - sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); - j += 2; + s[j] = t[i]; } else { - s[j] = t[i]; + sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); + j += 2; } } s[j] = 0; @@ -610,3 +647,54 @@ int md5_verify_password( char *password, char *hash ) return ret; } + +/* Split commands (root-style, *not* IRC-style). Handles "quoting of" + white\ space in 'various ways'. Returns a NULL-terminated static + char** so watch out with nested use! Definitely not thread-safe. */ +char **split_command_parts( char *command ) +{ + static char *cmd[IRC_MAX_ARGS+1]; + char *s, q = 0; + int k; + + memset( cmd, 0, sizeof( cmd ) ); + cmd[0] = command; + k = 1; + for( s = command; *s && k < IRC_MAX_ARGS; s ++ ) + if( *s == ' ' && !q ) + { + *s = 0; + while( *++s == ' ' ); + if( *s == '"' || *s == '\'' ) + { + q = *s; + s ++; + } + if( *s ) + { + cmd[k++] = s; + s --; + } + else + { + break; + } + } + else if( *s == '\\' && ( ( !q && s[1] ) || ( q && q == s[1] ) ) ) + { + char *cpy; + + for( cpy = s; *cpy; cpy ++ ) + cpy[0] = cpy[1]; + } + else if( *s == q ) + { + q = *s = 0; + } + + /* Full zero-padding for easier argc checking. */ + while( k <= IRC_MAX_ARGS ) + cmd[k++] = NULL; + + return cmd; +} @@ -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 ); @@ -67,4 +68,6 @@ G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl ); G_MODULE_EXPORT int md5_verify_password( char *password, char *hash ); +G_MODULE_EXPORT char **split_command_parts( char *command ); + #endif diff --git a/lib/oauth.c b/lib/oauth.c new file mode 100644 index 00000000..57dd10f8 --- /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 ? 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..0b1866ea 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -57,27 +57,6 @@ struct PHB { gint inpa; }; - - -static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) -{ - static struct sockaddr_in sin; - - if (!inet_aton(host, &sin.sin_addr)) { - struct hostent *hp; - if (!(hp = gethostbyname(host))) { - return NULL; - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - } else - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - return &sin; -} - static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) { struct PHB *phb = data; @@ -90,9 +69,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,56 +80,80 @@ 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); } return FALSE; } -static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) +static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb) { - struct sockaddr_in *sin; struct sockaddr_in me; int fd = -1; + int ret; + char port[6]; + struct addrinfo hints; + struct addrinfo* result; - if (!(sin = gaim_gethostbyname(host, port))) { - g_free(phb); - return -1; - } + g_snprintf(port, sizeof(port), "%d", port_); - if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { - g_free(phb); - return -1; - } + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; - sock_make_nonblocking(fd); + if (!(ret = getaddrinfo(host, port, &hints, &result))) + { + struct addrinfo* rp; + + for (rp = result; rp; rp = rp->ai_next) + { + if ((fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0) { + event_debug( "socket failed: %d\n", errno); + continue; + } + + sock_make_nonblocking(fd); + + if (global.conf->iface_out) + { + me.sin_family = AF_INET; + me.sin_port = 0; + me.sin_addr.s_addr = inet_addr( global.conf->iface_out ); + + if (bind(fd, (struct sockaddr *) &me, sizeof(me)) != 0) + event_debug("bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out); + } + + event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); - if( global.conf->iface_out ) + if (connect(fd, rp->ai_addr, rp->ai_addrlen) < 0 && !sockerr_again()) { + event_debug( "connect failed: %s\n", strerror(errno)); + closesocket(fd); + fd = -1; + continue; + } else { + phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb); + phb->fd = fd; + + break; + } + } + + freeaddrinfo(result); + } + else { - me.sin_family = AF_INET; - me.sin_port = 0; - me.sin_addr.s_addr = inet_addr( global.conf->iface_out ); - - if( bind( fd, (struct sockaddr *) &me, sizeof( me ) ) != 0 ) - event_debug( "bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out ); + event_debug("gai(): %s\n", gai_strerror(ret)); } - event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); - - if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) { - closesocket(fd); + if(fd < 0) g_free(phb); - - return -1; - } else { - phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); - phb->fd = fd; - - return fd; - } + + return fd; } @@ -178,14 +181,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 +206,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 +217,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 +232,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 +242,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 +275,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 +301,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 +311,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 +328,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 +361,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 +398,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 +416,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 +424,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 +444,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 +452,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 +467,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 +493,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 +515,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; } @@ -23,7 +23,11 @@ #ifndef _SHA1_H_ #define _SHA1_H_ +#if(__sun) +#include <inttypes.h> +#else #include <stdint.h> +#endif #include <gmodule.h> #ifndef _SHA_enum_ 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..b0a945ce 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -214,7 +214,10 @@ void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) return; if( node == NULL ) - return xt_cleanup( xt, xt->root, depth ); + { + xt_cleanup( xt, xt->root, depth ); + return; + } if( node->flags & XT_SEEN && node == xt->root ) { @@ -448,7 +451,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 +467,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 +476,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; } |