aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/msn/ns.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/msn/ns.c')
-rw-r--r--protocols/msn/ns.c371
1 files changed, 150 insertions, 221 deletions
diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c
index 0be9e727..a1b88ae1 100644
--- a/protocols/msn/ns.c
+++ b/protocols/msn/ns.c
@@ -1,7 +1,7 @@
/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
- * Copyright 2002-2004 Wilmer van der Gaast and others *
+ * Copyright 2002-2010 Wilmer van der Gaast and others *
\********************************************************************/
/* MSN module - Notification server callbacks */
@@ -26,15 +26,15 @@
#include <ctype.h>
#include "nogaim.h"
#include "msn.h"
-#include "passport.h"
#include "md5.h"
+#include "soap.h"
+#include "xmltree.h"
static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond );
static int msn_ns_command( gpointer data, char **cmd, int num_parts );
static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts );
-static void msn_auth_got_passport_token( struct msn_auth_data *mad );
-static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name );
+static void msn_ns_send_adl( struct im_connection *ic );
gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
{
@@ -72,7 +72,7 @@ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond )
md->handler->fd = md->fd;
md->handler->rxq = g_new0( char, 1 );
- g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
+ g_snprintf( s, sizeof( s ), "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER );
if( msn_write( ic, s, strlen( s ) ) )
{
ic->inpa = b_input_add( md->fd, B_EV_IO_READ, msn_ns_callback, ic );
@@ -112,7 +112,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
if( strcmp( cmd[0], "VER" ) == 0 )
{
- if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
+ if( cmd[2] && strncmp( cmd[2], MSNP_VER, 5 ) != 0 )
{
imcb_error( ic, "Unsupported protocol" );
imc_logout( ic, FALSE );
@@ -126,7 +126,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
else if( strcmp( cmd[0], "CVR" ) == 0 )
{
/* We don't give a damn about the information we just received */
- g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user );
+ g_snprintf( buf, sizeof( buf ), "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user );
return( msn_write( ic, buf, strlen( buf ) ) );
}
else if( strcmp( cmd[0], "XFR" ) == 0 )
@@ -134,7 +134,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
char *server;
int port;
- if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 )
+ if( num_parts >= 6 && strcmp( cmd[2], "NS" ) == 0 )
{
b_event_remove( ic->inpa );
ic->inpa = 0;
@@ -155,7 +155,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
md->fd = proxy_connect( server, port, msn_ns_connected, ic );
}
- else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 )
+ else if( num_parts >= 6 && strcmp( cmd[2], "SB" ) == 0 )
{
struct msn_switchboard *sb;
@@ -219,27 +219,15 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
}
else if( strcmp( cmd[0], "USR" ) == 0 )
{
- if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 )
+ if( num_parts >= 6 && strcmp( cmd[2], "SSO" ) == 0 &&
+ strcmp( cmd[3], "S" ) == 0 )
{
- /* Time for some Passport black magic... */
- if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) )
- {
- imcb_error( ic, "Error while contacting Passport server" );
- imc_logout( ic, TRUE );
- return( 0 );
- }
+ msn_soap_passport_sso_request( ic, cmd[4], cmd[5] );
}
- else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 )
+ else if( strcmp( cmd[2], "OK" ) == 0 )
{
- if( num_parts == 7 )
- msn_ns_got_display_name( ic, cmd[4] );
- else
- imcb_log( ic, "Warning: Friendly name in server response was corrupted" );
-
imcb_log( ic, "Authenticated, getting buddy list" );
-
- g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId );
- return( msn_write( ic, buf, strlen( buf ) ) );
+ msn_soap_memlist_request( ic );
}
else
{
@@ -250,7 +238,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
}
else if( strcmp( cmd[0], "MSG" ) == 0 )
{
- if( num_parts != 4 )
+ if( num_parts < 4 )
{
imcb_error( ic, "Syntax error" );
imc_logout( ic, TRUE );
@@ -266,131 +254,51 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
return( 0 );
}
}
- else if( strcmp( cmd[0], "SYN" ) == 0 )
+ else if( strcmp( cmd[0], "BLP" ) == 0 )
{
- if( num_parts == 5 )
- {
- int i, groupcount;
-
- groupcount = atoi( cmd[4] );
- if( groupcount > 0 )
- {
- /* valgrind says this is leaking memory, I'm guessing
- that this happens during server redirects. */
- if( md->grouplist )
- {
- for( i = 0; i < md->groupcount; i ++ )
- g_free( md->grouplist[i] );
- g_free( md->grouplist );
- }
-
- md->groupcount = groupcount;
- md->grouplist = g_new0( char *, md->groupcount );
- }
-
- md->buddycount = atoi( cmd[3] );
- if( !*cmd[3] || md->buddycount == 0 )
- msn_logged_in( ic );
- }
- else
- {
- /* Hrrm... This SYN reply doesn't really look like something we expected.
- Let's assume everything is okay. */
-
- msn_logged_in( ic );
- }
+ msn_ns_send_adl( ic );
}
- else if( strcmp( cmd[0], "LST" ) == 0 )
+ else if( strcmp( cmd[0], "ADL" ) == 0 )
{
- int list;
-
- if( num_parts != 4 && num_parts != 5 )
- {
- imcb_error( ic, "Syntax error" );
- imc_logout( ic, TRUE );
- return( 0 );
- }
-
- http_decode( cmd[2] );
- list = atoi( cmd[3] );
-
- if( list & 1 ) /* FL */
+ if( num_parts >= 3 && strcmp( cmd[2], "OK" ) == 0 )
{
- char *group = NULL;
- int num;
+ char buf[1024];
+ char *fn_raw = set_getstr( &ic->acc->set, "display_name" );
+ char *fn;
- if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount )
- group = md->grouplist[num];
+ if( fn_raw == NULL )
+ fn_raw = ic->acc->user;
+ fn = g_malloc( strlen( fn_raw ) * 3 + 1 );
+ strcpy( fn, fn_raw );
+ http_encode( fn );
- imcb_add_buddy( ic, cmd[1], group );
- imcb_rename_buddy( ic, cmd[1], cmd[2] );
- }
- if( list & 2 ) /* AL */
- {
- ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) );
- }
- if( list & 4 ) /* BL */
- {
- ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) );
- }
- if( list & 8 ) /* RL */
- {
- if( ( list & 6 ) == 0 )
- msn_buddy_ask( ic, cmd[1], cmd[2] );
- }
-
- if( --md->buddycount == 0 )
- {
- if( ic->flags & OPT_LOGGED_IN )
- {
- imcb_log( ic, "Successfully transferred to different server" );
- g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 );
- return( msn_write( ic, buf, strlen( buf ) ) );
- }
- else
- {
- msn_logged_in( ic );
- }
+ g_snprintf( buf, sizeof( buf ), "PRP %d MFN %s\r\n",
+ ++md->trId, fn );
+ g_free( fn );
+
+ msn_write( ic, buf, strlen( buf ) );
}
}
- else if( strcmp( cmd[0], "LSG" ) == 0 )
+ else if( strcmp( cmd[0], "PRP" ) == 0 )
{
- int num;
-
- if( num_parts != 4 )
- {
- imcb_error( ic, "Syntax error" );
- imc_logout( ic, TRUE );
- return( 0 );
- }
-
- http_decode( cmd[2] );
- num = atoi( cmd[1] );
-
- if( num < md->groupcount )
- md->grouplist[num] = g_strdup( cmd[2] );
+ imcb_connected( ic );
}
else if( strcmp( cmd[0], "CHL" ) == 0 )
{
- md5_state_t state;
- md5_byte_t digest[16];
- int i;
+ char *resp;
- if( num_parts != 3 )
+ if( num_parts < 3 )
{
imcb_error( ic, "Syntax error" );
imc_logout( ic, TRUE );
return( 0 );
}
- md5_init( &state );
- md5_append( &state, (const md5_byte_t *) cmd[2], strlen( cmd[2] ) );
- md5_append( &state, (const md5_byte_t *) QRY_CODE, strlen( QRY_CODE ) );
- md5_finish( &state, digest );
-
- g_snprintf( buf, sizeof( buf ), "QRY %d %s %d\r\n", ++md->trId, QRY_NAME, 32 );
- for( i = 0; i < 16; i ++ )
- g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] );
+ resp = msn_p11_challenge( cmd[2] );
+ g_snprintf( buf, sizeof( buf ), "QRY %d %s %zd\r\n%s",
+ ++md->trId, MSNP11_PROD_ID,
+ strlen( resp ), resp );
+ g_free( resp );
return( msn_write( ic, buf, strlen( buf ) ) );
}
@@ -398,15 +306,15 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
{
const struct msn_away_state *st;
- if( num_parts != 6 )
+ if( num_parts < 6 )
{
imcb_error( ic, "Syntax error" );
imc_logout( ic, TRUE );
return( 0 );
}
- http_decode( cmd[4] );
- imcb_rename_buddy( ic, cmd[3], cmd[4] );
+ http_decode( cmd[5] );
+ imcb_rename_buddy( ic, cmd[3], cmd[5] );
st = msn_away_state_by_code( cmd[2] );
if( !st )
@@ -432,15 +340,15 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
{
const struct msn_away_state *st;
- if( num_parts != 5 )
+ if( num_parts < 5 )
{
imcb_error( ic, "Syntax error" );
imc_logout( ic, TRUE );
return( 0 );
}
- http_decode( cmd[3] );
- imcb_rename_buddy( ic, cmd[2], cmd[3] );
+ http_decode( cmd[4] );
+ imcb_rename_buddy( ic, cmd[2], cmd[4] );
st = msn_away_state_by_code( cmd[1] );
if( !st )
@@ -461,7 +369,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
char *server;
int session, port;
- if( num_parts != 7 )
+ if( num_parts < 7 )
{
imcb_error( ic, "Syntax error" );
imc_logout( ic, TRUE );
@@ -505,7 +413,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
}
else if( strcmp( cmd[0], "ADD" ) == 0 )
{
- if( num_parts == 6 && strcmp( cmd[2], "RL" ) == 0 )
+ if( num_parts >= 6 && strcmp( cmd[2], "RL" ) == 0 )
{
GSList *l;
@@ -564,40 +472,6 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
imc_logout( ic, allow_reconnect );
return( 0 );
}
-#if 0
- /* Discard this one completely for now since I don't care about the ack
- and since MSN servers can apparently screw up the formatting. */
- else if( strcmp( cmd[0], "REA" ) == 0 )
- {
- if( num_parts != 5 )
- {
- imcb_error( ic, "Syntax error" );
- imc_logout( ic, TRUE );
- return( 0 );
- }
-
- if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 )
- {
- set_t *s;
-
- http_decode( cmd[4] );
- strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) );
- ic->displayname[sizeof(ic->displayname)-1] = 0;
-
- if( ( s = set_find( &ic->acc->set, "display_name" ) ) )
- {
- g_free( s->value );
- s->value = g_strdup( cmd[4] );
- }
- }
- else
- {
- /* This is not supposed to happen, but let's handle it anyway... */
- http_decode( cmd[4] );
- imcb_rename_buddy( ic, cmd[3], cmd[4] );
- }
- }
-#endif
else if( strcmp( cmd[0], "IPG" ) == 0 )
{
imcb_error( ic, "Received IPG command, we don't handle them yet." );
@@ -655,6 +529,25 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts )
}
}
}
+ else if( strcmp( cmd[0], "GCF" ) == 0 )
+ {
+ /* Coming up is cmd[2] bytes of stuff we're supposed to
+ censore. Meh. */
+ md->handler->msglen = atoi( cmd[2] );
+ }
+ else if( strcmp( cmd[0], "UBX" ) == 0 )
+ {
+ /* Status message. Parser coming soon. */
+ if( num_parts >= 4 )
+ md->handler->msglen = atoi( cmd[3] );
+ }
+ else if( strcmp( cmd[0], "NOT" ) == 0 )
+ {
+ /* Some kind of notification, not sure if it still exists
+ but we have to skip the payload or stuff breaks. */
+ if( num_parts >= 3 )
+ md->handler->msglen = atoi( cmd[2] );
+ }
else if( isdigit( cmd[0][0] ) )
{
int num = atoi( cmd[0] );
@@ -764,13 +657,25 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int
g_free( ct );
}
}
+ else if( strcmp( cmd[0], "UBX" ) == 0 )
+ {
+ struct xt_node *psm;
+ char *psm_text = NULL;
+
+ psm = xt_from_string( msg );
+ if( psm && strcmp( psm->name, "Data" ) == 0 &&
+ ( psm = xt_find_node( psm->children, "PSM" ) ) )
+ psm_text = psm->text;
+
+ imcb_buddy_status_msg( ic, cmd[1], psm_text );
+ xt_free_node( psm );
+ }
return( 1 );
}
-static void msn_auth_got_passport_token( struct msn_auth_data *mad )
+void msn_auth_got_passport_token( struct im_connection *ic, char *token )
{
- struct im_connection *ic = mad->data;
struct msn_data *md;
/* Dead connection? */
@@ -778,61 +683,85 @@ static void msn_auth_got_passport_token( struct msn_auth_data *mad )
return;
md = ic->proto_data;
- if( mad->token )
+
{
char buf[1024];
- g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token );
+ g_snprintf( buf, sizeof( buf ), "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token );
msn_write( ic, buf, strlen( buf ) );
}
- else
- {
- imcb_error( ic, "Error during Passport authentication: %s", mad->error );
- imc_logout( ic, TRUE );
- }
}
-static gboolean msn_ns_got_display_name( struct im_connection *ic, char *name )
+void msn_auth_got_contact_list( struct im_connection *ic )
{
- set_t *s;
+ char buf[64];
+ struct msn_data *md;
- if( ( s = set_find( &ic->acc->set, "display_name" ) ) == NULL )
- return FALSE; /* Shouldn't happen.. */
+ /* Dead connection? */
+ if( g_slist_find( msn_connections, ic ) == NULL )
+ return;
- http_decode( name );
+ md = ic->proto_data;
- if( s->value && strcmp( s->value, name ) == 0 )
- {
- return TRUE;
- /* The names match, nothing to worry about. */
- }
- else if( s->value != NULL &&
- ( strcmp( name, ic->acc->user ) == 0 ||
- set_getbool( &ic->acc->set, "local_display_name" ) ) )
- {
- /* The server thinks our display name is our e-mail address
- which is probably wrong, or the user *wants* us to do this:
- Always use the locally set display_name. */
- return msn_set_display_name( ic, s->value );
- }
- else
+
+ g_snprintf( buf, sizeof( buf ), "BLP %d %s\r\n", ++md->trId, "BL" );
+ msn_write( ic, buf, strlen( buf ) );
+}
+
+static gboolean msn_ns_send_adl_1( gpointer key, gpointer value, gpointer data )
+{
+ struct xt_node *adl = data, *d, *c;
+ struct bee_user *bu = value;
+ struct msn_buddy_data *bd = bu->data;
+ char handle[strlen(bu->handle)];
+ char *domain;
+ char l[4];
+
+ strcpy( handle, bu->handle );
+ if( ( domain = strchr( handle, '@' ) ) == NULL ) /* WTF */
+ return FALSE;
+ *domain = '\0';
+ domain ++;
+
+ if( ( d = adl->children ) == NULL ||
+ g_strcasecmp( xt_find_attr( d, "n" ), domain ) != 0 )
{
- if( s->value && *s->value )
- imcb_log( ic, "BitlBee thinks your display name is `%s' but "
- "the MSN server says it's `%s'. Using the MSN "
- "server's name. Set local_display_name to true "
- "to use the local name.", s->value, name );
-
- if( g_utf8_validate( name, -1, NULL ) )
- {
- g_free( s->value );
- s->value = g_strdup( name );
- }
- else
- {
- imcb_log( ic, "Warning: Friendly name in server response was corrupted" );
- }
-
- return TRUE;
+ d = xt_new_node( "d", NULL, NULL );
+ xt_add_attr( d, "n", domain );
+ xt_insert_child( adl, d );
}
+
+ g_snprintf( l, sizeof( l ), "%d", bd->flags & 7 );
+ c = xt_new_node( "c", NULL, NULL );
+ xt_add_attr( c, "n", handle );
+ xt_add_attr( c, "l", l );
+ xt_add_attr( c, "t", "1" ); /* 1 means normal, 4 means mobile? */
+ xt_insert_child( d, c );
+
+ return FALSE;
+}
+
+static void msn_ns_send_adl( struct im_connection *ic )
+{
+ struct xt_node *adl;
+ struct msn_data *md;
+ char *adls, buf[64];
+
+ /* Dead connection? */
+ if( g_slist_find( msn_connections, ic ) == NULL )
+ return;
+
+ md = ic->proto_data;
+
+ adl = xt_new_node( "ml", NULL, NULL );
+ xt_add_attr( adl, "l", "1" );
+ g_tree_foreach( md->domaintree, msn_ns_send_adl_1, adl );
+ adls = xt_to_string( adl );
+
+ g_snprintf( buf, sizeof( buf ), "ADL %d %zd\r\n", ++md->trId, strlen( adls ) );
+ if( msn_write( ic, buf, strlen( buf ) ) )
+ msn_write( ic, adls, strlen( adls ) );
+
+ g_free( adls );
+ xt_free_node( adl );
}