From e046390da36e369c94af607fdedfe7b9f99d9e47 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 11 Oct 2009 00:25:54 +0100 Subject: Make purple use BitlBee's event handling API. Since the APIs never really diverged too much this is fairly transparent. I did rename and redefine GAIM_INPUT_* variables to really make it work without adding another stupid layer in between. One problem left, the new libpurple input API doesn't care about return values. Fixing that in the next CL. --- lib/events.h | 4 ++-- lib/events_glib.c | 8 +++---- lib/events_libevent.c | 12 +++++----- lib/http_client.c | 6 ++--- lib/proxy.c | 64 +++++++++++++++++++++++++-------------------------- lib/ssl_bogus.c | 2 +- lib/ssl_client.h | 2 +- lib/ssl_gnutls.c | 4 ++-- lib/ssl_nss.c | 2 +- lib/ssl_openssl.c | 4 ++-- lib/ssl_sspi.c | 2 +- 11 files changed, 55 insertions(+), 55 deletions(-) (limited to 'lib') diff --git a/lib/events.h b/lib/events.h index 4baea7b6..5bf2cfd8 100644 --- a/lib/events.h +++ b/lib/events.h @@ -47,8 +47,8 @@ /* 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_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..2260ec4e 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -75,9 +75,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 ); @@ -105,9 +105,9 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct closure->function = function; closure->data = data; - 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..b52a5dd3 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -125,9 +125,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 ); @@ -173,8 +173,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 +197,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 ); 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; 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 */ } -- cgit v1.2.3 From c5c18c155cfdc3edcbd764633761d33e3c5992a3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 11 Oct 2009 00:57:26 +0100 Subject: Hacked up a B_EV_FLAG_FORCE_REPEAT event handler flag to make libpurple happy. --- lib/events.h | 4 +++- lib/events_glib.c | 9 ++++++++- lib/events_libevent.c | 4 +++- 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/events.h b/lib/events.h index 5bf2cfd8..fa30cf27 100644 --- a/lib/events.h +++ b/lib/events.h @@ -48,7 +48,9 @@ the given callback function. */ typedef enum { B_EV_IO_READ = 1 << 0, - B_EV_IO_WRITE = 1 << 1 + 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 2260ec4e..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; @@ -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,6 +110,7 @@ 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 & B_EV_IO_READ) cond |= GAIM_READ_COND; diff --git a/lib/events_libevent.c b/lib/events_libevent.c index b52a5dd3..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() @@ -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 ); @@ -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; } -- cgit v1.2.3 From 2e3a8576d6ca511df347426b4319bccde1871d06 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 8 Apr 2010 01:27:42 +0100 Subject: Added a mktime_utc() to misc.c using code that used to be in jabber_util.c. I want to use this in the Twitter module. --- lib/misc.c | 35 +++++++++++++++++++++++++++++++++++ lib/misc.h | 1 + 2 files changed, 36 insertions(+) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index fe2ff17c..1d36d639 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -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]; diff --git a/lib/misc.h b/lib/misc.h index ce36caf5..9f2058b6 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -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 ); -- cgit v1.2.3 From 0f64ca78c8ec9ee9be2ffa8ec203e138f7a00804 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 13:56:20 +0100 Subject: Make http_encode() RFC3986-compliant. (Escape everything except alphanumeric characters plus [-_~.].) --- lib/misc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/misc.c b/lib/misc.c index 1d36d639..c56b31f3 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -305,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; -- cgit v1.2.3 From be28fe7da3e197d91ec00a6c1017c053041f5a85 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 16:12:13 +0100 Subject: Code to calculate OAuth signatures. I hope that after wrapping my mind around all of this the rest is going to be easier.. --- lib/Makefile | 2 +- lib/oauth.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/oauth.h | 22 +++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 lib/oauth.c create mode 100644 lib/oauth.h (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index 03fef1ab..441634cd 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 +objects = arc.o base64.o $(EVENT_HANDLER) 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/oauth.c b/lib/oauth.c new file mode 100644 index 00000000..ef303f14 --- /dev/null +++ b/lib/oauth.c @@ -0,0 +1,106 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple OAuth client (consumer) implementation. * +* * +* Copyright 2010 Wilmer van der Gaast * +* * +* 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 +#include +#include +#include +#include "base64.h" +#include "misc.h" +#include "sha1.h" + +#define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" +#define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" +/* How can it be a secret if it's right here in the source code? No clue... */ + +#define HMAC_BLOCK_SIZE 64 + +struct oauth_state +{ +}; + +static char *oauth_sign( const char *method, const char *url, + const char *params, const char *token_secret ) +{ + 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( CONSUMER_SECRET ) + 1 + token_secret ? strlen( token_secret ) : 0; + if( i > HMAC_BLOCK_SIZE ) + { + sha1_init( &sha1 ); + sha1_append( &sha1, CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); + sha1_append( &sha1, "&", 1 ); + if( token_secret ) + sha1_append( &sha1, token_secret, strlen( token_secret ) ); + sha1_finish( &sha1, key ); + } + else + { + g_snprintf( key, HMAC_BLOCK_SIZE + 1, "%s&%s", + CONSUMER_SECRET, 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 it and we're done. */ + return base64_encode( hash, sha1_hash_size ); +} diff --git a/lib/oauth.h b/lib/oauth.h new file mode 100644 index 00000000..160e30f1 --- /dev/null +++ b/lib/oauth.h @@ -0,0 +1,22 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple OAuth client (consumer) implementation. * +* * +* Copyright 2010 Wilmer van der Gaast * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License 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. * +* * +\***************************************************************************/ -- cgit v1.2.3 From e9eaee6eb50cd566d699b61a4d643f64800b488b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 19:56:53 +0100 Subject: constified. --- lib/url.c | 2 +- lib/url.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/url.c b/lib/url.c index de9966b4..9e330f8c 100644 --- a/lib/url.c +++ b/lib/url.c @@ -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; diff --git a/lib/url.h b/lib/url.h index 8c038c91..55107ad2 100644 --- a/lib/url.h +++ b/lib/url.h @@ -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 ); -- cgit v1.2.3 From da2efd4eaaf6a87afc35402d96d98d8001e43af7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 19:57:06 +0100 Subject: Some HTTP stuff. Via gdb I can make this request a token. --- lib/oauth.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 212 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index ef303f14..6240d514 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -25,9 +25,11 @@ #include #include #include +#include "http_client.h" #include "base64.h" #include "misc.h" #include "sha1.h" +#include "url.h" #define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" #define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" @@ -35,8 +37,18 @@ #define HMAC_BLOCK_SIZE 64 -struct oauth_state +struct oauth_info; +typedef void (*oauth_cb)( struct oauth_info * ); + +struct oauth_info { + oauth_cb func; + void *data; + + struct http_request *http; + + char *auth_params; + char *token; }; static char *oauth_sign( const char *method, const char *url, @@ -51,19 +63,19 @@ static char *oauth_sign( const char *method, const char *url, /* 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( CONSUMER_SECRET ) + 1 + token_secret ? strlen( token_secret ) : 0; + i = strlen( CONSUMER_SECRET ) + 1 + ( token_secret ? strlen( token_secret ) : 0 ); if( i > HMAC_BLOCK_SIZE ) { sha1_init( &sha1 ); - sha1_append( &sha1, CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); - sha1_append( &sha1, "&", 1 ); + sha1_append( &sha1, (uint8_t*) CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); + sha1_append( &sha1, (uint8_t*) "&", 1 ); if( token_secret ) - sha1_append( &sha1, token_secret, strlen( token_secret ) ); + sha1_append( &sha1, (uint8_t*) token_secret, strlen( token_secret ) ); sha1_finish( &sha1, key ); } else { - g_snprintf( key, HMAC_BLOCK_SIZE + 1, "%s&%s", + g_snprintf( (gchar*) key, HMAC_BLOCK_SIZE + 1, "%s&%s", CONSUMER_SECRET, token_secret ? : "" ); } @@ -104,3 +116,197 @@ static char *oauth_sign( const char *method, const char *url, /* base64_encode it and we're done. */ return base64_encode( hash, sha1_hash_size ); } + +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 ); + } + } +} + +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; +} + +GSList *oauth_params_parse( char *in ) +{ + GSList *ret = NULL; + char *amp, *eq; + + while( in && *in ) + { + eq = strchr( in, '=' ); + if( !eq ) + break; + + *eq = '\0'; + if( ( amp = strchr( eq + 1, '&' ) ) ) + *amp = '\0'; + + oauth_params_add( &ret, in, eq + 1 ); + + *eq = '='; + if( amp == NULL ) + break; + + *amp = '&'; + in = amp + 1; + } + + return ret; +} + +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 ) + { + g_string_append( str, l->data ); + if( l->next ) + g_string_append_c( str, '&' ); + } + + return g_string_free( str, FALSE ); +} + +static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, void *data ) +{ + 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_params_set( ¶ms, "oauth_consumer_key", CONSUMER_KEY ); + oauth_params_set( ¶ms, "oauth_signature_method", "HMAC-SHA1" ); + + s = g_strdup_printf( "%d", (int) time( NULL ) ); + oauth_params_set( ¶ms, "oauth_timestamp", s ); + g_free( s ); + + s = oauth_nonce(); + oauth_params_set( ¶ms, "oauth_nonce", s ); + g_free( s ); + + oauth_params_set( ¶ms, "oauth_version", "1.0" ); + oauth_params_set( ¶ms, "oauth_callback", "oob" ); + + params_s = oauth_params_string( params ); + oauth_params_free( params_ ); + + s = oauth_sign( "POST", url, params_s, NULL ); + s = g_realloc( s, strlen( s ) * 3 + 1 ); + http_encode( s ); + + 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, data ); + g_free( s ); + + return req; +} + +void oauth_request_token_done( struct http_request *req ); + +void *oauth_request_token( const char *url, oauth_cb func, void *data ) +{ + struct oauth_info *st = g_new0( struct oauth_info, 1 ); + + st->func = func; + st->data = data; + + return oauth_post_request( url, NULL, oauth_request_token_done, st ); +} + +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; + + st->auth_params = g_strdup( req->reply_body ); + params = oauth_params_parse( st->auth_params ); + st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); + oauth_params_free( ¶ms ); + } + + st->func( st ); +} -- cgit v1.2.3 From 346dfd940c1439f6113c3cf80340791567de5d25 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Apr 2010 20:22:02 +0100 Subject: oauth_access_token() added. I managed to increase the counter on http://twitter.com/oauth_clients/details/127170 . \o/ --- lib/oauth.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 6240d514..bc3974c1 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -252,7 +252,6 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f g_free( s ); oauth_params_set( ¶ms, "oauth_version", "1.0" ); - oauth_params_set( ¶ms, "oauth_callback", "oob" ); params_s = oauth_params_string( params ); oauth_params_free( params_ ); @@ -280,19 +279,22 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f return req; } -void oauth_request_token_done( struct http_request *req ); +static void oauth_request_token_done( struct http_request *req ); void *oauth_request_token( const char *url, oauth_cb func, void *data ) { struct oauth_info *st = g_new0( struct oauth_info, 1 ); + GSList *params = NULL; st->func = func; st->data = data; + oauth_params_add( ¶ms, "oauth_callback", "oob" ); + return oauth_post_request( url, NULL, oauth_request_token_done, st ); } -void oauth_request_token_done( struct http_request *req ) +static void oauth_request_token_done( struct http_request *req ) { struct oauth_info *st = req->data; @@ -308,5 +310,21 @@ void oauth_request_token_done( struct http_request *req ) oauth_params_free( ¶ms ); } - st->func( st ); + //st->func( st ); +} + +static void oauth_access_token_done( struct http_request *req ); + +void *oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) +{ + GSList *params = NULL; + + oauth_params_add( ¶ms, "oauth_token", st->token ); + oauth_params_add( ¶ms, "oauth_verifier", pin ); + + return oauth_post_request( url, ¶ms, oauth_access_token_done, st ); +} + +static void oauth_access_token_done( struct http_request *req ) +{ } -- cgit v1.2.3 From b2bc25c4483f4c2b419d91d479f38c3f07ef4226 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 00:21:00 +0100 Subject: Added a function that generates an OAuth Authorization: HTTP header. --- lib/oauth.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index bc3974c1..c166d96a 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -49,6 +49,8 @@ struct oauth_info char *auth_params; char *token; + + char *access_token; }; static char *oauth_sign( const char *method, const char *url, @@ -146,7 +148,7 @@ void oauth_params_del( GSList **params, const char *key ) ((char*)l->data)[key_len] == '=' ) { g_free( l->data ); - *params = g_slist_remove( *params, l ); + *params = g_slist_remove( *params, l->data ); } } } @@ -224,6 +226,24 @@ char *oauth_params_string( GSList *params ) return g_string_free( str, FALSE ); } +static void oauth_add_default_params( GSList **params ) +{ + char *s; + + oauth_params_set( params, "oauth_consumer_key", 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, void *data ) { GSList *params = NULL; @@ -240,18 +260,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f if( params_ ) params = *params_; - oauth_params_set( ¶ms, "oauth_consumer_key", CONSUMER_KEY ); - oauth_params_set( ¶ms, "oauth_signature_method", "HMAC-SHA1" ); - - s = g_strdup_printf( "%d", (int) time( NULL ) ); - oauth_params_set( ¶ms, "oauth_timestamp", s ); - g_free( s ); - - s = oauth_nonce(); - oauth_params_set( ¶ms, "oauth_nonce", s ); - g_free( s ); - - oauth_params_set( ¶ms, "oauth_version", "1.0" ); + oauth_add_default_params( ¶ms ); params_s = oauth_params_string( params ); oauth_params_free( params_ ); @@ -327,4 +336,61 @@ void *oauth_access_token( const char *url, const char *pin, struct oauth_info *s static void oauth_access_token_done( struct http_request *req ) { + struct oauth_info *st = req->data; + + if( req->status_code == 200 ) + st->access_token = g_strdup( req->reply_body ); + + //st->func( st ); +} + +char *oauth_http_header( char *access_token, const char *method, const char *url ) +{ + GSList *params, *l; + char *token_secret, *sig, *params_s; + GString *ret = NULL; + + params = oauth_params_parse( access_token ); + if( params == NULL ) + goto err; + token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); + if( token_secret == NULL ) + goto err; + oauth_params_del( ¶ms, "oauth_token_secret" ); + + oauth_add_default_params( ¶ms ); + + params_s = oauth_params_string( params ); + sig = oauth_sign( method, url, params_s, token_secret ); + g_free( params_s ); + sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); + http_encode( sig ); + + 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, "\", " ); + } + + g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); + +err: + oauth_params_free( ¶ms ); + g_free( sig ); + g_free( token_secret ); + + return ret ? g_string_free( ret, FALSE ) : NULL; } -- cgit v1.2.3 From 508c340d1d12d3ca932001d7ee1dea1a4c81bf02 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 01:42:37 +0100 Subject: Successfully posted a tweet! Twitter's tricky. It returns vars (user_id, screen_name) in the access token that, the way I read the spec, should be included in all subsequent queries. However, stuff only started to work when I dropped those vars. This code's definitely not pretty ATM. Need to clean up now that it actually works. --- lib/oauth.c | 40 +++++++++++++++++++++++----------------- lib/oauth.h | 2 ++ 2 files changed, 25 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index c166d96a..6731fe7e 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -174,9 +174,8 @@ const char *oauth_params_get( GSList **params, const char *key ) return NULL; } -GSList *oauth_params_parse( char *in ) +static void oauth_params_parse( GSList **params, char *in ) { - GSList *ret = NULL; char *amp, *eq; while( in && *in ) @@ -189,7 +188,7 @@ GSList *oauth_params_parse( char *in ) if( ( amp = strchr( eq + 1, '&' ) ) ) *amp = '\0'; - oauth_params_add( &ret, in, eq + 1 ); + oauth_params_add( params, in, eq + 1 ); *eq = '='; if( amp == NULL ) @@ -198,8 +197,6 @@ GSList *oauth_params_parse( char *in ) *amp = '&'; in = amp + 1; } - - return ret; } void oauth_params_free( GSList **params ) @@ -311,10 +308,10 @@ static void oauth_request_token_done( struct http_request *req ) if( req->status_code == 200 ) { - GSList *params; + GSList *params = NULL; st->auth_params = g_strdup( req->reply_body ); - params = oauth_params_parse( st->auth_params ); + oauth_params_parse( ¶ms, st->auth_params ); st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); oauth_params_free( ¶ms ); } @@ -344,13 +341,13 @@ static void oauth_access_token_done( struct http_request *req ) //st->func( st ); } -char *oauth_http_header( char *access_token, const char *method, const char *url ) +char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) { - GSList *params, *l; - char *token_secret, *sig, *params_s; + GSList *params = NULL, *l; + char *token_secret, *sig, *params_s, *s; GString *ret = NULL; - params = oauth_params_parse( access_token ); + oauth_params_parse( ¶ms, access_token ); if( params == NULL ) goto err; token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); @@ -360,12 +357,6 @@ char *oauth_http_header( char *access_token, const char *method, const char *url oauth_add_default_params( ¶ms ); - params_s = oauth_params_string( params ); - sig = oauth_sign( method, url, params_s, token_secret ); - g_free( params_s ); - sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); - http_encode( sig ); - ret = g_string_new( "OAuth " ); for( l = params; l; l = l->next ) { @@ -385,6 +376,21 @@ char *oauth_http_header( char *access_token, const char *method, const char *url g_string_append( ret, "\", " ); } + if( args ) + oauth_params_parse( ¶ms, args ); + if( ( s = strchr( url, '?' ) ) ) + { + s = g_strdup( s + 1 ); + oauth_params_parse( ¶ms, s + 1 ); + g_free( s ); + } + + params_s = oauth_params_string( params ); + sig = oauth_sign( method, url, params_s, token_secret ); + g_free( params_s ); + sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); + http_encode( sig ); + g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); err: diff --git a/lib/oauth.h b/lib/oauth.h index 160e30f1..98e58c64 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -20,3 +20,5 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * * \***************************************************************************/ + +char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ); -- cgit v1.2.3 From acba168df90f28fdaee26bc09d621364878dd099 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 22:20:09 +0100 Subject: Moving two public OAuth functions into the header file. --- lib/oauth.c | 17 +---------------- lib/oauth.h | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 6731fe7e..7897b760 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -30,6 +30,7 @@ #include "misc.h" #include "sha1.h" #include "url.h" +#include "oauth.h" #define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" #define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" @@ -37,22 +38,6 @@ #define HMAC_BLOCK_SIZE 64 -struct oauth_info; -typedef void (*oauth_cb)( struct oauth_info * ); - -struct oauth_info -{ - oauth_cb func; - void *data; - - struct http_request *http; - - char *auth_params; - char *token; - - char *access_token; -}; - static char *oauth_sign( const char *method, const char *url, const char *params, const char *token_secret ) { diff --git a/lib/oauth.h b/lib/oauth.h index 98e58c64..91696d83 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -21,4 +21,39 @@ * * \***************************************************************************/ +/* http://oauth.net/core/1.0a/ */ + +struct oauth_info; +typedef void (*oauth_cb)( struct oauth_info * ); + +struct oauth_info +{ + oauth_cb func; + void *data; + + struct http_request *http; + + char *auth_params; + char *token; + + char *access_token; +}; + +/* 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. */ +void *oauth_request_token( const char *url, 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. */ +void *oauth_access_token( const char *url, 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( char *access_token, const char *method, const char *url, char *args ); -- cgit v1.2.3 From 713d6111cd754ff9eae4cfa1e6de82c9824d16db Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 22:50:48 +0100 Subject: Twitter module now generates authorize URLs. --- lib/oauth.c | 8 ++++---- lib/oauth.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 7897b760..828d713d 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -297,11 +297,11 @@ static void oauth_request_token_done( struct http_request *req ) st->auth_params = g_strdup( req->reply_body ); oauth_params_parse( ¶ms, st->auth_params ); - st->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); + st->request_token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) ); oauth_params_free( ¶ms ); } - //st->func( st ); + st->func( st ); } static void oauth_access_token_done( struct http_request *req ); @@ -310,7 +310,7 @@ void *oauth_access_token( const char *url, const char *pin, struct oauth_info *s { GSList *params = NULL; - oauth_params_add( ¶ms, "oauth_token", st->token ); + oauth_params_add( ¶ms, "oauth_token", st->request_token ); oauth_params_add( ¶ms, "oauth_verifier", pin ); return oauth_post_request( url, ¶ms, oauth_access_token_done, st ); @@ -323,7 +323,7 @@ static void oauth_access_token_done( struct http_request *req ) if( req->status_code == 200 ) st->access_token = g_strdup( req->reply_body ); - //st->func( st ); + st->func( st ); } char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) diff --git a/lib/oauth.h b/lib/oauth.h index 91696d83..4151d73f 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -34,7 +34,7 @@ struct oauth_info struct http_request *http; char *auth_params; - char *token; + char *request_token; char *access_token; }; -- cgit v1.2.3 From c42e8b907817fc76df4dc3b48d85858555102654 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 23:40:11 +0100 Subject: OAuth, it lives! --- lib/oauth.c | 14 +++++++++++++- lib/oauth.h | 9 +++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 828d713d..7f60f4f5 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -301,6 +301,7 @@ static void oauth_request_token_done( struct http_request *req ) oauth_params_free( ¶ms ); } + st->stage = OAUTH_REQUEST_TOKEN; st->func( st ); } @@ -321,8 +322,19 @@ static void oauth_access_token_done( struct http_request *req ) struct oauth_info *st = req->data; if( req->status_code == 200 ) - st->access_token = g_strdup( req->reply_body ); + { + GSList *params; + const char *token, *token_secret; + + oauth_params_parse( ¶ms, req->reply_body ); + token = oauth_params_get( ¶ms, "oauth_token" ); + token_secret = oauth_params_get( ¶ms, "oauth_token_secret" ); + st->access_token = g_strdup_printf( + "oauth_token=%s&oauth_token_secret=%s", token, token_secret ); + oauth_params_free( ¶ms ); + } + st->stage = OAUTH_ACCESS_TOKEN; st->func( st ); } diff --git a/lib/oauth.h b/lib/oauth.h index 4151d73f..30486b98 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -26,8 +26,17 @@ struct oauth_info; typedef void (*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; + oauth_cb func; void *data; -- cgit v1.2.3 From 78a2f1e4ac9aeb2c041059eb7a9578d34bd60d50 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 23:47:35 +0100 Subject: Escaping in oauth_nonce(). Not sure if the escaping is entirely right ATM... :-( --- lib/oauth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 7f60f4f5..9a372082 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -107,9 +107,14 @@ static char *oauth_sign( const char *method, const char *url, static char *oauth_nonce() { unsigned char bytes[9]; + char *ret; random_bytes( bytes, sizeof( bytes ) ); - return base64_encode( bytes, sizeof( bytes ) ); + ret = base64_encode( bytes, sizeof( bytes ) ); + ret = g_realloc( ret, strlen( ret ) * 3 + 1 ); + http_encode( ret ); + + return ret; } void oauth_params_add( GSList **params, const char *key, const char *value ) -- cgit v1.2.3 From ee84bdbc2510fa09bd0f67e14d06e69c2626d0f1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 27 Apr 2010 23:11:11 +0100 Subject: The escaping, I fixed it for you. More expensive code this way and most of the vars don't need escaping. But this shouldn't be so fragile anymore. --- lib/oauth.c | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 9a372082..0ab94c96 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -100,21 +100,21 @@ static char *oauth_sign( const char *method, const char *url, sha1_append( &sha1, hash, sha1_hash_size ); sha1_finish( &sha1, hash ); - /* base64_encode it and we're done. */ - return base64_encode( hash, sha1_hash_size ); + /* 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]; - char *ret; random_bytes( bytes, sizeof( bytes ) ); - ret = base64_encode( bytes, sizeof( bytes ) ); - ret = g_realloc( ret, strlen( ret ) * 3 + 1 ); - http_encode( ret ); - - return ret; + return base64_encode( bytes, sizeof( bytes ) ); } void oauth_params_add( GSList **params, const char *key, const char *value ) @@ -166,7 +166,7 @@ const char *oauth_params_get( GSList **params, const char *key ) static void oauth_params_parse( GSList **params, char *in ) { - char *amp, *eq; + char *amp, *eq, *s; while( in && *in ) { @@ -178,7 +178,10 @@ static void oauth_params_parse( GSList **params, char *in ) if( ( amp = strchr( eq + 1, '&' ) ) ) *amp = '\0'; - oauth_params_add( params, in, eq + 1 ); + s = g_strdup( eq + 1 ); + http_decode( s ); + oauth_params_add( params, in, s ); + g_free( s ); *eq = '='; if( amp == NULL ) @@ -205,7 +208,15 @@ char *oauth_params_string( GSList *params ) for( l = params; l; l = l->next ) { - g_string_append( str, l->data ); + 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, '&' ); } @@ -253,9 +264,6 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f oauth_params_free( params_ ); s = oauth_sign( "POST", url, params_s, NULL ); - s = g_realloc( s, strlen( s ) * 3 + 1 ); - http_encode( s ); - post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); g_free( params_s ); g_free( s ); @@ -389,11 +397,8 @@ char *oauth_http_header( char *access_token, const char *method, const char *url params_s = oauth_params_string( params ); sig = oauth_sign( method, url, params_s, token_secret ); - g_free( params_s ); - sig = g_realloc( sig, strlen( sig ) * 3 + 1 ); - http_encode( sig ); - g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); + g_free( params_s ); err: oauth_params_free( ¶ms ); -- cgit v1.2.3 From 18dbb20242719f7537ad1a18a9a3befa2eefd502 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 27 Apr 2010 23:42:07 +0100 Subject: Valgrind cleanup. --- lib/oauth.c | 40 ++++++++++++++++++++++++++++++++++------ lib/oauth.h | 12 +++++++++--- 2 files changed, 43 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 0ab94c96..97017043 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -224,6 +224,17 @@ char *oauth_params_string( GSList *params ) return g_string_free( str, FALSE ); } +void oauth_info_free( struct oauth_info *info ) +{ + if( info ) + { + g_free( info->auth_params ); + g_free( info->request_token ); + g_free( info->access_token ); + g_free( info ); + } +} + static void oauth_add_default_params( GSList **params ) { char *s; @@ -285,7 +296,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f static void oauth_request_token_done( struct http_request *req ); -void *oauth_request_token( const char *url, oauth_cb func, void *data ) +struct oauth_info *oauth_request_token( const char *url, oauth_cb func, void *data ) { struct oauth_info *st = g_new0( struct oauth_info, 1 ); GSList *params = NULL; @@ -295,7 +306,13 @@ void *oauth_request_token( const char *url, oauth_cb func, void *data ) oauth_params_add( ¶ms, "oauth_callback", "oob" ); - return oauth_post_request( url, NULL, oauth_request_token_done, st ); + if( !oauth_post_request( url, ¶ms, oauth_request_token_done, st ) ) + { + oauth_info_free( st ); + return NULL; + } + + return st; } static void oauth_request_token_done( struct http_request *req ) @@ -315,19 +332,21 @@ static void oauth_request_token_done( struct http_request *req ) } st->stage = OAUTH_REQUEST_TOKEN; - st->func( st ); + if( !st->func( st ) ) + oauth_info_free( st ); } static void oauth_access_token_done( struct http_request *req ); -void *oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) +void oauth_access_token( const char *url, 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( url, ¶ms, oauth_access_token_done, st ); + if( !oauth_post_request( url, ¶ms, oauth_access_token_done, st ) ) + oauth_info_free( st ); } static void oauth_access_token_done( struct http_request *req ) @@ -336,7 +355,7 @@ static void oauth_access_token_done( struct http_request *req ) if( req->status_code == 200 ) { - GSList *params; + GSList *params = NULL; const char *token, *token_secret; oauth_params_parse( ¶ms, req->reply_body ); @@ -349,6 +368,7 @@ static void oauth_access_token_done( struct http_request *req ) st->stage = OAUTH_ACCESS_TOKEN; st->func( st ); + oauth_info_free( st ); } char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) @@ -357,9 +377,12 @@ char *oauth_http_header( char *access_token, const char *method, const char *url char *token_secret, *sig, *params_s, *s; GString *ret = NULL; + /* First, get the two pieces of info from the access token that we need. */ oauth_params_parse( ¶ms, access_token ); if( params == NULL ) goto err; + + /* Pick out the token secret, we shouldn't include it but use it for signing. */ token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); if( token_secret == NULL ) goto err; @@ -367,6 +390,7 @@ char *oauth_http_header( char *access_token, const char *method, const char *url oauth_add_default_params( ¶ms ); + /* Start building the OAuth header. 'key="value", '... */ ret = g_string_new( "OAuth " ); for( l = params; l; l = l->next ) { @@ -386,6 +410,9 @@ char *oauth_http_header( char *access_token, const char *method, const char *url 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, '?' ) ) ) @@ -395,6 +422,7 @@ char *oauth_http_header( char *access_token, const char *method, const char *url g_free( s ); } + /* Append the signature and we're done! */ params_s = oauth_params_string( params ); sig = oauth_sign( method, url, params_s, token_secret ); g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); diff --git a/lib/oauth.h b/lib/oauth.h index 30486b98..a61650cc 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -24,7 +24,10 @@ /* http://oauth.net/core/1.0a/ */ struct oauth_info; -typedef void (*oauth_cb)( 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 { @@ -52,13 +55,13 @@ struct oauth_info 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. */ -void *oauth_request_token( const char *url, oauth_cb func, void *data ); +struct oauth_info *oauth_request_token( const char *url, 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. */ -void *oauth_access_token( const char *url, const char *pin, struct oauth_info *st ); +void oauth_access_token( const char *url, 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 @@ -66,3 +69,6 @@ void *oauth_access_token( const char *url, const char *pin, struct oauth_info *s whatever's going to be in the POST body of the request. GET args will automatically be grabbed from url. */ char *oauth_http_header( char *access_token, 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 ); -- cgit v1.2.3 From 0bff877cf81754283eac52ee49fedc3872cd0d4c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 27 Apr 2010 23:49:58 +0100 Subject: Valgrind-clean now. And decent handling of errors (wrong PIN). --- lib/oauth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 97017043..9fb83922 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -272,7 +272,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f oauth_add_default_params( ¶ms ); params_s = oauth_params_string( params ); - oauth_params_free( params_ ); + oauth_params_free( ¶ms ); s = oauth_sign( "POST", url, params_s, NULL ); post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s ); @@ -353,6 +353,8 @@ 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; -- cgit v1.2.3 From 85ef57f94436f23447c0d8603b52977824381854 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 30 Apr 2010 23:53:29 +0100 Subject: NULL-initialize two vars that weren't and should. --- lib/oauth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 9fb83922..4a465a2f 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -376,7 +376,7 @@ static void oauth_access_token_done( struct http_request *req ) char *oauth_http_header( char *access_token, const char *method, const char *url, char *args ) { GSList *params = NULL, *l; - char *token_secret, *sig, *params_s, *s; + char *token_secret = NULL, *sig = NULL, *params_s, *s; GString *ret = NULL; /* First, get the two pieces of info from the access token that we need. */ -- cgit v1.2.3 From c2ecadc08daa5163f4c90aef36de0e33d0d44f16 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 May 2010 14:53:59 +0100 Subject: Cleaned up OAuth stuff: consumer key/secret should *not* be in lib/oauth.c. Keep it in the Twitter module, and use the oauth_info struct through the whole session to keep all this together. --- lib/oauth.c | 91 ++++++++++++++++++++++++++----------------------------------- lib/oauth.h | 22 +++++++++++---- 2 files changed, 56 insertions(+), 57 deletions(-) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 4a465a2f..4c93cbf4 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -32,14 +32,10 @@ #include "url.h" #include "oauth.h" -#define CONSUMER_KEY "xsDNKJuNZYkZyMcu914uEA" -#define CONSUMER_SECRET "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo" -/* How can it be a secret if it's right here in the source code? No clue... */ - #define HMAC_BLOCK_SIZE 64 static char *oauth_sign( const char *method, const char *url, - const char *params, const char *token_secret ) + const char *params, struct oauth_info *oi ) { sha1_state_t sha1; uint8_t hash[sha1_hash_size]; @@ -50,20 +46,20 @@ static char *oauth_sign( const char *method, const char *url, /* 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( CONSUMER_SECRET ) + 1 + ( token_secret ? strlen( token_secret ) : 0 ); + 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*) CONSUMER_SECRET, strlen( CONSUMER_SECRET ) ); + sha1_append( &sha1, (uint8_t*) oi->sp->consumer_secret, strlen( oi->sp->consumer_secret ) ); sha1_append( &sha1, (uint8_t*) "&", 1 ); - if( token_secret ) - sha1_append( &sha1, (uint8_t*) token_secret, strlen( token_secret ) ); + 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", - CONSUMER_SECRET, token_secret ? : "" ); + oi->sp->consumer_secret, oi->token_secret ? : "" ); } /* Inner part: H(K XOR 0x36, text) */ @@ -228,18 +224,19 @@ void oauth_info_free( struct oauth_info *info ) { if( info ) { - g_free( info->auth_params ); + g_free( info->auth_url ); g_free( info->request_token ); - g_free( info->access_token ); + g_free( info->token ); + g_free( info->token_secret ); g_free( info ); } } -static void oauth_add_default_params( GSList **params ) +static void oauth_add_default_params( GSList **params, struct oauth_service *sp ) { char *s; - oauth_params_set( params, "oauth_consumer_key", CONSUMER_KEY ); + 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 ) ); @@ -253,7 +250,7 @@ static void oauth_add_default_params( GSList **params ) oauth_params_set( params, "oauth_version", "1.0" ); } -static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, void *data ) +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; @@ -269,12 +266,12 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f if( params_ ) params = *params_; - oauth_add_default_params( ¶ms ); + oauth_add_default_params( ¶ms, oi->sp ); params_s = oauth_params_string( params ); oauth_params_free( ¶ms ); - s = oauth_sign( "POST", url, params_s, NULL ); + 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 ); @@ -288,7 +285,7 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f g_free( post ); req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS, - s, func, data ); + s, func, oi ); g_free( s ); return req; @@ -296,17 +293,18 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f static void oauth_request_token_done( struct http_request *req ); -struct oauth_info *oauth_request_token( const char *url, oauth_cb func, void *data ) +struct oauth_info *oauth_request_token( 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( url, ¶ms, oauth_request_token_done, st ) ) + if( !oauth_post_request( sp->url_request_token, ¶ms, oauth_request_token_done, st ) ) { oauth_info_free( st ); return NULL; @@ -325,28 +323,26 @@ static void oauth_request_token_done( struct http_request *req ) { GSList *params = NULL; - st->auth_params = g_strdup( req->reply_body ); - oauth_params_parse( ¶ms, st->auth_params ); + 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; - if( !st->func( st ) ) - oauth_info_free( st ); + st->func( st ); } static void oauth_access_token_done( struct http_request *req ); -void oauth_access_token( const char *url, const char *pin, struct oauth_info *st ) +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 ); - if( !oauth_post_request( url, ¶ms, oauth_access_token_done, st ) ) - oauth_info_free( st ); + 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 ) @@ -358,39 +354,32 @@ static void oauth_access_token_done( struct http_request *req ) if( req->status_code == 200 ) { GSList *params = NULL; - const char *token, *token_secret; oauth_params_parse( ¶ms, req->reply_body ); - token = oauth_params_get( ¶ms, "oauth_token" ); - token_secret = oauth_params_get( ¶ms, "oauth_token_secret" ); - st->access_token = g_strdup_printf( - "oauth_token=%s&oauth_token_secret=%s", token, token_secret ); + 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; - st->func( st ); - oauth_info_free( st ); + 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( char *access_token, const char *method, const char *url, char *args ) +char *oauth_http_header( struct oauth_info *oi, const char *method, const char *url, char *args ) { GSList *params = NULL, *l; - char *token_secret = NULL, *sig = NULL, *params_s, *s; + char *sig = NULL, *params_s, *s; GString *ret = NULL; - /* First, get the two pieces of info from the access token that we need. */ - oauth_params_parse( ¶ms, access_token ); - if( params == NULL ) - goto err; - - /* Pick out the token secret, we shouldn't include it but use it for signing. */ - token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) ); - if( token_secret == NULL ) - goto err; - oauth_params_del( ¶ms, "oauth_token_secret" ); - - oauth_add_default_params( ¶ms ); + 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 " ); @@ -420,20 +409,18 @@ char *oauth_http_header( char *access_token, const char *method, const char *url if( ( s = strchr( url, '?' ) ) ) { s = g_strdup( s + 1 ); - oauth_params_parse( ¶ms, 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, token_secret ); + sig = oauth_sign( method, url, params_s, oi ); g_string_append_printf( ret, "oauth_signature=\"%s\"", sig ); g_free( params_s ); -err: oauth_params_free( ¶ms ); g_free( sig ); - g_free( token_secret ); return ret ? g_string_free( ret, FALSE ) : NULL; } diff --git a/lib/oauth.h b/lib/oauth.h index a61650cc..849375be 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -39,36 +39,48 @@ typedef enum struct oauth_info { oauth_stage_t stage; + struct oauth_service *sp; oauth_cb func; void *data; struct http_request *http; - char *auth_params; + char *auth_url; char *request_token; - char *access_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 char *url, oauth_cb func, void *data ); +struct oauth_info *oauth_request_token( 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. */ -void oauth_access_token( const char *url, const char *pin, struct oauth_info *st ); +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( char *access_token, const char *method, const char *url, char *args ); +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 ); -- cgit v1.2.3 From f4b0911d037c02f8b9190518b5efda4368dcc25b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 May 2010 15:10:32 +0100 Subject: Save the credentials again. --- lib/oauth.c | 27 +++++++++++++++++++++++++++ lib/oauth.h | 4 ++++ 2 files changed, 31 insertions(+) (limited to 'lib') diff --git a/lib/oauth.c b/lib/oauth.c index 4c93cbf4..8012c37a 100644 --- a/lib/oauth.c +++ b/lib/oauth.c @@ -424,3 +424,30 @@ char *oauth_http_header( struct oauth_info *oi, const char *method, const char * 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, 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 index 849375be..6b51dc2c 100644 --- a/lib/oauth.h +++ b/lib/oauth.h @@ -84,3 +84,7 @@ char *oauth_http_header( struct oauth_info *oi, const char *method, const char * /* 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, struct oauth_service *sp ); -- cgit v1.2.3 From 3742fb6ae99c2e5e25cff272a154b9834866e8f9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 12 May 2010 00:27:11 +0100 Subject: Implement some kind of ignorant awareness of XML namespaces: Enough to not break backward compatibility (hopefully) but be able to pick up inappropriate uses of XML namespace prefixes. Main reason for this change: Fix XMPP typing notification compatibility with GMail. --- lib/xmltree.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'lib') 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; } -- cgit v1.2.3 From f60079b74053a53da3720b992c603fddf75ff1dd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 25 May 2010 23:26:54 +0100 Subject: Allow one to run the configure script from a different directory and put all build files in there. I need this to properly make Debian package variants (i.e. libpurple and native). --- lib/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/Makefile b/lib/Makefile index b686f886..8fd9b19e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -7,6 +7,9 @@ ### DEFINITIONS -include ../Makefile.settings +ifdef SRCDIR +SRCDIR := $(SRCDIR)lib/ +endif # [SH] Program variables 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 @@ -36,6 +39,6 @@ lib.o: $(objects) $(subdirs) $(objects): ../Makefile.settings Makefile -$(objects): %.o: %.c +$(objects): %.o: $(SRCDIR)%.c @echo '*' Compiling $< @$(CC) -c $(CFLAGS) $< -o $@ -- cgit v1.2.3