aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rwxr-xr-xconfigure2
-rw-r--r--lib/http_client.c253
-rw-r--r--lib/http_client.h6
-rw-r--r--lib/oauth.c1
-rw-r--r--lib/oauth2.c76
-rw-r--r--lib/oauth2.h5
-rw-r--r--lib/proxy.c2
-rw-r--r--lib/ssl_nss.c4
-rw-r--r--nick.c3
-rw-r--r--protocols/jabber/sasl.c6
-rw-r--r--protocols/oscar/oscar.c6
-rw-r--r--protocols/skype/README83
-rw-r--r--protocols/skype/skype.c15
-rw-r--r--protocols/skype/skyped.py2
-rw-r--r--protocols/skype/t/away-set-bitlbee.mock10
-rw-r--r--protocols/skype/t/away-set-skyped.mock20
-rw-r--r--protocols/skype/t/group-add-bitlbee.mock14
-rw-r--r--protocols/skype/t/group-add-skyped.mock38
-rw-r--r--protocols/skype/t/groupchat-msg-bitlbee.mock11
-rw-r--r--protocols/skype/t/groupchat-msg-skyped.mock60
-rw-r--r--protocols/skype/t/groupchat-topic-bitlbee.mock10
-rw-r--r--protocols/skype/t/groupchat-topic-skyped.mock60
-rwxr-xr-xprotocols/skype/test.py12
-rw-r--r--protocols/twitter/twitter.c15
-rw-r--r--protocols/twitter/twitter_http.c2
-rw-r--r--protocols/twitter/twitter_lib.h2
-rw-r--r--storage_xml.c2
28 files changed, 529 insertions, 193 deletions
diff --git a/Makefile b/Makefile
index b64337a5..e1dc397b 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@
# Program variables
objects = bitlbee.o dcc.o help.o ipc.o irc.o irc_im.o irc_channel.o irc_commands.o irc_send.o irc_user.o irc_util.o nick.o $(OTR_BI) query.o root_commands.o set.o storage.o $(STORAGE_OBJS)
-headers = bitlbee.h commands.h conf.h config.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/account.h protocols/bee.h protocols/ft.h protocols/nogaim.h
+headers = bitlbee.h commands.h conf.h config.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/json.h lib/json_util.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/account.h protocols/bee.h protocols/ft.h protocols/nogaim.h
subdirs = lib protocols
ifeq ($(TARGET),i586-mingw32msvc)
diff --git a/configure b/configure
index 10d7c1bd..1e3a2421 100755
--- a/configure
+++ b/configure
@@ -210,7 +210,7 @@ fi
echo CFLAGS=$CFLAGS $CPPFLAGS >> Makefile.settings
echo CFLAGS+=-I${srcdir} -I${srcdir}/lib -I${srcdir}/protocols -I. >> Makefile.settings
-echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings
+echo CFLAGS+=-DHAVE_CONFIG_H -D_GNU_SOURCE >> Makefile.settings
if [ -n "$CC" ]; then
CC=$CC
diff --git a/lib/http_client.c b/lib/http_client.c
index b384e1f0..b509c839 100644
--- a/lib/http_client.c
+++ b/lib/http_client.c
@@ -1,7 +1,7 @@
/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
- * Copyright 2002-2012 Wilmer van der Gaast and others *
+ * Copyright 2002-2013 Wilmer van der Gaast and others *
\********************************************************************/
/* HTTP(S) module */
@@ -68,6 +68,7 @@ struct http_request *http_dorequest( char *host, int port, int ssl, char *reques
req->request = g_strdup( request );
req->request_length = strlen( request );
req->redir_ttl = 3;
+ req->content_length = -1;
if( getenv( "BITLBEE_DEBUG" ) )
printf( "About to send HTTP request:\n%s\n", req->request );
@@ -95,7 +96,6 @@ struct http_request *http_dorequest_url( char *url_string, http_input_function f
request = g_strdup_printf( "GET %s HTTP/1.0\r\n"
"Host: %s\r\n"
- "Connection: close\r\n"
"User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n"
"\r\n", url->file, url->host );
@@ -192,14 +192,21 @@ static gboolean http_ssl_connected( gpointer data, int returncode, void *source,
return http_connected( data, req->fd, cond );
}
+typedef enum {
+ CR_OK,
+ CR_EOF,
+ CR_ERROR,
+ CR_ABORT,
+} http_ret_t;
+
static gboolean http_handle_headers( struct http_request *req );
+static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len );
+static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len );
static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond )
{
struct http_request *req = data;
char buffer[4096];
- char *s;
- size_t content_length;
int st;
if( req->inpa > 0 )
@@ -243,53 +250,25 @@ static gboolean http_incoming_data( gpointer data, int source, b_input_condition
}
}
- if( st > 0 && !req->sbuf )
+ if( st > 0 )
{
- req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 );
- memcpy( req->reply_headers + req->bytes_read, buffer, st );
- req->bytes_read += st;
+ http_ret_t c;
- st = 0;
- }
-
- if( st >= 0 && ( req->flags & HTTPC_STREAMING ) )
- {
- if( !req->reply_body &&
- ( strstr( req->reply_headers, "\r\n\r\n" ) ||
- strstr( req->reply_headers, "\n\n" ) ) )
- {
- size_t hlen;
-
- /* We've now received all headers, so process them once
- before we start feeding back data. */
- if( !http_handle_headers( req ) )
- return FALSE;
-
- hlen = req->reply_body - req->reply_headers;
-
- req->sblen = req->bytes_read - hlen;
- req->sbuf = g_memdup( req->reply_body, req->sblen + 1 );
- req->reply_headers = g_realloc( req->reply_headers, hlen + 1 );
-
- req->reply_body = req->sbuf;
- }
-
- if( st > 0 )
- {
- int pos = req->reply_body - req->sbuf;
- req->sbuf = g_realloc( req->sbuf, req->sblen + st + 1 );
- memcpy( req->sbuf + req->sblen, buffer, st );
- req->bytes_read += st;
- req->sblen += st;
- req->sbuf[req->sblen] = '\0';
- req->reply_body = req->sbuf + pos;
- req->body_size = req->sblen - pos;
- }
+ if( req->flags & HTTPC_CHUNKED )
+ c = http_process_chunked_data( req, buffer, st );
+ else
+ c = http_process_data( req, buffer, st );
- if( req->reply_body )
- req->func( req );
+ if( c == CR_EOF )
+ goto eof;
+ else if( c == CR_ERROR || c == CR_ABORT )
+ return FALSE;
}
+ if( req->content_length != -1 &&
+ req->body_size >= req->content_length )
+ goto eof;
+
if( ssl_pending( req->ssl ) )
return http_incoming_data( data, source, cond );
@@ -310,14 +289,6 @@ eof:
req->status_string = g_strdup( "Empty HTTP reply" );
goto cleanup;
}
-
- if( !( req->flags & HTTPC_STREAMING ) )
- {
- /* Returns FALSE if we were redirected, in which case we should abort
- and not run any callback yet. */
- if( !http_handle_headers( req ) )
- return FALSE;
- }
cleanup:
if( req->ssl )
@@ -325,17 +296,12 @@ cleanup:
else
closesocket( req->fd );
- if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) &&
- sscanf( s, "%zd", &content_length ) == 1 )
+ if( req->body_size < req->content_length )
{
- if( content_length < req->body_size )
- {
- req->status_code = -1;
- g_free( req->status_string );
- req->status_string = g_strdup( "Response truncated" );
- }
+ req->status_code = -1;
+ g_free( req->status_string );
+ req->status_string = g_strdup( "Response truncated" );
}
- g_free( s );
if( getenv( "BITLBEE_DEBUG" ) && req )
printf( "Finishing HTTP request with status: %s\n",
@@ -346,11 +312,120 @@ cleanup:
return FALSE;
}
+static http_ret_t http_process_chunked_data( struct http_request *req, const char *buffer, int len )
+{
+ char *chunk, *eos, *s;
+
+ if( len < 0 )
+ return TRUE;
+
+ if( len > 0 )
+ {
+ req->cbuf = g_realloc( req->cbuf, req->cblen + len + 1 );
+ memcpy( req->cbuf + req->cblen, buffer, len );
+ req->cblen += len;
+ req->cbuf[req->cblen] = '\0';
+ }
+
+ /* Turns out writing a proper chunked-encoding state machine is not
+ that simple. :-( I've tested this one feeding it byte by byte so
+ I hope it's solid now. */
+ chunk = req->cbuf;
+ eos = req->cbuf + req->cblen;
+ while( TRUE )
+ {
+ int clen = 0;
+
+ /* Might be a \r\n from the last chunk. */
+ s = chunk;
+ while( isspace( *s ) )
+ s ++;
+ /* Chunk length. Might be incomplete. */
+ if( s < eos && sscanf( s, "%x", &clen ) != 1 )
+ return CR_ERROR;
+ while( isxdigit( *s ) )
+ s ++;
+
+ /* If we read anything here, it *must* be \r\n. */
+ if( strncmp( s, "\r\n", MIN( 2, eos - s ) ) != 0 )
+ return CR_ERROR;
+ s += 2;
+
+ if( s >= eos )
+ break;
+
+ /* 0-length chunk means end of response. */
+ if( clen == 0 )
+ return CR_EOF;
+
+ /* Wait for the whole chunk to arrive. */
+ if( s + clen > eos )
+ break;
+ if( http_process_data( req, s, clen ) != CR_OK )
+ return CR_ABORT;
+
+ chunk = s + clen;
+ }
+
+ if( chunk != req->cbuf )
+ {
+ req->cblen = eos - chunk;
+ s = g_memdup( chunk, req->cblen + 1 );
+ g_free( req->cbuf );
+ req->cbuf = s;
+ }
+
+ return CR_OK;
+}
+
+static http_ret_t http_process_data( struct http_request *req, const char *buffer, int len )
+{
+ if( len <= 0 )
+ return CR_OK;
+
+ if( !req->reply_body )
+ {
+ req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + len + 1 );
+ memcpy( req->reply_headers + req->bytes_read, buffer, len );
+ req->bytes_read += len;
+ req->reply_headers[req->bytes_read] = '\0';
+
+ if( strstr( req->reply_headers, "\r\n\r\n" ) ||
+ strstr( req->reply_headers, "\n\n" ) )
+ {
+ /* We've now received all headers. Look for something
+ interesting. */
+ if( !http_handle_headers( req ) )
+ return CR_ABORT;
+
+ /* Start parsing the body as chunked if required. */
+ if( req->flags & HTTPC_CHUNKED )
+ return http_process_chunked_data( req, NULL, 0 );
+ }
+ }
+ else
+ {
+ int pos = req->reply_body - req->sbuf;
+ req->sbuf = g_realloc( req->sbuf, req->sblen + len + 1 );
+ memcpy( req->sbuf + req->sblen, buffer, len );
+ req->bytes_read += len;
+ req->sblen += len;
+ req->sbuf[req->sblen] = '\0';
+ req->reply_body = req->sbuf + pos;
+ req->body_size = req->sblen - pos;
+ }
+
+ if( ( req->flags & HTTPC_STREAMING ) && req->reply_body )
+ req->func( req );
+
+ return CR_OK;
+}
+
/* Splits headers and body. Checks result code, in case of 300s it'll handle
redirects. If this returns FALSE, don't call any callbacks! */
static gboolean http_handle_headers( struct http_request *req )
{
- char *end1, *end2;
+ char *end1, *end2, *s;
int evil_server = 0;
/* Zero termination is very convenient. */
@@ -376,7 +451,7 @@ static gboolean http_handle_headers( struct http_request *req )
return TRUE;
}
- *end1 = 0;
+ *end1 = '\0';
if( getenv( "BITLBEE_DEBUG" ) )
printf( "HTTP response headers:\n%s\n", req->reply_headers );
@@ -386,7 +461,10 @@ static gboolean http_handle_headers( struct http_request *req )
else
req->reply_body = end1 + 2;
- req->body_size = req->reply_headers + req->bytes_read - req->reply_body;
+ /* Separately allocated space for headers and body. */
+ req->sblen = req->body_size = req->reply_headers + req->bytes_read - req->reply_body;
+ req->sbuf = req->reply_body = g_memdup( req->reply_body, req->body_size + 1 );
+ req->reply_headers = g_realloc( req->reply_headers, end1 - req->reply_headers + 1 );
if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL )
{
@@ -451,7 +529,7 @@ static gboolean http_handle_headers( struct http_request *req )
/* Since we don't cache the servername, and since we
don't need this yet anyway, I won't implement it. */
- req->status_string = g_strdup( "Can't handle recursive redirects" );
+ req->status_string = g_strdup( "Can't handle relative redirects" );
return TRUE;
}
@@ -459,7 +537,7 @@ static gboolean http_handle_headers( struct http_request *req )
{
/* A whole URL */
url_t *url;
- char *s;
+ char *s, *version, *headers;
const char *new_method;
s = strstr( loc, "\r\n" );
@@ -487,6 +565,7 @@ static gboolean http_handle_headers( struct http_request *req )
g_free( url );
return TRUE;
}
+ headers = s;
/* More or less HTTP/1.0 compliant, from my reading of RFC 2616.
Always perform a GET request unless we received a 301. 303 was
@@ -506,9 +585,19 @@ static gboolean http_handle_headers( struct http_request *req )
/* 301 de-facto should stay POST, 307 specifally RFC 2616#10.3.8 */
new_method = "POST";
+ if( ( version = strstr( req->request, " HTTP/" ) ) &&
+ ( s = strstr( version, "\r\n" ) ) )
+ {
+ version ++;
+ version = g_strndup( version, s - version );
+ }
+ else
+ version = g_strdup( "HTTP/1.0" );
+
/* Okay, this isn't fun! We have to rebuild the request... :-( */
- new_request = g_strdup_printf( "%s %s HTTP/1.0\r\nHost: %s%s",
- new_method, url->file, url->host, s );
+ new_request = g_strdup_printf( "%s %s %s\r\nHost: %s%s",
+ new_method, url->file, version,
+ url->host, headers );
new_host = g_strdup( url->host );
new_port = url->port;
@@ -520,6 +609,7 @@ static gboolean http_handle_headers( struct http_request *req )
s[4] = '\0';
g_free( url );
+ g_free( version );
}
if( req->ssl )
@@ -556,13 +646,35 @@ static gboolean http_handle_headers( struct http_request *req )
g_free( req->request );
g_free( req->reply_headers );
+ g_free( req->sbuf );
req->request = new_request;
req->request_length = strlen( new_request );
req->bytes_read = req->bytes_written = req->inpa = 0;
req->reply_headers = req->reply_body = NULL;
+ req->sbuf = req->cbuf = NULL;
+ req->sblen = req->cblen = 0;
return FALSE;
}
+
+ if( ( s = get_rfc822_header( req->reply_headers, "Content-Length", 0 ) ) &&
+ sscanf( s, "%d", &req->content_length ) != 1 )
+ req->content_length = -1;
+ g_free( s );
+
+ if( ( s = get_rfc822_header( req->reply_headers, "Transfer-Encoding", 0 ) ) )
+ {
+ if( strcasestr( s, "chunked" ) )
+ {
+ req->flags |= HTTPC_CHUNKED;
+ req->cbuf = req->sbuf;
+ req->cblen = req->sblen;
+
+ req->reply_body = req->sbuf = g_strdup( "" );
+ req->body_size = req->sblen = 0;
+ }
+ g_free( s );
+ }
return TRUE;
}
@@ -606,5 +718,6 @@ static void http_free( struct http_request *req )
g_free( req->reply_headers );
g_free( req->status_string );
g_free( req->sbuf );
+ g_free( req->cbuf );
g_free( req );
}
diff --git a/lib/http_client.h b/lib/http_client.h
index ca427118..1b86f228 100644
--- a/lib/http_client.h
+++ b/lib/http_client.h
@@ -41,6 +41,7 @@ typedef enum http_client_flags
{
HTTPC_STREAMING = 1,
HTTPC_EOF = 2,
+ HTTPC_CHUNKED = 4,
/* Let's reserve 0x1000000+ for lib users. */
} http_client_flags_t;
@@ -76,10 +77,15 @@ struct http_request
int inpa;
int bytes_written;
int bytes_read;
+ int content_length; /* "Content-Length:" header or -1 */
/* Used in streaming mode. Caller should read from reply_body. */
char *sbuf;
size_t sblen;
+
+ /* Chunked encoding only. Raw chunked stream is decoded from here. */
+ char *cbuf;
+ size_t cblen;
};
/* The _url variant is probably more useful than the raw version. The raw
diff --git a/lib/oauth.c b/lib/oauth.c
index 04949e1b..c78b4a43 100644
--- a/lib/oauth.c
+++ b/lib/oauth.c
@@ -261,7 +261,6 @@ static void *oauth_post_request( const char *url, GSList **params_, http_input_f
"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 );
diff --git a/lib/oauth2.c b/lib/oauth2.c
index 6921a6d5..bfd4b143 100644
--- a/lib/oauth2.c
+++ b/lib/oauth2.c
@@ -1,9 +1,9 @@
/***************************************************************************\
* *
* BitlBee - An IRC to IM gateway *
-* Simple OAuth client (consumer) implementation. *
+* Simple OAuth2 client (consumer) implementation. *
* *
-* Copyright 2010-2012 Wilmer van der Gaast <wilmer@gaast.net> *
+* Copyright 2010-2013 Wilmer van der Gaast <wilmer@gaast.net> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -21,11 +21,28 @@
* *
\***************************************************************************/
+/* Out of protest, I should rename this file. OAuth2 is a pathetic joke, and
+ of all things, DEFINITELY NOT A STANDARD. The only thing various OAuth2
+ implementations have in common is that name, wrongfully stolen from
+ a pretty nice standard called OAuth 1.0a. That, and the fact that they
+ use JSON. Wait, no, Facebook's version doesn't use JSON. For some of its
+ responses.
+
+ Apparently too many people were too retarded to comprehend the elementary
+ bits of crypto in OAuth 1.0a (took me one afternoon to implement) so
+ the standard was replaced with what comes down to a complicated scheme
+ around what's really just application-specific passwords.
+
+ And then a bunch of mostly incompatible implementations. Great work, guys.
+
+ http://hueniverse.com/2012/07/oauth-2-0-and-the-road-to-hell/ */
+
#include <glib.h>
#include "http_client.h"
#include "oauth2.h"
#include "oauth.h"
#include "json.h"
+#include "json_util.h"
#include "url.h"
char *oauth2_url( const struct oauth2_service *sp )
@@ -78,7 +95,6 @@ int oauth2_access_token( const struct oauth2_service *sp,
"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( args_s ), args_s );
g_free( args_s );
@@ -98,10 +114,35 @@ int oauth2_access_token( const struct oauth2_service *sp,
return req != NULL;
}
+static char* oauth2_parse_error( json_value *e )
+{
+ /* This does a reasonable job with some of the flavours of error
+ responses I've seen. Because apparently it's not standardised. */
+
+ if( e->type == json_object )
+ {
+ /* Facebook style */
+ const char *msg = json_o_str( e, "message" );
+ const char *type = json_o_str( e, "type" );
+ json_value *code_o = json_o_get( e, "code" );
+ int code = 0;
+
+ if( code_o && code_o->type == json_integer )
+ code = code_o->u.integer;
+
+ return g_strdup_printf( "Error %d: %s", code, msg ? msg : type ? type : "Unknown error" );
+ }
+ else if( e->type == json_string )
+ {
+ return g_strdup( e->u.string.ptr );
+ }
+ return NULL;
+}
+
static void oauth2_access_token_done( struct http_request *req )
{
struct oauth2_access_token_data *cb_data = req->data;
- char *atoken = NULL, *rtoken = NULL;
+ char *atoken = NULL, *rtoken = NULL, *error = NULL;
char *content_type;
if( getenv( "BITLBEE_DEBUG" ) && req->reply_body )
@@ -109,24 +150,22 @@ static void oauth2_access_token_done( struct http_request *req )
content_type = get_rfc822_header( req->reply_headers, "Content-Type", 0 );
- if( req->status_code != 200 )
- {
- }
- else if( content_type && strstr( content_type, "application/json" ) )
+ if( content_type && ( strstr( content_type, "application/json" ) ||
+ strstr( content_type, "text/javascript" ) ) )
{
json_value *js = json_parse( req->reply_body );
if( js && js->type == json_object )
{
- int i;
-
- for( i = 0; i < js->u.object.length; i ++ )
+ JSON_O_FOREACH( js, k, v )
{
- if( js->u.object.values[i].value->type != json_string )
+ if( strcmp( k, "error" ) == 0 )
+ error = oauth2_parse_error( v );
+ if( v->type != json_string )
continue;
- if( strcmp( js->u.object.values[i].name, "access_token" ) == 0 )
- atoken = g_strdup( js->u.object.values[i].value->u.string.ptr );
- if( strcmp( js->u.object.values[i].name, "refresh_token" ) == 0 )
- rtoken = g_strdup( js->u.object.values[i].value->u.string.ptr );
+ if( strcmp( k, "access_token" ) == 0 )
+ atoken = g_strdup( v->u.string.ptr );
+ if( strcmp( k, "refresh_token" ) == 0 )
+ rtoken = g_strdup( v->u.string.ptr );
}
}
json_value_free( js );
@@ -143,10 +182,13 @@ static void oauth2_access_token_done( struct http_request *req )
}
if( getenv( "BITLBEE_DEBUG" ) )
printf( "Extracted atoken=%s rtoken=%s\n", atoken, rtoken );
+ if( !atoken && !rtoken && !error )
+ error = g_strdup( "Unusuable response" );
- cb_data->func( cb_data->data, atoken, rtoken );
+ cb_data->func( cb_data->data, atoken, rtoken, error );
g_free( content_type );
g_free( atoken );
g_free( rtoken );
+ g_free( error );
g_free( cb_data );
}
diff --git a/lib/oauth2.h b/lib/oauth2.h
index c8d18963..b3811f49 100644
--- a/lib/oauth2.h
+++ b/lib/oauth2.h
@@ -3,7 +3,7 @@
* BitlBee - An IRC to IM gateway *
* Simple OAuth2 client (consumer) implementation. *
* *
-* Copyright 2010-2011 Wilmer van der Gaast <wilmer@gaast.net> *
+* Copyright 2010-2013 Wilmer van der Gaast <wilmer@gaast.net> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
@@ -24,7 +24,8 @@
/* Implementation mostly based on my experience with writing the previous OAuth
module, and from http://code.google.com/apis/accounts/docs/OAuth2.html . */
-typedef void (*oauth2_token_callback)( gpointer data, const char *atoken, const char *rtoken );
+typedef void (*oauth2_token_callback)( gpointer data, const char *atoken,
+ const char *rtoken, const char *error );
struct oauth2_service
{
diff --git a/lib/proxy.c b/lib/proxy.c
index 3e5c9d49..b6b02d72 100644
--- a/lib/proxy.c
+++ b/lib/proxy.c
@@ -157,7 +157,7 @@ static int proxy_connect_none(const char *host, unsigned short port_, struct PHB
event_debug("bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out);
}
- event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd);
+ event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port_, fd);
if (connect(fd, phb->gai_cur->ai_addr, phb->gai_cur->ai_addrlen) < 0 && !sockerr_again()) {
event_debug( "connect failed: %s\n", strerror(errno));
diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c
index e8de884f..045cd322 100644
--- a/lib/ssl_nss.c
+++ b/lib/ssl_nss.c
@@ -151,7 +151,7 @@ void *ssl_starttls(int fd, char *hostname, gboolean verify,
conn->fd = fd;
conn->func = func;
conn->data = data;
- conn->hostname = hostname;
+ conn->hostname = g_strdup(hostname);
/* For now, SSL verification is globally enabled by setting the cafile
setting in bitlbee.conf. Commented out by default because probably
@@ -295,7 +295,7 @@ void ssl_disconnect(void *conn_)
if (conn->prfd)
PR_Close(conn->prfd);
- g_free(conn->hostname);
+ g_free(conn->hostname);
g_free(conn);
}
diff --git a/nick.c b/nick.c
index 744a6131..65e36e54 100644
--- a/nick.c
+++ b/nick.c
@@ -391,7 +391,8 @@ int nick_lc( irc_t *irc, char *nick )
}
for( i = 0; nick[i]; i ++ )
- nick[i] = tab[(int)nick[i]];
+ if( nick[i] < 0x7f )
+ nick[i] = tab[(int)nick[i]];
return nick_ok( irc, nick );
}
diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c
index 450b5b28..12111fc7 100644
--- a/protocols/jabber/sasl.c
+++ b/protocols/jabber/sasl.c
@@ -482,7 +482,7 @@ static gboolean sasl_oauth2_remove_contact( gpointer data, gint fd, b_input_cond
return FALSE;
}
-static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token );
+static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token, const char *error );
int sasl_oauth2_get_refresh_token( struct im_connection *ic, const char *msg )
{
@@ -513,7 +513,7 @@ int sasl_oauth2_refresh( struct im_connection *ic, const char *refresh_token )
refresh_token, sasl_oauth2_got_token, ic );
}
-static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token )
+static void sasl_oauth2_got_token( gpointer data, const char *access_token, const char *refresh_token, const char *error )
{
struct im_connection *ic = data;
struct jabber_data *jd;
@@ -526,7 +526,7 @@ static void sasl_oauth2_got_token( gpointer data, const char *access_token, cons
if( access_token == NULL )
{
- imcb_error( ic, "OAuth failure (missing access token)" );
+ imcb_error( ic, "OAuth failure (%s)", error );
imc_logout( ic, TRUE );
return;
}
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 05be086d..021792b3 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -980,7 +980,7 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_
char *src;
if (args->icbmflags & AIM_IMFLAGS_UNICODE)
- src = "UNICODEBIG";
+ src = "UCS-2BE";
else
src = "ISO8859-1";
@@ -1768,7 +1768,7 @@ static int oscar_buddy_msg(struct im_connection *ic, char *name, char *message,
if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) {
args.flags |= AIM_IMFLAGS_ISO_8859_1;
len = ret;
- } else if ((ret = do_iconv("UTF-8", "UNICODEBIG", message, s, len, BUF_LONG)) >= 0) {
+ } else if ((ret = do_iconv("UTF-8", "UCS-2BE", message, s, len, BUF_LONG)) >= 0) {
args.flags |= AIM_IMFLAGS_UNICODE;
len = ret;
} else {
@@ -2405,7 +2405,7 @@ void oscar_chat_msg(struct groupchat *c, char *message, int msgflags)
if ((ret = do_iconv("UTF-8", "ISO8859-1", message, s, len, BUF_LONG)) >= 0) {
flags |= AIM_CHATFLAGS_ISO_8859_1;
len = ret;
- } else if ((ret = do_iconv("UTF-8", "UNICODEBIG", message, s, len, BUF_LONG)) >= 0) {
+ } else if ((ret = do_iconv("UTF-8", "UCS-2BE", message, s, len, BUF_LONG)) >= 0) {
flags |= AIM_CHATFLAGS_UNICODE;
len = ret;
} else {
diff --git a/protocols/skype/README b/protocols/skype/README
index b9f22481..f780ca32 100644
--- a/protocols/skype/README
+++ b/protocols/skype/README
@@ -57,90 +57,17 @@ a public server) and/or your IRC client.
NOTE: The order is important. First `skyped` starts Skype. Then `skyped`
connects to Skype, finally BitlBee can connect to `skyped`.
-=== Installing under Frugalware or Debian
+=== Installing
-- Install the necessary packages:
-
-----
-# pacman-g2 -S bitlbee-skype
-----
-
-or
+Either use your package manager to install the Skype plugin, using something
+like:
----
# apt-get install skyped bitlbee-plugin-skype
----
-(the later from the unstable repo)
-
-and you don't have to compile anything manually.
-
-=== Installing under OS X
-
-- Install the necessary packages from ports:
-
-NOTE: You have to edit the Portfile manually to include the install-dev target,
-just append install-dev after install-etc.
-
-----
-# port -v install bitlbee
-----
-
-and you have to install `bitlbee-skype` and `skype4py` from
-source.
-
-=== Installing from source
-
-NOTE: bitlbee-skype by default builds and installs skyped and the
-plugin. In case you just want to install the plugin for a public server
-or you want to use skyped with a public server (like
-`bitlbee1.asnetinc.net`), you don't need both.
-
-- You need the latest stable BitlBee release (unless you want to use a
- public server):
-
-----
-$ wget http://get.bitlbee.org/src/bitlbee-@BITLBEE_VERSION@.tar.gz
-$ tar xf bitlbee-@BITLBEE_VERSION@.tar.gz
-$ cd bitlbee-@BITLBEE_VERSION@
-----
-
-- Now compile and install it:
-
-----
-$ ./configure
-$ make
-# make install install-dev
-----
-
-- To install http://skype4py.sourceforge.net/[Skype4Py] from source
- (unless you want to install the plugin for a public server):
-
-----
-$ tar -zxvf Skype4Py-x.x.x.x.tar.gz
-$ cd Skype4Py-x.x.x.x
-# python setup.py install
-----
-
-- Get the plugin code (in an empty dir, or whereever you want, it does
- not matter):
-
-----
-$ wget http://vmiklos.hu/project/bitlbee-skype/bitlbee-skype-@VERSION@.tar.gz
-$ tar xf bitlbee-skype-@VERSION@.tar.gz
-$ cd bitlbee-skype-@VERSION@
-----
-
-- Compile and install it:
-
-----
-$ ./configure
-$ make
-# make install
-----
-
-This will install the plugin to where BitlBee expects them, which is
-`/usr/local/lib/bitlbee` if you installed BitlBee from source.
+Or install http://sourceforge.net/projects/skype4py/[Skype4Py], and build
+BitlBee with `--skype=1`.
=== Configuring
diff --git a/protocols/skype/skype.c b/protocols/skype/skype.c
index 7ce562d4..714babf4 100644
--- a/protocols/skype/skype.c
+++ b/protocols/skype/skype.c
@@ -343,11 +343,11 @@ static void skype_parse_user(struct im_connection *ic, char *line)
*ptr = '\0';
ptr++;
if (!strncmp(ptr, "ONLINESTATUS ", 13)) {
- if (!strcmp(user, sd->username))
- return;
- if (!set_getbool(&ic->acc->set, "test_join")
+ if (!strlen(user) || !strcmp(user, sd->username))
+ return;
+ if (!set_getbool(&ic->acc->set, "test_join")
&& !strcmp(user, "echo123"))
- return;
+ return;
ptr = g_strdup_printf("%s@skype.com", user);
imcb_add_buddy(ic, ptr, skype_group_by_username(ic, user));
if (strcmp(status, "OFFLINE") && (strcmp(status, "SKYPEOUT") ||
@@ -1015,7 +1015,10 @@ static void skype_parse_chat(struct im_connection *ic, char *line)
sd->adder = NULL;
}
} else if (!strncmp(info, "MEMBERS ", 8) || !strncmp(info, "ACTIVEMEMBERS ", 14) ) {
- info += 8;
+ if (!strncmp(info, "MEMBERS ", 8))
+ info += 8;
+ else
+ info += 14;
gc = bee_chat_by_title(ic->bee, ic, id);
/* Hack! We set ->data to TRUE
* while we're on the channel
@@ -1563,7 +1566,7 @@ static void skype_init(account_t *acc)
s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
s = set_add(&acc->set, "mood_text", NULL, skype_set_mood_text, acc);
- s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
s = set_add(&acc->set, "call", NULL, skype_set_call, acc);
s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
diff --git a/protocols/skype/skyped.py b/protocols/skype/skyped.py
index 86b1e96a..c9bb103b 100644
--- a/protocols/skype/skyped.py
+++ b/protocols/skype/skyped.py
@@ -272,7 +272,7 @@ def dprint(msg):
if options.log:
sock = open(options.log, "a")
- sock.write(prefix + ": " + sanitized)
+ sock.write("%s: %s\n" % (prefix, sanitized))
sock.close()
sys.stdout.flush()
diff --git a/protocols/skype/t/away-set-bitlbee.mock b/protocols/skype/t/away-set-bitlbee.mock
new file mode 100644
index 00000000..bf073400
--- /dev/null
+++ b/protocols/skype/t/away-set-bitlbee.mock
@@ -0,0 +1,10 @@
+>> NOTICE AUTH
+<< NICK alice
+<< USER alice alice localhost :Alice
+>> PRIVMSG &bitlbee
+<< PRIVMSG &bitlbee :account add skype alice foo
+<< PRIVMSG &bitlbee :account skype set skypeconsole_receive true
+<< PRIVMSG &bitlbee :account skype on
+>> PRIVMSG &bitlbee :skype - Logging in: Logged in
+<< AWAY :work
+>> PRIVMSG &bitlbee :alice: USERSTATUS AWAY
diff --git a/protocols/skype/t/away-set-skyped.mock b/protocols/skype/t/away-set-skyped.mock
new file mode 100644
index 00000000..0c2cc494
--- /dev/null
+++ b/protocols/skype/t/away-set-skyped.mock
@@ -0,0 +1,20 @@
+>> SEARCH GROUPS CUSTOM
+<< GROUPS 48, 49
+>> SEARCH FRIENDS
+<< USERS echo123, bob
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> GET USER echo123 ONLINESTATUS
+<< USER echo123 ONLINESTATUS ONLINE
+>> GET USER echo123 FULLNAME
+<< USER echo123 FULLNAME Echo / Sound Test Service
+>> GET USER bob ONLINESTATUS
+<< USER bob ONLINESTATUS ONLINE
+>> GET USER bob FULLNAME
+<< USER bob FULLNAME Bob
+>> SET USERSTATUS AWAY
+<< USERSTATUS AWAY
+<< USER alice ONLINESTATUS AWAY
+<< USERSTATUS AWAY
diff --git a/protocols/skype/t/group-add-bitlbee.mock b/protocols/skype/t/group-add-bitlbee.mock
new file mode 100644
index 00000000..05c9f987
--- /dev/null
+++ b/protocols/skype/t/group-add-bitlbee.mock
@@ -0,0 +1,14 @@
+>> NOTICE AUTH
+<< NICK alice
+<< USER alice alice localhost :Alice
+>> PRIVMSG &bitlbee
+<< PRIVMSG &bitlbee :account add skype alice foo
+<< PRIVMSG &bitlbee :account skype set read_groups true
+<< PRIVMSG &bitlbee :account skype on
+>> :bob!bob@skype.com JOIN :&bitlbee
+>> :cecil!cecil@skype.com JOIN :&bitlbee
+>> :daniel!daniel@skype.com JOIN :&bitlbee
+<< JOIN &family
+>> 353 alice = &family :@alice +bob +cecil @root
+<< INVITE daniel &family
+>> :daniel!daniel@skype.com JOIN :&family
diff --git a/protocols/skype/t/group-add-skyped.mock b/protocols/skype/t/group-add-skyped.mock
new file mode 100644
index 00000000..c47f6629
--- /dev/null
+++ b/protocols/skype/t/group-add-skyped.mock
@@ -0,0 +1,38 @@
+>> SEARCH GROUPS CUSTOM
+<< GROUPS 70, 71
+>> SEARCH FRIENDS
+<< USERS echo123, bob, cecil, daniel, emily
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> GET GROUP 70 DISPLAYNAME
+<< GROUP 70 DISPLAYNAME Family
+>> GET GROUP 70 USERS
+<< GROUP 70 USERS bob, cecil
+>> GET GROUP 71 DISPLAYNAME
+<< GROUP 71 DISPLAYNAME Work
+>> GET GROUP 71 USERS
+<< GROUP 71 USERS daniel, emily
+>> GET USER echo123 ONLINESTATUS
+<< USER echo123 ONLINESTATUS ONLINE
+>> GET USER echo123 FULLNAME
+<< USER echo123 FULLNAME Echo / Sound Test Service
+>> GET USER bob ONLINESTATUS
+<< USER bob ONLINESTATUS ONLINE
+>> GET USER bob FULLNAME
+<< USER bob FULLNAME Bob
+>> GET USER cecil ONLINESTATUS
+<< USER cecil ONLINESTATUS ONLINE
+>> GET USER cecil FULLNAME
+<< USER cecil FULLNAME Cecil
+>> GET USER daniel ONLINESTATUS
+<< USER daniel ONLINESTATUS ONLINE
+>> GET USER daniel FULLNAME
+<< USER daniel FULLNAME Daniel
+>> GET USER emily ONLINESTATUS
+<< USER emily ONLINESTATUS OFFLINE
+>> GET USER emily FULLNAME
+<< USER emily FULLNAME Emily
+>> ALTER GROUP 70 ADDUSER daniel
+<< ALTER GROUP 70 ADDUSER daniel
diff --git a/protocols/skype/t/groupchat-msg-bitlbee.mock b/protocols/skype/t/groupchat-msg-bitlbee.mock
new file mode 100644
index 00000000..d6fac10d
--- /dev/null
+++ b/protocols/skype/t/groupchat-msg-bitlbee.mock
@@ -0,0 +1,11 @@
+>> NOTICE AUTH
+<< NICK alice
+<< USER alice alice localhost :Alice
+>> PRIVMSG &bitlbee
+<< PRIVMSG &bitlbee :account add skype alice foo
+<< PRIVMSG &bitlbee :account skype set skypeconsole_receive true
+<< PRIVMSG &bitlbee :account skype on
+>> JOIN :##cecil/$bob;4d8cc9965791
+>> 353 alice = ##cecil/$bob;4d8cc9965791 :@alice bob cecil @root
+<< PRIVMSG ##cecil/$bob;4d8cc9965791 :hello
+>> PRIVMSG &bitlbee :alice: CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVITY_TIMESTAMP
diff --git a/protocols/skype/t/groupchat-msg-skyped.mock b/protocols/skype/t/groupchat-msg-skyped.mock
new file mode 100644
index 00000000..e939585c
--- /dev/null
+++ b/protocols/skype/t/groupchat-msg-skyped.mock
@@ -0,0 +1,60 @@
+>> SEARCH GROUPS CUSTOM
+<< GROUPS 48, 49
+>> SEARCH FRIENDS
+<< USERS echo123, bob, cecil
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> GET USER echo123 ONLINESTATUS
+<< USER echo123 ONLINESTATUS ONLINE
+>> GET USER echo123 FULLNAME
+<< USER echo123 FULLNAME Echo / Sound Test Service
+>> GET USER bob ONLINESTATUS
+<< USER bob ONLINESTATUS OFFLINE
+>> GET USER bob FULLNAME
+<< USER bob FULLNAME Bob
+>> GET USER cecil ONLINESTATUS
+<< USER cecil ONLINESTATUS OFFLINE
+>> GET USER cecil FULLNAME
+<< USER cecil FULLNAME Cecil
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 NAME #cecil/$bob;4d8cc9965791c6b9
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED
+<< CHATMEMBER 186 ROLE USER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 MYROLE USER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil alice
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 FRIENDLYNAME bob, cecil
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob alice
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TIMESTAMP 1358276196
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED
+<< CHATMESSAGE 188 STATUS RECEIVED
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+>> GET CHATMESSAGE 188 FROM_HANDLE
+<< CHATMESSAGE 188 FROM_HANDLE bob
+>> GET CHATMESSAGE 188 BODY
+<< CHATMESSAGE 188 BODY
+>> GET CHATMESSAGE 188 TYPE
+<< CHATMESSAGE 188 TYPE ADDEDMEMBERS
+>> GET CHATMESSAGE 188 CHATNAME
+<< CHATMESSAGE 188 CHATNAME #cecil/$bob;4d8cc9965791c6b9
+<< CHATMESSAGE 189 STATUS READ
+<< CHATMESSAGE 189 STATUS READ
+<< CHATMEMBER 186 IS_ACTIVE TRUE
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice
+<< CHATMESSAGE 190 STATUS SENT
+>> CHATMESSAGE #cecil/$bob;4d8cc9965791c6b9 hello
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVITY_TIMESTAMP 1364652882
diff --git a/protocols/skype/t/groupchat-topic-bitlbee.mock b/protocols/skype/t/groupchat-topic-bitlbee.mock
new file mode 100644
index 00000000..637e4d98
--- /dev/null
+++ b/protocols/skype/t/groupchat-topic-bitlbee.mock
@@ -0,0 +1,10 @@
+>> NOTICE AUTH
+<< NICK alice
+<< USER alice alice localhost :Alice
+>> PRIVMSG &bitlbee
+<< PRIVMSG &bitlbee :account add skype alice foo
+<< PRIVMSG &bitlbee :account skype on
+>> JOIN :##cecil/$bob;4d8cc9965791
+>> 353 alice = ##cecil/$bob;4d8cc9965791 :@alice bob cecil @root
+<< TOPIC ##cecil/$bob;4d8cc9965791 :topic
+>> TOPIC ##cecil/$bob;4d8cc9965791 :topic
diff --git a/protocols/skype/t/groupchat-topic-skyped.mock b/protocols/skype/t/groupchat-topic-skyped.mock
new file mode 100644
index 00000000..26c4b53b
--- /dev/null
+++ b/protocols/skype/t/groupchat-topic-skyped.mock
@@ -0,0 +1,60 @@
+>> SEARCH GROUPS CUSTOM
+<< GROUPS 48, 49
+>> SEARCH FRIENDS
+<< USERS echo123, bob, cecil
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> SET USERSTATUS ONLINE
+<< USERSTATUS ONLINE
+>> GET USER echo123 ONLINESTATUS
+<< USER echo123 ONLINESTATUS ONLINE
+>> GET USER echo123 FULLNAME
+<< USER echo123 FULLNAME Echo / Sound Test Service
+>> GET USER bob ONLINESTATUS
+<< USER bob ONLINESTATUS OFFLINE
+>> GET USER bob FULLNAME
+<< USER bob FULLNAME Bob
+>> GET USER cecil ONLINESTATUS
+<< USER cecil ONLINESTATUS OFFLINE
+>> GET USER cecil FULLNAME
+<< USER cecil FULLNAME Cecil
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 NAME #cecil/$bob;4d8cc9965791c6b9
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED
+<< CHATMEMBER 186 ROLE USER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 MYROLE USER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 MEMBERS bob cecil alice
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 FRIENDLYNAME bob, cecil
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob alice
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TIMESTAMP 1358276196
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 STATUS MULTI_SUBSCRIBED
+<< CHATMESSAGE 188 STATUS RECEIVED
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ADDER bob
+>> GET CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC
+>> GET CHATMESSAGE 188 FROM_HANDLE
+<< CHATMESSAGE 188 FROM_HANDLE bob
+>> GET CHATMESSAGE 188 BODY
+<< CHATMESSAGE 188 BODY
+>> GET CHATMESSAGE 188 TYPE
+<< CHATMESSAGE 188 TYPE ADDEDMEMBERS
+>> GET CHATMESSAGE 188 CHATNAME
+<< CHATMESSAGE 188 CHATNAME #cecil/$bob;4d8cc9965791c6b9
+<< CHATMESSAGE 189 STATUS READ
+<< CHATMESSAGE 189 STATUS READ
+<< CHATMEMBER 186 IS_ACTIVE TRUE
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 ACTIVEMEMBERS bob cecil alice
+<< CHATMESSAGE 190 STATUS SENT
+>> ALTER CHAT #cecil/$bob;4d8cc9965791c6b9 SETTOPIC topic
+<< CHAT #cecil/$bob;4d8cc9965791c6b9 TOPIC topic
diff --git a/protocols/skype/test.py b/protocols/skype/test.py
index 63652f76..233c41c8 100755
--- a/protocols/skype/test.py
+++ b/protocols/skype/test.py
@@ -112,6 +112,12 @@ class Test(unittest.TestCase):
def testGroupchatLeave(self):
self.mock("groupchat-leave")
+ def testGroupchatMsg(self):
+ self.mock("groupchat-msg")
+
+ def testGroupchatTopic(self):
+ self.mock("groupchat-topic")
+
def testCalledYes(self):
self.mock("called-yes")
@@ -124,11 +130,17 @@ class Test(unittest.TestCase):
def testGroupRead(self):
self.mock("group-read")
+ def testGroupAdd(self):
+ self.mock("group-add")
+
def testCtcpHelp(self):
self.mock("ctcp-help")
def testSetMoodText(self):
self.mock("set-mood-text")
+
+ def testAwaySet(self):
+ self.mock("away-set")
if __name__ == '__main__':
setupSkyped()
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c
index db61ba7c..4626cf55 100644
--- a/protocols/twitter/twitter.c
+++ b/protocols/twitter/twitter.c
@@ -157,8 +157,13 @@ static const struct oauth_service *get_oauth_service(struct im_connection *ic)
static void twitter_oauth_start(struct im_connection *ic)
{
struct twitter_data *td = ic->proto_data;
+ const char *url = set_getstr(&ic->acc->set, "base_url");
imcb_log(ic, "Requesting OAuth request token");
+
+ if (!strstr(url, "twitter.com") && !strstr(url, "identi.ca"))
+ imcb_log(ic, "Warning: OAuth only works with identi.ca and "
+ "Twitter.");
td->oauth_info = oauth_request_token(get_oauth_service(ic), twitter_oauth_callback, ic);
@@ -177,7 +182,7 @@ static gboolean twitter_oauth_callback(struct oauth_info *info)
td = ic->proto_data;
if (info->stage == OAUTH_REQUEST_TOKEN) {
- char name[strlen(ic->acc->user) + 9], *msg;
+ char *name, *msg;
if (info->request_token == NULL) {
imcb_error(ic, "OAuth error: %s", twitter_parse_error(info->http));
@@ -185,11 +190,12 @@ static gboolean twitter_oauth_callback(struct oauth_info *info)
return FALSE;
}
- sprintf(name, "%s_%s", td->prefix, ic->acc->user);
+ name = g_strdup_printf("%s_%s", td->prefix, ic->acc->user);
msg = g_strdup_printf("To finish OAuth authentication, please visit "
"%s and respond with the resulting PIN code.",
info->auth_url);
imcb_buddy_msg(ic, name, msg, 0, 0);
+ g_free(name);
g_free(msg);
} else if (info->stage == OAUTH_ACCESS_TOKEN) {
const char *sn;
@@ -282,13 +288,16 @@ static void twitter_init(account_t * acc)
set_t *s;
char *def_url;
char *def_tul;
+ char *def_mentions;
if (strcmp(acc->prpl->name, "twitter") == 0) {
def_url = TWITTER_API_URL;
def_tul = "20";
+ def_mentions = "true";
} else { /* if( strcmp( acc->prpl->name, "identica" ) == 0 ) */
def_url = IDENTICA_API_URL;
def_tul = "0";
+ def_mentions = "false";
}
s = set_add(&acc->set, "auto_reply_timeout", "10800", set_eval_int, acc);
@@ -301,7 +310,7 @@ static void twitter_init(account_t * acc)
s = set_add(&acc->set, "fetch_interval", "60", set_eval_int, acc);
s->flags |= ACC_SET_OFFLINE_ONLY;
- s = set_add(&acc->set, "fetch_mentions", "true", set_eval_bool, acc);
+ s = set_add(&acc->set, "fetch_mentions", def_mentions, set_eval_bool, acc);
s = set_add(&acc->set, "message_length", "140", set_eval_int, acc);
diff --git a/protocols/twitter/twitter_http.c b/protocols/twitter/twitter_http.c
index 0f1ab518..f7ab6e18 100644
--- a/protocols/twitter/twitter_http.c
+++ b/protocols/twitter/twitter_http.c
@@ -77,7 +77,7 @@ struct http_request *twitter_http(struct im_connection *ic, char *url_string, ht
}
// Make the request.
- g_string_printf(request, "%s %s%s%s%s HTTP/1.0\r\n"
+ g_string_printf(request, "%s %s%s%s%s HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n",
is_post ? "POST" : "GET",
diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h
index f59c81ef..e593d229 100644
--- a/protocols/twitter/twitter_lib.h
+++ b/protocols/twitter/twitter_lib.h
@@ -28,7 +28,7 @@
#include "nogaim.h"
#include "twitter_http.h"
-#define TWITTER_API_URL "http://api.twitter.com/1.1"
+#define TWITTER_API_URL "https://api.twitter.com/1.1"
#define IDENTICA_API_URL "https://identi.ca/api"
/* Status URLs */
diff --git a/storage_xml.c b/storage_xml.c
index 3ee8ae1d..d32ed25f 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -173,7 +173,7 @@ static storage_status_t xml_load_real( irc_t *irc, const char *my_nick, const ch
struct xml_parsedata xd[1];
char *fn, buf[2048];
int fd, st;
- struct xt_parser *xp;
+ struct xt_parser *xp = NULL;
struct xt_node *node;
storage_status_t ret = STORAGE_OTHER_ERROR;