/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
* Copyright 2002-2004 Wilmer van der Gaast and others *
\********************************************************************/
/* MSN module - Some tables with useful data */
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License with
the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
if not, write to the Free Software Foundation, Inc., 59 Temple Place,
Suite 330, Boston, MA 02111-1307 USA
*/
#include "nogaim.h"
#include "msn.h"
const struct msn_away_state msn_away_state_list[] =
{
{ 0, "NLN", "Available" },
{ 1, "BSY", "Busy" },
{ 3, "IDL", "Idle" },
{ 5, "BRB", "Be Right Back" },
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//***************************************************************************\
* *
* BitlBee - An IRC to IM gateway *
* Simple OAuth client (consumer) implementation. *
* *
* Copyright 2010 Wilmer van der Gaast <wilmer@gaast.net> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation, version *
* 2.1. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library; if not, write to the Free Software Foundation, *
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
* *
\***************************************************************************/
#include <glib.h>
#include <gmodule.h>
#include <stdlib.h>
#include <string.h>
#include "http_client.h"
#include "base64.h"
#include "misc.h"
#include "sha1.h"
#include "url.h"
#include "oauth.h"
#define HMAC_BLOCK_SIZE 64
static char *oauth_sign( const char *method, const char *url,
const char *params, struct oauth_info *oi )
{
uint8_t hash[sha1_hash_size];
GString *payload = g_string_new( "" );
char *key;
char *s;
key = g_strdup_printf( "%s&%s", oi->sp->consumer_secret, oi->token_secret ? oi->token_secret : "" );
g_string_append_printf( payload, "%s&", method );
s = g_new0( char, strlen( url ) * 3 + 1 );
strcpy( s, url );
http_encode( s );
g_string_append_printf( payload, "%s&", s );
g_free( s );
s = g_new0( char, strlen( params ) * 3 + 1 );
strcpy( s, params );
http_encode( s );
g_string_append( payload, s );
g_free( s );
sha1_hmac( key, 0, payload->str, 0, hash );
g_free( key );
g_string_free( payload, TRUE );
/* 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[21];
char *ret = g_new0( char, sizeof( bytes) / 3 * 4 + 1 );
random_bytes( bytes, sizeof( bytes ) );
base64_encode_real( bytes, sizeof( bytes), (unsigned char*) ret, "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0A" );
return ret;
}
void oauth_params_add( GSList **params, const char *key, const char *value )
{
char *item;
if( !key || !value )
return;
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;
if( params == NULL )
return;
for( l = *params; l; l = n )
{
n = l->next;
if( strncmp( (char*) l->data, key, key_len ) == 0 &&
((char*)l->data)[key_len] == '=' )
{
g_free( l->data );
*params = g_slist_remove( *params, l->data );
}
}
}
void oauth_params_set( GSList **params, const char *key, const char *value )
{
oauth_params_del( params, key );
oauth_params_add( params, key, value );
}
const char *oauth_params_get( GSList **params, const char *key )
{
int key_len = strlen( key );
GSList *l;
if( params == NULL )
return NULL;
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;
}
void oauth_params_parse( GSList **params, char *in )
{
char *amp, *eq, *s;
while( in && *in )
{
eq = strchr( in, '=' );
if( !eq )
break;
*eq = '\0';
if( ( amp = strchr( eq + 1, '&' ) ) )
*amp = '\0';
s = g_strdup( eq + 1 );
http_decode( s );
oauth_params_add( params, in, s );
g_free( s );
*eq = '=';
if( amp == NULL )
break;
*amp = '&';
in = amp + 1;
}
}
void oauth_params_free( GSList **params )
{
while( params && *params )
{
g_free( (*params)->data );
*params = g_slist_remove( *params, (*params)->data );
}
}
char *oauth_params_string( GSList *params )
{
GSList *l;
GString *str = g_string_new( "" );
for( l = params; l; l = l->next )
{
char *s, *eq;
s = g_malloc( strlen( l->data ) * 3 + 1 );
strcpy( s, l->data );
if( ( eq = strchr( s, '=' ) ) )
http_encode( eq + 1 );
g_string_append( str, s );
g_free( s );
if( l->next )
g_string_append_c( str, '&' );
}
return g_string_free( str, FALSE );
}
void oauth_info_free( struct oauth_info *info )
{
if( info )
{
g_free( info->auth_url );
g_free( info->request_token );
g_free( info->token );
g_free( info->token_secret );
oauth_params_free( &info->params );
g_free( info );
}
}
static void oauth_add_default_params( GSList **params, const struct oauth_service *sp )
{
char *s;
oauth_params_set( params, "oauth_consumer_key", sp->consumer_key );
oauth_params_set( params, "oauth_signature_method", "HMAC-SHA1" );
s = g_strdup_printf( "%d", (int) time( NULL ) );
oauth_params_set( params, "oauth_timestamp", s );
g_free( s );
s = oauth_nonce();
oauth_params_set( params, "oauth_nonce", s );
g_free( s );
oauth_params_set( params, "oauth_version", "1.0" );
}
static void *oauth_post_request( const char *url, GSList **params_, http_input_function func, struct oauth_info *oi )
{
GSList *params = NULL;
char *s, *params_s, *post;
void *req;
url_t url_p;
if( !url_set( &url_p, url ) )
{
oauth_params_free( params_ );
return NULL;
}
if( params_ )
params = *params_;
oauth_add_default_params( ¶ms, oi->sp );
params_s = oauth_params_string( params );
oauth_params_free( ¶ms );
s = oauth_sign( "POST", url, params_s, oi );
post = g_strdup_printf( "%s&oauth_signature=%s", params_s, s );
g_free( params_s );
g_free( s );
s = g_strdup_printf( "POST %s HTTP/1.0\r\n"
"Host: %s\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: %zd\r\n"
"Connection: close\r\n"
"\r\n"
"%s", url_p.file, url_p.host, strlen( post ), post );
g_free( post );
req = http_dorequest( url_p.host, url_p.port, url_p.proto == PROTO_HTTPS,
s, func, oi );
g_free( s );
return req;
}
static void oauth_request_token_done( struct http_request *req );
struct oauth_info *oauth_request_token( const struct oauth_service *sp, oauth_cb func, void *data )
{
struct oauth_info *st = g_new0( struct oauth_info, 1 );
GSList *params = NULL;
st->func = func;
st->data = data;
st->sp = sp;
oauth_params_add( ¶ms, "oauth_callback", "oob" );
if( !oauth_post_request( sp->url_request_token, ¶ms, oauth_request_token_done, st ) )
{
oauth_info_free( st );
return NULL;
}
return st;
}
static void oauth_request_token_done( struct http_request *req )
{
struct oauth_info *st = req->data;
st->http = req;
if( req->status_code == 200 )
{
GSList *params = NULL;
st->auth_url = g_strdup_printf( "%s?%s", st->sp->url_authorize, req->reply_body );
oauth_params_parse( ¶ms, req->reply_body );
st->request_token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) );
st->token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) );
oauth_params_free( ¶ms );
}
st->stage = OAUTH_REQUEST_TOKEN;
st->func( st );
}
static void oauth_access_token_done( struct http_request *req );
gboolean oauth_access_token( const char *pin, struct oauth_info *st )
{
GSList *params = NULL;
oauth_params_add( ¶ms, "oauth_token", st->request_token );
oauth_params_add( ¶ms, "oauth_verifier", pin );
return oauth_post_request( st->sp->url_access_token, ¶ms, oauth_access_token_done, st ) != NULL;
}
static void oauth_access_token_done( struct http_request *req )
{
struct oauth_info *st = req->data;
st->http = req;
if( req->status_code == 200 )
{
oauth_params_parse( &st->params, req->reply_body );
st->token = g_strdup( oauth_params_get( &st->params, "oauth_token" ) );
g_free( st->token_secret );
st->token_secret = g_strdup( oauth_params_get( &st->params, "oauth_token_secret" ) );
}
st->stage = OAUTH_ACCESS_TOKEN;
if( st->func( st ) )
{
/* Don't need these anymore, but keep the rest. */
g_free( st->auth_url );
st->auth_url = NULL;
g_free( st->request_token );
st->request_token = NULL;
oauth_params_free( &st->params );
}
}
char *oauth_http_header( struct oauth_info *oi, const char *method, const char *url, char *args )
{
GSList *params = NULL, *l;
char *sig = NULL, *params_s, *s;
GString *ret = NULL;
oauth_params_add( ¶ms, "oauth_token", oi->token );
oauth_add_default_params( ¶ms, oi->sp );
/* Start building the OAuth header. 'key="value", '... */
ret = g_string_new( "OAuth " );
for( l = params; l; l = l->next )
{
char *kv = l->data;
char *eq = strchr( kv, '=' );
char esc[strlen(kv)*3+1];
if( eq == NULL )
break; /* WTF */
strcpy( esc, eq + 1 );
http_encode( esc );
g_string_append_len( ret, kv, eq - kv + 1 );
g_string_append_c( ret, '"' );
g_string_append( ret, esc );
g_string_append( ret, "\", " );
}
/* Now, before generating the signature, add GET/POST arguments to params
since they should be included in the base signature string (but not in
the HTTP header). */
if( args )
oauth_params_parse( ¶ms, args );
if( ( s = strchr( url, '?' ) ) )
{
s = g_strdup( s + 1 );
oauth_params_parse( ¶ms, s );
g_free( s );
}
/* Append the signature and we're done! */
params_s = oauth_params_string( params );
sig = oauth_sign( method, url, params_s, oi );
g_string_append_printf( ret, "oauth_signature=\"%s\"", sig );
g_free( params_s );
oauth_params_free( ¶ms );
g_free( sig );
return ret ? g_string_free( ret, FALSE ) : NULL;
}
char *oauth_to_string( struct oauth_info *oi )
{
GSList *params = NULL;
char *ret;
oauth_params_add( ¶ms, "oauth_token", oi->token );
oauth_params_add( ¶ms, "oauth_token_secret", oi->token_secret );
ret = oauth_params_string( params );
oauth_params_free( ¶ms );
return ret;
}
struct oauth_info *oauth_from_string( char *in, const struct oauth_service *sp )
{
struct oauth_info *oi = g_new0( struct oauth_info, 1 );
GSList *params = NULL;
oauth_params_parse( ¶ms, in );
oi->token = g_strdup( oauth_params_get( ¶ms, "oauth_token" ) );
oi->token_secret = g_strdup( oauth_params_get( ¶ms, "oauth_token_secret" ) );
oauth_params_free( ¶ms );
oi->sp = sp;
return oi;
}