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. --- protocols/twitter/twitter.c | 7 ++++++- protocols/twitter/twitter.h | 1 + protocols/twitter/twitter_http.c | 18 ++++++++++++++++-- protocols/twitter/twitter_http.h | 2 +- protocols/twitter/twitter_lib.c | 10 +++++----- 5 files changed, 29 insertions(+), 9 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 726c7cb1..ead03c56 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -81,7 +81,10 @@ static void twitter_login( account_t *acc ) twitter_connections = g_slist_append( twitter_connections, ic ); td->user = acc->user; - td->pass = acc->pass; + if( strstr( acc->pass, "oauth_token=" ) == NULL ) + td->pass = g_strdup( acc->pass ); + else + td->oauth = g_strdup( acc->pass ); td->home_timeline_id = 0; ic->proto_data = td; @@ -118,6 +121,8 @@ static void twitter_logout( struct im_connection *ic ) if( td ) { + g_free( td->pass ); + g_free( td->oauth ); g_free( td ); } diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 88caa104..16620e1d 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -36,6 +36,7 @@ struct twitter_data { char* user; char* pass; + char* oauth; guint64 home_timeline_id; gint main_loop_id; struct groupchat *home_timeline_gc; diff --git a/protocols/twitter/twitter_http.c b/protocols/twitter/twitter_http.c index 3632140f..93e315fa 100644 --- a/protocols/twitter/twitter_http.c +++ b/protocols/twitter/twitter_http.c @@ -34,6 +34,7 @@ #include "url.h" #include "misc.h" #include "base64.h" +#include "oauth.h" #include #include @@ -44,7 +45,7 @@ char *twitter_url_append(char *url, char *key, char* value); * Do a request. * This is actually pretty generic function... Perhaps it should move to the lib/http_client.c */ -void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post, char* user, char* pass, char** arguments, int arguments_len) +void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post, char* user, char* pass, char* oauth_token, char** arguments, int arguments_len) { url_t *url = g_new0( url_t, 1 ); char *tmp; @@ -109,7 +110,20 @@ void *twitter_http(char *url_string, http_input_function func, gpointer data, in is_post ? "POST" : "GET", url->file, url->host ); // If a pass and user are given we append them to the request. - if (userpass_base64) + if (oauth_token) + { + char *full_header; + + full_header = oauth_http_header(oauth_token, + is_post ? "POST" : "GET", + url_string, url_arguments); + + tmp = g_strdup_printf("%sAuthorization: %s\r\n", request, full_header); + g_free(request); + g_free(full_header); + request = tmp; + } + else if (userpass_base64) { tmp = g_strdup_printf("%sAuthorization: Basic %s\r\n", request, userpass_base64); g_free(request); diff --git a/protocols/twitter/twitter_http.h b/protocols/twitter/twitter_http.h index ec4a0b7c..1e29fb99 100644 --- a/protocols/twitter/twitter_http.h +++ b/protocols/twitter/twitter_http.h @@ -28,7 +28,7 @@ #include "http_client.h" void *twitter_http(char *url_string, http_input_function func, gpointer data, int is_post, - char* user, char* pass, char** arguments, int arguments_len); + char* user, char* pass, char *oauth_token, char** arguments, int arguments_len); #endif //_TWITTER_HTTP_H diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index d58afd73..c91f8bbf 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -129,7 +129,7 @@ void twitter_get_friends_ids(struct im_connection *ic, int next_cursor) char* args[2]; args[0] = "cursor"; args[1] = g_strdup_printf ("%d", next_cursor); - twitter_http(TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, td->user, td->pass, args, 2); + twitter_http(TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, td->user, td->pass, td->oauth, args, 2); g_free(args[1]); } @@ -395,7 +395,7 @@ void twitter_get_home_timeline(struct im_connection *ic, int next_cursor) args[3] = g_strdup_printf ("%llu", (long long unsigned int) td->home_timeline_id); } - twitter_http(TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, td->user, td->pass, args, td->home_timeline_id ? 4 : 2); + twitter_http(TWITTER_HOME_TIMELINE_URL, twitter_http_get_home_timeline, ic, 0, td->user, td->pass, td->oauth, args, td->home_timeline_id ? 4 : 2); g_free(args[1]); if (td->home_timeline_id) { @@ -619,7 +619,7 @@ void twitter_get_statuses_friends(struct im_connection *ic, int next_cursor) args[0] = "cursor"; args[1] = g_strdup_printf ("%d", next_cursor); - twitter_http(TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, td->user, td->pass, args, 2); + twitter_http(TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, td->user, td->pass, td->oauth, args, 2); g_free(args[1]); } @@ -653,7 +653,7 @@ void twitter_post_status(struct im_connection *ic, char* msg) char* args[2]; args[0] = "status"; args[1] = msg; - twitter_http(TWITTER_STATUS_UPDATE_URL, twitter_http_post_status, ic, 1, td->user, td->pass, args, 2); + twitter_http(TWITTER_STATUS_UPDATE_URL, twitter_http_post_status, ic, 1, td->user, td->pass, td->oauth, args, 2); // g_free(args[1]); } @@ -671,7 +671,7 @@ void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg) args[2] = "text"; args[3] = msg; // Use the same callback as for twitter_post_status, since it does basically the same. - twitter_http(TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post_status, ic, 1, td->user, td->pass, args, 4); + twitter_http(TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post_status, ic, 1, td->user, td->pass, td->oauth, args, 4); // g_free(args[1]); // g_free(args[3]); } -- 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. --- protocols/twitter/twitter.c | 64 +++++++++++++++++++++++++++++++++++---------- protocols/twitter/twitter.h | 4 +++ 2 files changed, 54 insertions(+), 14 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index ead03c56..e2a5986b 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -22,6 +22,7 @@ ****************************************************************************/ #include "nogaim.h" +#include "oauth.h" #include "twitter.h" #include "twitter_http.h" #include "twitter_lib.h" @@ -50,6 +51,44 @@ gboolean twitter_main_loop(gpointer data, gint fd, b_input_condition cond) return (ic->flags & OPT_LOGGED_IN) == OPT_LOGGED_IN; } +static void twitter_main_loop_start( struct im_connection *ic ) +{ + struct twitter_data *td = ic->proto_data; + + imcb_log( ic, "Connecting to Twitter" ); + + // Run this once. After this queue the main loop function. + twitter_main_loop(ic, -1, 0); + + // Queue the main_loop + // Save the return value, so we can remove the timeout on logout. + td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic); +} + +static void twitter_oauth_callback( struct oauth_info *info ); + +static void twitter_oauth_start( struct im_connection *ic ) +{ + oauth_request_token( TWITTER_OAUTH_REQUEST_TOKEN, twitter_oauth_callback, ic ); +} + +static void twitter_oauth_callback( struct oauth_info *info ) +{ + struct im_connection *ic = info->data; + + if( info->request_token && info->access_token == NULL ) + { + char name[strlen(ic->acc->user)+9], *msg; + + sprintf( name, "twitter_%s", ic->acc->user ); + msg = g_strdup_printf( "To finish OAuth authentication, please visit " + "%s?%s and respond with the resulting PIN code.", + TWITTER_OAUTH_AUTHORIZE, info->auth_params ); + imcb_buddy_msg( ic, name, msg, 0, 0 ); + g_free( msg ); + } +} + static char *set_eval_mode( set_t *set, char *value ) { if( g_strcasecmp( value, "one" ) == 0 || @@ -66,6 +105,8 @@ static void twitter_init( account_t *acc ) s = set_add( &acc->set, "mode", "one", set_eval_mode, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; + + s = set_add( &acc->set, "oauth", "true", set_eval_bool, acc ); } /** @@ -79,28 +120,23 @@ static void twitter_login( account_t *acc ) char name[strlen(acc->user)+9]; twitter_connections = g_slist_append( twitter_connections, ic ); - + ic->proto_data = td; + td->user = acc->user; - if( strstr( acc->pass, "oauth_token=" ) == NULL ) + if( !set_getbool( &acc->set, "oauth" ) ) td->pass = g_strdup( acc->pass ); - else + else if( strstr( acc->pass, "oauth_token=" ) ) td->oauth = g_strdup( acc->pass ); td->home_timeline_id = 0; - - ic->proto_data = td; - - imcb_log( ic, "Connecting to Twitter" ); - - // Run this once. After this queue the main loop function. - twitter_main_loop(ic, -1, 0); - - // Queue the main_loop - // Save the return value, so we can remove the timeout on logout. - td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic); sprintf( name, "twitter_%s", acc->user ); imcb_add_buddy( ic, name, NULL ); imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL ); + + if( td->pass || td->oauth ) + twitter_main_loop_start( ic ); + else + twitter_oauth_start( ic ); } /** diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 16620e1d..f1937bd0 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -50,4 +50,8 @@ struct twitter_data */ GSList *twitter_connections; +#define TWITTER_OAUTH_REQUEST_TOKEN "http://api.twitter.com/oauth/request_token" +#define TWITTER_OAUTH_ACCESS_TOKEN "http://api.twitter.com/oauth/access_token" +#define TWITTER_OAUTH_AUTHORIZE "http://api.twitter.com/oauth/authorize" + #endif //_TWITTER_H -- 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! --- protocols/twitter/twitter.c | 39 ++++++++++++++++++++++++++++++++++++--- protocols/twitter/twitter.h | 1 + 2 files changed, 37 insertions(+), 3 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index e2a5986b..eb05d9d5 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -69,17 +69,29 @@ static void twitter_oauth_callback( struct oauth_info *info ); static void twitter_oauth_start( struct im_connection *ic ) { + imcb_log( ic, "Requesting OAuth request token" ); + oauth_request_token( TWITTER_OAUTH_REQUEST_TOKEN, twitter_oauth_callback, ic ); } static void twitter_oauth_callback( struct oauth_info *info ) { struct im_connection *ic = info->data; + struct twitter_data *td = ic->proto_data; - if( info->request_token && info->access_token == NULL ) + if( info->stage == OAUTH_REQUEST_TOKEN ) { char name[strlen(ic->acc->user)+9], *msg; + if( info->request_token == NULL ) + { + imcb_error( ic, "OAuth error: %s", info->http->status_string ); + imc_logout( ic, TRUE ); + return; + } + + td->oauth_info = info; + sprintf( name, "twitter_%s", ic->acc->user ); msg = g_strdup_printf( "To finish OAuth authentication, please visit " "%s?%s and respond with the resulting PIN code.", @@ -87,6 +99,19 @@ static void twitter_oauth_callback( struct oauth_info *info ) imcb_buddy_msg( ic, name, msg, 0, 0 ); g_free( msg ); } + else if( info->stage == OAUTH_ACCESS_TOKEN ) + { + if( info->access_token == NULL ) + { + imcb_error( ic, "OAuth error: %s", info->http->status_string ); + imc_logout( ic, TRUE ); + return; + } + + td->oauth = g_strdup( info->access_token ); + + twitter_main_loop_start( ic ); + } } static char *set_eval_mode( set_t *set, char *value ) @@ -170,12 +195,20 @@ static void twitter_logout( struct im_connection *ic ) */ static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away ) { + struct twitter_data *td = ic->proto_data; + if (g_strncasecmp(who, "twitter_", 8) == 0 && g_strcasecmp(who + 8, ic->acc->user) == 0) - twitter_post_status(ic, message); + { + if( set_getbool( &ic->acc->set, "oauth" ) && td->oauth == NULL ) + oauth_access_token( TWITTER_OAUTH_ACCESS_TOKEN, message, td->oauth_info ); + else + twitter_post_status(ic, message); + } else + { twitter_direct_messages_new(ic, who, message); - + } return( 0 ); } diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index f1937bd0..9c046b66 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -37,6 +37,7 @@ struct twitter_data char* user; char* pass; char* oauth; + struct oauth_info *oauth_info; guint64 home_timeline_id; gint main_loop_id; struct groupchat *home_timeline_gc; -- cgit v1.2.3 From 288b215ca64d09ea6a49cf9ff1fcc7682b7607ec Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Apr 2010 23:50:25 +0100 Subject: Save the OAuth token in the acct structs so it doesn't have to be rerequested every time. --- protocols/twitter/twitter.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index eb05d9d5..54bee2f1 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -110,6 +110,11 @@ static void twitter_oauth_callback( struct oauth_info *info ) td->oauth = g_strdup( info->access_token ); + /* IM mods didn't do this so far and it's ugly but I should + be able to get away with it... */ + g_free( ic->acc->pass ); + ic->acc->pass = g_strdup( info->access_token ); + twitter_main_loop_start( ic ); } } -- 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. --- protocols/twitter/twitter.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'protocols') diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index 54bee2f1..8ea1a56e 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -65,20 +65,27 @@ static void twitter_main_loop_start( struct im_connection *ic ) td->main_loop_id = b_timeout_add(60000, twitter_main_loop, ic); } -static void twitter_oauth_callback( struct oauth_info *info ); +static gboolean twitter_oauth_callback( struct oauth_info *info ); static void twitter_oauth_start( struct im_connection *ic ) { + struct twitter_data *td = ic->proto_data; + imcb_log( ic, "Requesting OAuth request token" ); - oauth_request_token( TWITTER_OAUTH_REQUEST_TOKEN, twitter_oauth_callback, ic ); + td->oauth_info = oauth_request_token( + TWITTER_OAUTH_REQUEST_TOKEN, twitter_oauth_callback, ic ); } -static void twitter_oauth_callback( struct oauth_info *info ) +static gboolean twitter_oauth_callback( struct oauth_info *info ) { struct im_connection *ic = info->data; - struct twitter_data *td = ic->proto_data; + struct twitter_data *td; + if( !g_slist_find( twitter_connections, ic ) ) + return FALSE; + + td = ic->proto_data; if( info->stage == OAUTH_REQUEST_TOKEN ) { char name[strlen(ic->acc->user)+9], *msg; @@ -87,11 +94,9 @@ static void twitter_oauth_callback( struct oauth_info *info ) { imcb_error( ic, "OAuth error: %s", info->http->status_string ); imc_logout( ic, TRUE ); - return; + return FALSE; } - td->oauth_info = info; - sprintf( name, "twitter_%s", ic->acc->user ); msg = g_strdup_printf( "To finish OAuth authentication, please visit " "%s?%s and respond with the resulting PIN code.", @@ -105,7 +110,7 @@ static void twitter_oauth_callback( struct oauth_info *info ) { imcb_error( ic, "OAuth error: %s", info->http->status_string ); imc_logout( ic, TRUE ); - return; + return FALSE; } td->oauth = g_strdup( info->access_token ); @@ -117,6 +122,8 @@ static void twitter_oauth_callback( struct oauth_info *info ) twitter_main_loop_start( ic ); } + + return TRUE; } static char *set_eval_mode( set_t *set, char *value ) @@ -187,6 +194,8 @@ static void twitter_logout( struct im_connection *ic ) if( td ) { + oauth_info_free( td->oauth_info ); + g_free( td->pass ); g_free( td->oauth ); g_free( td ); @@ -205,8 +214,11 @@ static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message if (g_strncasecmp(who, "twitter_", 8) == 0 && g_strcasecmp(who + 8, ic->acc->user) == 0) { - if( set_getbool( &ic->acc->set, "oauth" ) && td->oauth == NULL ) + if( set_getbool( &ic->acc->set, "oauth" ) && td->oauth_info ) + { oauth_access_token( TWITTER_OAUTH_ACCESS_TOKEN, message, td->oauth_info ); + td->oauth_info = NULL; + } else twitter_post_status(ic, message); } -- cgit v1.2.3