aboutsummaryrefslogtreecommitdiffstats
path: root/protocols
diff options
context:
space:
mode:
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Makefile2
-rw-r--r--protocols/http_client.c382
-rw-r--r--protocols/http_client.h54
-rw-r--r--protocols/jabber/Makefile8
-rw-r--r--protocols/msn/Makefile8
-rw-r--r--protocols/msn/msn.h2
-rw-r--r--protocols/msn/ns.c2
-rw-r--r--protocols/msn/passport.c308
-rw-r--r--protocols/msn/passport.h6
-rw-r--r--protocols/msn/sb.c26
-rw-r--r--protocols/msn/tables.c8
-rw-r--r--protocols/oscar/Makefile8
-rw-r--r--protocols/proxy.c2
-rw-r--r--protocols/ssl_bogus.c2
-rw-r--r--protocols/ssl_client.h5
-rw-r--r--protocols/ssl_gnutls.c39
-rw-r--r--protocols/ssl_nss.c4
-rw-r--r--protocols/ssl_openssl.c84
-rw-r--r--protocols/yahoo/Makefile8
19 files changed, 703 insertions, 255 deletions
diff --git a/protocols/Makefile b/protocols/Makefile
index c5f938fd..1ed6b52e 100644
--- a/protocols/Makefile
+++ b/protocols/Makefile
@@ -9,7 +9,7 @@
-include ../Makefile.settings
# [SH] Program variables
-objects = md5.o nogaim.o proxy.o sha.o util.o $(SSL_CLIENT)
+objects = http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) util.o
# [SH] The next two lines should contain the directory name (in $(subdirs))
# and the name of the object file, which should be linked into
diff --git a/protocols/http_client.c b/protocols/http_client.c
new file mode 100644
index 00000000..51424e1c
--- /dev/null
+++ b/protocols/http_client.c
@@ -0,0 +1,382 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2005 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* HTTP(S) module */
+
+/*
+ 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 <string.h>
+#include <stdio.h>
+
+#include "sock.h"
+#include "http_client.h"
+#include "url.h"
+
+
+static void http_connected( gpointer data, int source, GaimInputCondition cond );
+static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond );
+static void http_incoming_data( gpointer data, int source, GaimInputCondition cond );
+
+
+void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data )
+{
+ struct http_request *req;
+ int error = 0;
+
+ req = g_new0( struct http_request, 1 );
+
+ if( ssl )
+ {
+ req->ssl = ssl_connect( host, port, http_ssl_connected, req );
+ if( req->ssl == NULL )
+ error = 1;
+ }
+ else
+ {
+ req->fd = proxy_connect( host, port, http_connected, req );
+ if( req->fd < 0 )
+ error = 1;
+ }
+
+ if( error )
+ {
+ g_free( req );
+ return( NULL );
+ }
+
+ req->func = func;
+ req->data = data;
+ req->request = g_strdup( request );
+ req->request_length = strlen( request );
+
+ return( req );
+}
+
+/* This one is actually pretty simple... Might get more calls if we can't write
+ the whole request at once. */
+static void http_connected( gpointer data, int source, GaimInputCondition cond )
+{
+ struct http_request *req = data;
+ int st;
+
+ if( source < 0 )
+ goto error;
+
+ if( req->inpa > 0 )
+ gaim_input_remove( req->inpa );
+
+ sock_make_nonblocking( req->fd );
+
+ if( req->ssl )
+ {
+ st = ssl_write( req->ssl, req->request + req->bytes_written,
+ req->request_length - req->bytes_written );
+ if( st < 0 )
+ {
+ if( ssl_errno != SSL_AGAIN )
+ {
+ ssl_disconnect( req->ssl );
+ goto error;
+ }
+ }
+ }
+ else
+ {
+ st = write( source, req->request + req->bytes_written,
+ req->request_length - req->bytes_written );
+ if( st < 0 )
+ {
+ if( !sockerr_again() )
+ {
+ closesocket( req->fd );
+ goto error;
+ }
+ }
+ }
+
+ if( st > 0 )
+ req->bytes_written += st;
+
+ if( req->bytes_written < req->request_length )
+ req->inpa = gaim_input_add( source,
+ req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE,
+ http_connected, req );
+ else
+ req->inpa = gaim_input_add( source, GAIM_INPUT_READ, http_incoming_data, req );
+
+ return;
+
+error:
+ req->func( req );
+
+ g_free( req->request );
+ g_free( req );
+
+ return;
+}
+
+static void http_ssl_connected( gpointer data, void *source, GaimInputCondition cond )
+{
+ struct http_request *req = data;
+
+ if( source == NULL )
+ return http_connected( data, -1, cond );
+
+ req->fd = ssl_getfd( source );
+
+ return http_connected( data, req->fd, cond );
+}
+
+static void http_incoming_data( gpointer data, int source, GaimInputCondition cond )
+{
+ struct http_request *req = data;
+ int evil_server = 0;
+ char buffer[2048];
+ char *end1, *end2;
+ int st;
+
+ if( req->inpa > 0 )
+ gaim_input_remove( req->inpa );
+
+ if( req->ssl )
+ {
+ st = ssl_read( req->ssl, buffer, sizeof( buffer ) );
+ if( st < 0 )
+ {
+ if( ssl_errno != SSL_AGAIN )
+ {
+ /* goto cleanup; */
+
+ /* YAY! We have to deal with crappy Microsoft
+ servers that LOVE to send invalid TLS
+ packets that abort connections! \o/ */
+
+ goto got_reply;
+ }
+ }
+ else if( st == 0 )
+ {
+ goto got_reply;
+ }
+ }
+ else
+ {
+ st = read( req->fd, buffer, sizeof( buffer ) );
+ if( st < 0 )
+ {
+ if( !sockerr_again() )
+ {
+ goto cleanup;
+ }
+ }
+ else if( st == 0 )
+ {
+ goto got_reply;
+ }
+ }
+
+ 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;
+ }
+
+ /* There will be more! */
+ req->inpa = gaim_input_add( req->fd,
+ req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ,
+ http_incoming_data, req );
+
+ return;
+
+got_reply:
+ /* Zero termination is very convenient. */
+ req->reply_headers[req->bytes_read] = 0;
+
+ /* Find the separation between headers and body, and keep stupid
+ webservers in mind. */
+ end1 = strstr( req->reply_headers, "\r\n\r\n" );
+ end2 = strstr( req->reply_headers, "\n\n" );
+
+ if( end2 && end2 < end1 )
+ {
+ end1 = end2 + 1;
+ evil_server = 1;
+ }
+ else
+ {
+ end1 += 2;
+ }
+
+ if( end1 )
+ {
+ *end1 = 0;
+
+ if( evil_server )
+ req->reply_body = end1 + 1;
+ else
+ req->reply_body = end1 + 2;
+ }
+
+ if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL )
+ {
+ if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 )
+ req->status_code = -1;
+ }
+ else
+ {
+ req->status_code = -1;
+ }
+
+ if( req->status_code == 301 || req->status_code == 302 )
+ {
+ char *loc, *new_request, *new_host;
+ int error = 0, new_port, new_proto;
+
+ loc = strstr( req->reply_headers, "\nLocation: " );
+ if( loc == NULL ) /* We can't handle this redirect... */
+ goto cleanup;
+
+ loc += 11;
+ while( *loc == ' ' )
+ loc ++;
+
+ /* TODO/FIXME: Possibly have to handle relative redirections,
+ and rewrite Host: headers. Not necessary for now, it's
+ enough for passport authentication like this. */
+
+ if( *loc == '/' )
+ {
+ /* Just a different pathname... */
+
+ /* Since we don't cache the servername, and since we
+ don't need this yet anyway, I won't implement it. */
+
+ goto cleanup;
+ }
+ else
+ {
+ /* A whole URL */
+ url_t *url;
+ char *s;
+
+ s = strstr( loc, "\r\n" );
+ if( s == NULL )
+ goto cleanup;
+
+ url = g_new0( url_t, 1 );
+ *s = 0;
+
+ if( !url_set( url, loc ) )
+ {
+ g_free( url );
+ goto cleanup;
+ }
+
+ /* Okay, this isn't fun! We have to rebuild the request... :-( */
+ new_request = g_malloc( req->request_length + strlen( url->file ) );
+
+ /* So, now I just allocated enough memory, so I'm
+ going to use strcat(), whether you like it or not. :-) */
+
+ /* First, find the GET/POST/whatever from the original request. */
+ s = strchr( req->request, ' ' );
+ if( s == NULL )
+ {
+ g_free( new_request );
+ g_free( url );
+ goto cleanup;
+ }
+
+ *s = 0;
+ sprintf( new_request, "%s %s HTTP/1.0\r\n", req->request, url->file );
+ *s = ' ';
+
+ s = strstr( req->request, "\r\n" );
+ if( s == NULL )
+ {
+ g_free( new_request );
+ g_free( url );
+ goto cleanup;
+ }
+
+ strcat( new_request, s + 2 );
+ new_host = g_strdup( url->host );
+ new_port = url->port;
+ new_proto = url->proto;
+
+ g_free( url );
+ }
+
+ if( req->ssl )
+ ssl_disconnect( req->ssl );
+ else
+ closesocket( req->fd );
+
+ req->fd = -1;
+ req->ssl = 0;
+
+ if( new_proto == PROTO_HTTPS )
+ {
+ req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req );
+ if( req->ssl == NULL )
+ error = 1;
+ }
+ else
+ {
+ req->fd = proxy_connect( new_host, new_port, http_connected, req );
+ if( req->fd < 0 )
+ error = 1;
+ }
+ g_free( new_host );
+
+ if( error )
+ {
+ g_free( new_request );
+ goto cleanup;
+ }
+
+ g_free( req->request );
+ g_free( req->reply_headers );
+ 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;
+
+ return;
+ }
+
+ /* Assume that a closed connection means we're finished, this indeed
+ breaks with keep-alive connections and faulty connections. */
+ req->finished = 1;
+
+cleanup:
+ if( req->ssl )
+ ssl_disconnect( req->ssl );
+ else
+ closesocket( req->fd );
+
+ req->func( req );
+
+ g_free( req->request );
+ g_free( req->reply_headers );
+ g_free( req );
+}
diff --git a/protocols/http_client.h b/protocols/http_client.h
new file mode 100644
index 00000000..53c6fcd6
--- /dev/null
+++ b/protocols/http_client.h
@@ -0,0 +1,54 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2005 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* HTTP(S) module */
+
+/*
+ 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 <glib.h>
+
+#include "ssl_client.h"
+
+struct http_request;
+
+typedef void (*http_input_function)( struct http_request * );
+
+struct http_request
+{
+ char *request;
+ int request_length;
+ int status_code;
+ char *reply_headers;
+ char *reply_body;
+ int finished;
+
+ void *ssl;
+ int fd;
+
+ int inpa;
+ int bytes_written;
+ int bytes_read;
+
+ http_input_function func;
+ gpointer data;
+};
+
+void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data );
diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile
index df326fe6..9b414dc8 100644
--- a/protocols/jabber/Makefile
+++ b/protocols/jabber/Makefile
@@ -15,7 +15,7 @@ CFLAGS += -Wall
LFLAGS += -r
# [SH] Phony targets
-all: jabberr.o
+all: jabber_mod.o
.PHONY: all clean distclean
@@ -32,6 +32,6 @@ $(objects): %.o: %.c
@echo '*' Compiling $<
@$(CC) -c $(CFLAGS) $< -o $@
-jabberr.o: $(objects)
- @echo '*' Linking jabberr.o
- @$(LD) $(LFLAGS) $(objects) -o jabberr.o
+jabber_mod.o: $(objects)
+ @echo '*' Linking jabber_mod.o
+ @$(LD) $(LFLAGS) $(objects) -o jabber_mod.o
diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile
index e6620323..873c831c 100644
--- a/protocols/msn/Makefile
+++ b/protocols/msn/Makefile
@@ -15,7 +15,7 @@ CFLAGS += -Wall
LFLAGS += -r
# [SH] Phony targets
-all: msnn.o
+all: msn_mod.o
.PHONY: all clean distclean
@@ -32,8 +32,8 @@ $(objects): %.o: %.c
@echo '*' Compiling $<
@$(CC) -c $(CFLAGS) $< -o $@
-msnn.o: $(objects)
- @echo '*' Linking msnn.o
- @$(LD) $(LFLAGS) $(objects) -o msnn.o
+msn_mod.o: $(objects)
+ @echo '*' Linking msn_mod.o
+ @$(LD) $(LFLAGS) $(objects) -o msn_mod.o
diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h
index 61231d8a..c8c7a788 100644
--- a/protocols/msn/msn.h
+++ b/protocols/msn/msn.h
@@ -126,6 +126,8 @@ struct msn_handler_data
/* Bitfield values for msn_status_code.flags */
#define STATUS_FATAL 1
#define STATUS_SB_FATAL 2
+#define STATUS_SB_IM_SPARE 4 /* Make one-to-one conversation switchboard available again, invite failed. */
+#define STATUS_SB_CHAT_SPARE 8 /* Same, but also for groupchats (not used yet). */
int msn_chat_id;
extern struct msn_away_state msn_away_state_list[];
diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c
index f1bda1a4..2d90b2f3 100644
--- a/protocols/msn/ns.c
+++ b/protocols/msn/ns.c
@@ -207,7 +207,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 )
{
/* Time for some Passport black magic... */
- if( !passport_get_id( gc, gc->username, gc->password, cmd[4], msn_auth_got_passport_id ) )
+ if( !passport_get_id( msn_auth_got_passport_id, gc, gc->username, gc->password, cmd[4] ) )
{
hide_login_progress_error( gc, "Error while contacting Passport server" );
signoff( gc );
diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c
index 640126a0..34703432 100644
--- a/protocols/msn/passport.c
+++ b/protocols/msn/passport.c
@@ -19,7 +19,7 @@
*
*/
-#include "ssl_client.h"
+#include "http_client.h"
#include "passport.h"
#include "msn.h"
#include "bitlbee.h"
@@ -30,34 +30,91 @@
static char *prd_cached = NULL;
-static char *passport_create_header( char *reply, char *email, char *pwd );
+static int passport_get_id_real( gpointer func, gpointer data, char *header );
+static void passport_get_id_ready( struct http_request *req );
+
static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header );
-static void passport_retrieve_dalogin_connected( gpointer data, void *ssl, GaimInputCondition cond );
-static int passport_get_id_from( gpointer data, gpointer func, char *header_i, char *url );
-static void passport_get_id_connected( gpointer data, void *ssl, GaimInputCondition cond );
-static void destroy_reply( struct passport_reply *rep );
+static void passport_retrieve_dalogin_ready( struct http_request *req );
+static char *passport_create_header( char *cookie, char *email, char *pwd );
+static void destroy_reply( struct passport_reply *rep );
-int passport_get_id( gpointer data, char *username, char *password, char *cookie, gpointer func )
+int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie )
{
char *header = passport_create_header( cookie, username, password );
- if( prd_cached )
- {
- int st;
-
- st = passport_get_id_from( data, func, header, prd_cached );
- g_free( header );
- return( st );
- }
+ if( prd_cached == NULL )
+ return passport_retrieve_dalogin( func, data, header );
else
+ return passport_get_id_real( func, data, header );
+}
+
+static int passport_get_id_real( gpointer func, gpointer data, char *header )
+{
+ struct passport_reply *rep;
+ char *server, *dummy, *reqs;
+ struct http_request *req;
+
+ rep = g_new0( struct passport_reply, 1 );
+ rep->data = data;
+ rep->func = func;
+
+ server = g_strdup( prd_cached );
+ dummy = strchr( server, '/' );
+
+ if( dummy == NULL )
{
- return( passport_retrieve_dalogin( data, func, header ) );
+ destroy_reply( rep );
+ return( 0 );
}
+
+ reqs = g_malloc( strlen( header ) + strlen( dummy ) + 128 );
+ sprintf( reqs, "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header );
+
+ *dummy = 0;
+ req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep );
+
+ g_free( server );
+ g_free( reqs );
+
+ if( req == NULL )
+ destroy_reply( rep );
+
+ return( req != NULL );
}
+static void passport_get_id_ready( struct http_request *req )
+{
+ struct passport_reply *rep = req->data;
+
+ if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers )
+ {
+ destroy_reply( rep );
+ return;
+ }
+
+ if( req->status_code == 200 )
+ {
+ char *dummy;
+
+ if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) )
+ {
+ char *responseend;
+
+ dummy += strlen( "from-PP='" );
+ responseend = strchr( dummy, '\'' );
+ if( responseend )
+ *responseend = 0;
+
+ rep->result = g_strdup( dummy );
+ }
+ }
+
+ rep->func( rep );
+ destroy_reply( rep );
+}
-static char *passport_create_header( char *reply, char *email, char *pwd )
+static char *passport_create_header( char *cookie, char *email, char *pwd )
{
char *buffer = g_new0( char, 2048 );
char *currenttoken;
@@ -71,7 +128,7 @@ static char *passport_create_header( char *reply, char *email, char *pwd )
strcpy( pwd_enc, pwd );
http_encode( pwd_enc );
- currenttoken = strstr( reply, "lc=" );
+ currenttoken = strstr( cookie, "lc=" );
if( currenttoken == NULL )
return( NULL );
@@ -87,227 +144,68 @@ static char *passport_create_header( char *reply, char *email, char *pwd )
return( buffer );
}
-
-static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header )
+#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n"
+static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header )
{
struct passport_reply *rep = g_new0( struct passport_reply, 1 );
- void *ssl;
+ struct http_request *req;
rep->data = data;
rep->func = func;
rep->header = header;
- ssl = ssl_connect( "nexus.passport.com", 443, passport_retrieve_dalogin_connected, rep );
+ req = http_dorequest( "nexus.passport.com", 443, 1, PPR_REQUEST, passport_retrieve_dalogin_ready, rep );
- if( !ssl )
+ if( !req )
destroy_reply( rep );
- return( ssl != NULL );
+ return( req != NULL );
}
-#define PPR_BUFFERSIZE 2048
-#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n"
-static void passport_retrieve_dalogin_connected( gpointer data, void *ssl, GaimInputCondition cond )
+static void passport_retrieve_dalogin_ready( struct http_request *req )
{
- int ret;
- char buffer[PPR_BUFFERSIZE+1];
- struct passport_reply *rep = data;
+ struct passport_reply *rep = req->data;
+ char *dalogin;
+ char *urlend;
- if( !g_slist_find( msn_connections, rep->data ) )
+ if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers )
{
- if( ssl ) ssl_disconnect( ssl );
destroy_reply( rep );
return;
}
- if( !ssl )
- {
- rep->func( rep );
- destroy_reply( rep );
- return;
- }
-
- ssl_write( ssl, PPR_REQUEST, strlen( PPR_REQUEST ) );
+ dalogin = strstr( req->reply_headers, "DALogin=" );
- if( ( ret = ssl_read( ssl, buffer, PPR_BUFFERSIZE ) ) <= 0 )
- {
+ if( !dalogin )
goto failure;
- }
-
- {
- char *dalogin = strstr( buffer, "DALogin=" );
- char *urlend;
-
- if( !dalogin )
- goto failure;
-
- dalogin += strlen( "DALogin=" );
- urlend = strchr( dalogin, ',' );
- if( urlend )
- *urlend = 0;
-
- /* strip the http(s):// part from the url */
- urlend = strstr( urlend, "://" );
- if( urlend )
- dalogin = urlend + strlen( "://" );
-
- if( prd_cached == NULL )
- prd_cached = g_strdup( dalogin );
- }
-
- if( passport_get_id_from( rep->data, rep->func, rep->header, prd_cached ) )
- {
- ssl_disconnect( ssl );
- destroy_reply( rep );
- return;
- }
-failure:
- ssl_disconnect( ssl );
- rep->func( rep );
- destroy_reply( rep );
-}
-
-
-static int passport_get_id_from( gpointer data, gpointer func, char *header_i, char *url )
-{
- struct passport_reply *rep = g_new0( struct passport_reply, 1 );
- char server[512], *dummy;
- void *ssl;
-
- rep->data = data;
- rep->func = func;
- rep->redirects = 4;
-
- strncpy( server, url, 512 );
- dummy = strchr( server, '/' );
- if( dummy )
- *dummy = 0;
-
- ssl = ssl_connect( server, 443, passport_get_id_connected, rep );
-
- if( ssl )
- {
- rep->header = g_strdup( header_i );
- rep->url = g_strdup( url );
- }
- else
- {
- destroy_reply( rep );
- }
+ dalogin += strlen( "DALogin=" );
+ urlend = strchr( dalogin, ',' );
+ if( urlend )
+ *urlend = 0;
- return( ssl != NULL );
-}
-
-#define PPG_BUFFERSIZE 4096
-static void passport_get_id_connected( gpointer data, void *ssl, GaimInputCondition cond )
-{
- struct passport_reply *rep = data;
- char server[512], buffer[PPG_BUFFERSIZE+1], *dummy;
- int ret;
+ /* strip the http(s):// part from the url */
+ urlend = strstr( urlend, "://" );
+ if( urlend )
+ dalogin = urlend + strlen( "://" );
- if( !g_slist_find( msn_connections, rep->data ) )
- {
- if( ssl ) ssl_disconnect( ssl );
- destroy_reply( rep );
- return;
- }
+ if( prd_cached == NULL )
+ prd_cached = g_strdup( dalogin );
- if( !ssl )
+ if( passport_get_id_real( rep->func, rep->data, rep->header ) )
{
- rep->func( rep );
destroy_reply( rep );
return;
}
- memset( buffer, 0, PPG_BUFFERSIZE + 1 );
-
- strncpy( server, rep->url, 512 );
- dummy = strchr( server, '/' );
- if( dummy == NULL )
- goto end;
-
- g_snprintf( buffer, PPG_BUFFERSIZE - 1, "GET %s HTTP/1.0\r\n"
- "%s\r\n\r\n", dummy, rep->header );
-
- ssl_write( ssl, buffer, strlen( buffer ) );
- memset( buffer, 0, PPG_BUFFERSIZE + 1 );
-
- {
- char *buffer2 = buffer;
-
- while( ( ( ret = ssl_read( ssl, buffer2, 512 ) ) > 0 ) &&
- ( buffer + PPG_BUFFERSIZE - buffer2 - ret - 512 >= 0 ) )
- {
- buffer2 += ret;
- }
- }
-
- if( *buffer == 0 )
- goto end;
-
- if( ( dummy = strstr( buffer, "Location:" ) ) )
- {
- char *urlend;
-
- rep->redirects --;
- if( rep->redirects == 0 )
- goto end;
-
- dummy += strlen( "Location:" );
- while( isspace( *dummy ) ) dummy ++;
- urlend = dummy;
- while( !isspace( *urlend ) ) urlend ++;
- *urlend = 0;
- if( ( urlend = strstr( dummy, "://" ) ) )
- dummy = urlend + strlen( "://" );
-
- g_free( rep->url );
- rep->url = g_strdup( dummy );
-
- strncpy( server, dummy, sizeof( server ) - 1 );
- dummy = strchr( server, '/' );
- if( dummy ) *dummy = 0;
-
- ssl_disconnect( ssl );
-
- if( ssl_connect( server, 443, passport_get_id_connected, rep ) )
- {
- return;
- }
- else
- {
- rep->func( rep );
- destroy_reply( rep );
- return;
- }
- }
- else if( strstr( buffer, "200 OK" ) )
- {
- if( ( dummy = strstr( buffer, "from-PP='" ) ) )
- {
- char *responseend;
-
- dummy += strlen( "from-PP='" );
- responseend = strchr( dummy, '\'' );
- if( responseend )
- *responseend = 0;
-
- rep->result = g_strdup( dummy );
- }
- }
-
-end:
- ssl_disconnect( ssl );
+failure:
rep->func( rep );
destroy_reply( rep );
}
-
static void destroy_reply( struct passport_reply *rep )
{
- if( rep->result ) g_free( rep->result );
- if( rep->url ) g_free( rep->url );
- if( rep->header ) g_free( rep->header );
- if( rep ) g_free( rep );
+ g_free( rep->result );
+ g_free( rep->header );
+ g_free( rep );
}
diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h
index 63fef2e9..f7e6ebb6 100644
--- a/protocols/msn/passport.h
+++ b/protocols/msn/passport.h
@@ -34,14 +34,12 @@
struct passport_reply
{
+ void (*func)( struct passport_reply * );
void *data;
char *result;
- void (*func)( struct passport_reply * );
- char *url;
char *header;
- int redirects;
};
-int passport_get_id( gpointer data, char *username, char *password, char *cookie, gpointer func );
+int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie );
#endif /* __PASSPORT_H__ */
diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c
index 2f4d05d5..11728f03 100644
--- a/protocols/msn/sb.c
+++ b/protocols/msn/sb.c
@@ -521,11 +521,35 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts )
msn_sb_destroy( sb );
return( 0 );
}
- else if( err->flags & STATUS_FATAL )
+ if( err->flags & STATUS_FATAL )
{
signoff( gc );
return( 0 );
}
+ if( err->flags & STATUS_SB_IM_SPARE )
+ {
+ if( sb->who )
+ {
+ struct msn_message *m;
+ GSList *l;
+
+ /* Apparently some invitation failed. We might want to use this
+ board later, so keep it as a spare. */
+ g_free( sb->who );
+ sb->who = NULL;
+
+ /* Also clear the msgq, otherwise someone else might get them. */
+ for( l = sb->msgq; l; l = l->next )
+ {
+ m = l->data;
+ g_free( m->who );
+ g_free( m->text );
+ g_free( m );
+ }
+ g_slist_free( sb->msgq );
+ sb->msgq = NULL;
+ }
+ }
}
else
{
diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c
index 0cd80c01..2741048a 100644
--- a/protocols/msn/tables.c
+++ b/protocols/msn/tables.c
@@ -79,12 +79,12 @@ struct msn_status_code msn_status_code_list[] =
{ 205, "Invalid (non-existent) handle", 0 },
{ 206, "Domain name missing", 0 },
{ 207, "Already logged in", 0 },
- { 208, "Invalid handle", 0 },
+ { 208, "Invalid handle", STATUS_SB_IM_SPARE },
{ 209, "Forbidden nickname", 0 },
{ 210, "Buddy list too long", 0 },
{ 215, "Handle is already in list", 0 },
- { 216, "Handle is not in list", 0 },
- { 217, "Person is off-line or non-existent", 0 },
+ { 216, "Handle is not in list", STATUS_SB_IM_SPARE },
+ { 217, "Person is off-line or non-existent", STATUS_SB_IM_SPARE },
{ 218, "Already in that mode", 0 },
{ 219, "Handle is already in opposite list", 0 },
{ 223, "Too many groups", 0 },
@@ -117,7 +117,7 @@ struct msn_status_code msn_status_code_list[] =
{ 710, "Invalid CVR parameters", STATUS_FATAL },
{ 711, "Write is blocking", STATUS_FATAL },
{ 712, "Session is overloaded", STATUS_FATAL },
- { 713, "Calling too rapidly", 0 },
+ { 713, "Calling too rapidly", STATUS_SB_IM_SPARE },
{ 714, "Too many sessions", STATUS_FATAL },
{ 715, "Not expected/Invalid argument/action", 0 },
{ 717, "Bad friend file", STATUS_FATAL },
diff --git a/protocols/oscar/Makefile b/protocols/oscar/Makefile
index 5ef996a1..97a27299 100644
--- a/protocols/oscar/Makefile
+++ b/protocols/oscar/Makefile
@@ -15,7 +15,7 @@ CFLAGS += -Wall
LFLAGS += -r
# [SH] Phony targets
-all: oscarr.o
+all: oscar_mod.o
.PHONY: all clean distclean
@@ -32,6 +32,6 @@ $(objects): %.o: %.c
@echo '*' Compiling $<
@$(CC) -c $(CFLAGS) $< -o $@
-oscarr.o: $(objects)
- @echo '*' Linking oscarr.o
- @$(LD) $(LFLAGS) $(objects) -o oscarr.o
+oscar_mod.o: $(objects)
+ @echo '*' Linking oscar_mod.o
+ @$(LD) $(LFLAGS) $(objects) -o oscar_mod.o
diff --git a/protocols/proxy.c b/protocols/proxy.c
index c658a163..1ca35dfe 100644
--- a/protocols/proxy.c
+++ b/protocols/proxy.c
@@ -105,8 +105,6 @@ static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpoin
gaim_cond |= GAIM_INPUT_READ;
if (condition & GAIM_WRITE_COND)
gaim_cond |= GAIM_INPUT_WRITE;
-// if (condition & GAIM_ERR_COND)
-// fprintf( stderr, "ERROR! fd=%d\n", g_io_channel_unix_get_fd( source ) );
closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond);
diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c
index 1ee0df4c..3766baaa 100644
--- a/protocols/ssl_bogus.c
+++ b/protocols/ssl_bogus.c
@@ -27,7 +27,7 @@
int ssl_errno;
-void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
+void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
{
return( NULL );
}
diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h
index 719cd0c4..89189db9 100644
--- a/protocols/ssl_client.h
+++ b/protocols/ssl_client.h
@@ -32,10 +32,11 @@
extern int ssl_errno;
-typedef void (*SslInputFunction)(gpointer, void*, GaimInputCondition);
+typedef void (*ssl_input_function)(gpointer, void*, GaimInputCondition);
-G_MODULE_EXPORT void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data );
+G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data );
G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len );
G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len );
G_MODULE_EXPORT void ssl_disconnect( void *conn_ );
G_MODULE_EXPORT int ssl_getfd( void *conn );
+G_MODULE_EXPORT GaimInputCondition ssl_getdirection( void *conn );
diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c
index c2eb6906..f2cb3e08 100644
--- a/protocols/ssl_gnutls.c
+++ b/protocols/ssl_gnutls.c
@@ -37,7 +37,7 @@ static gboolean initialized = FALSE;
struct scd
{
- SslInputFunction func;
+ ssl_input_function func;
gpointer data;
int fd;
gboolean established;
@@ -50,7 +50,7 @@ struct scd
static void ssl_connected( gpointer data, gint source, GaimInputCondition cond );
-void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
+void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
{
struct scd *conn = g_new0( struct scd, 1 );
@@ -110,15 +110,16 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )
int st;
if( conn->inpa != -1 )
+ {
gaim_input_remove( conn->inpa );
+ conn->inpa = -1;
+ }
if( ( st = gnutls_handshake( conn->session ) ) < 0 )
{
if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )
{
- conn->inpa = gaim_input_add( conn->fd,
- gnutls_record_get_direction( conn->session ) ?
- GAIM_INPUT_WRITE : GAIM_INPUT_READ,
+ conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ),
ssl_handshake, data );
}
else
@@ -144,31 +145,49 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )
int ssl_read( void *conn, char *buf, int len )
{
+ int st;
+
if( !((struct scd*)conn)->established )
{
ssl_errno = SSL_NOHANDSHAKE;
return( -1 );
}
- return( gnutls_record_recv( ((struct scd*)conn)->session, buf, len ) );
+ st = gnutls_record_recv( ((struct scd*)conn)->session, buf, len );
+ ssl_errno = SSL_OK;
+ if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )
+ ssl_errno = SSL_AGAIN;
+
+ return st;
}
int ssl_write( void *conn, const char *buf, int len )
{
+ int st;
+
if( !((struct scd*)conn)->established )
{
ssl_errno = SSL_NOHANDSHAKE;
return( -1 );
}
- return( gnutls_record_send( ((struct scd*)conn)->session, buf, len ) );
+ st = gnutls_record_send( ((struct scd*)conn)->session, buf, len );
+
+ ssl_errno = SSL_OK;
+ if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED )
+ ssl_errno = SSL_AGAIN;
+
+ return st;
}
void ssl_disconnect( void *conn_ )
{
struct scd *conn = conn_;
+ if( conn->inpa != -1 )
+ gaim_input_remove( conn->inpa );
+
if( conn->established )
gnutls_bye( conn->session, GNUTLS_SHUT_WR );
@@ -183,3 +202,9 @@ int ssl_getfd( void *conn )
{
return( ((struct scd*)conn)->fd );
}
+
+GaimInputCondition ssl_getdirection( void *conn )
+{
+ return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ?
+ GAIM_INPUT_WRITE : GAIM_INPUT_READ );
+}
diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c
index d28983fc..dfd32622 100644
--- a/protocols/ssl_nss.c
+++ b/protocols/ssl_nss.c
@@ -44,7 +44,7 @@ static gboolean initialized = FALSE;
struct scd
{
- SslInputFunction func;
+ ssl_input_function func;
gpointer data;
int fd;
PRFileDesc *prfd;
@@ -90,7 +90,7 @@ static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket)
}
-void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
+void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
{
struct scd *conn = g_new0( struct scd, 1 );
diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c
index bf87ab73..ae55f3f9 100644
--- a/protocols/ssl_openssl.c
+++ b/protocols/ssl_openssl.c
@@ -40,11 +40,13 @@ static gboolean initialized = FALSE;
struct scd
{
- SslInputFunction func;
+ ssl_input_function func;
gpointer data;
int fd;
gboolean established;
+ int inpa;
+ int lasterr; /* Necessary for SSL_get_error */
SSL *ssl;
SSL_CTX *ssl_ctx;
};
@@ -53,7 +55,7 @@ static void ssl_connected( gpointer data, gint source, GaimInputCondition cond )
-void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
+void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
{
struct scd *conn = g_new0( struct scd, 1 );
SSL_METHOD *meth;
@@ -92,19 +94,45 @@ void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
return( conn );
}
+static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond );
+
static void ssl_connected( gpointer data, gint source, GaimInputCondition cond )
{
struct scd *conn = data;
if( source == -1 )
- goto ssl_connected_failure;
+ return ssl_handshake( data, -1, cond );
+ /* Make it non-blocking at least during the handshake... */
+ sock_make_nonblocking( conn->fd );
SSL_set_fd( conn->ssl, conn->fd );
- if( SSL_connect( conn->ssl ) < 0 )
- goto ssl_connected_failure;
+ return ssl_handshake( data, source, cond );
+}
+
+static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )
+{
+ struct scd *conn = data;
+ int st;
+
+ if( conn->inpa != -1 )
+ {
+ gaim_input_remove( conn->inpa );
+ conn->inpa = -1;
+ }
+
+ if( ( st = SSL_connect( conn->ssl ) ) < 0 )
+ {
+ conn->lasterr = SSL_get_error( conn->ssl, st );
+ if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
+ goto ssl_connected_failure;
+
+ conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
+ return;
+ }
conn->established = TRUE;
+ sock_make_blocking( conn->fd ); /* For now... */
conn->func( conn->data, conn, cond );
return;
@@ -126,24 +154,57 @@ ssl_connected_failure:
int ssl_read( void *conn, char *buf, int len )
{
+ int st;
+
if( !((struct scd*)conn)->established )
- return( 0 );
+ {
+ ssl_errno = SSL_NOHANDSHAKE;
+ return -1;
+ }
+
+ st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
- return( SSL_read( ((struct scd*)conn)->ssl, buf, len ) );
+ ssl_errno = SSL_OK;
+ if( st <= 0 )
+ {
+ ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
+ if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
+ ssl_errno = SSL_AGAIN;
+ }
+
+ return st;
}
int ssl_write( void *conn, const char *buf, int len )
{
+ int st;
+
if( !((struct scd*)conn)->established )
- return( 0 );
+ {
+ ssl_errno = SSL_NOHANDSHAKE;
+ return -1;
+ }
+
+ st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
- return( SSL_write( ((struct scd*)conn)->ssl, buf, len ) );
+ ssl_errno = SSL_OK;
+ if( st <= 0 )
+ {
+ ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
+ if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
+ ssl_errno = SSL_AGAIN;
+ }
+
+ return st;
}
void ssl_disconnect( void *conn_ )
{
struct scd *conn = conn_;
+ if( conn->inpa != -1 )
+ gaim_input_remove( conn->inpa );
+
if( conn->established )
SSL_shutdown( conn->ssl );
@@ -158,3 +219,8 @@ int ssl_getfd( void *conn )
{
return( ((struct scd*)conn)->fd );
}
+
+GaimInputCondition ssl_getdirection( void *conn )
+{
+ return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ );
+}
diff --git a/protocols/yahoo/Makefile b/protocols/yahoo/Makefile
index 39a655a3..e594cc1f 100644
--- a/protocols/yahoo/Makefile
+++ b/protocols/yahoo/Makefile
@@ -15,7 +15,7 @@ CFLAGS += -Wall -DSTDC_HEADERS -DHAVE_STRING_H -DHAVE_STRCHR -DHAVE_MEMCPY -DHAV
LFLAGS += -r
# [SH] Phony targets
-all: yahooo.o
+all: yahoo_mod.o
.PHONY: all clean distclean
@@ -32,6 +32,6 @@ $(objects): %.o: %.c
@echo '*' Compiling $<
@$(CC) -c $(CFLAGS) $< -o $@
-yahooo.o: $(objects)
- @echo '*' Linking yahooo.o
- @$(LD) $(LFLAGS) $(objects) -o yahooo.o
+yahoo_mod.o: $(objects)
+ @echo '*' Linking yahoo_mod.o
+ @$(LD) $(LFLAGS) $(objects) -o yahoo_mod.o