diff options
Diffstat (limited to 'protocols/msn/ns.c')
| -rw-r--r-- | protocols/msn/ns.c | 197 | 
1 files changed, 151 insertions, 46 deletions
| diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 5436270e..a4785eb2 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-2010 Wilmer van der Gaast and others                * +  * Copyright 2002-2012 Wilmer van der Gaast and others                *    \********************************************************************/  /* MSN module - Notification server callbacks                           */ @@ -24,9 +24,11 @@  */  #include <ctype.h> +#include <sys/utsname.h>  #include "nogaim.h"  #include "msn.h"  #include "md5.h" +#include "sha1.h"  #include "soap.h"  #include "xmltree.h" @@ -110,6 +112,23 @@ static gboolean msn_ns_connected( gpointer data, gint source, b_input_condition  	handler->rxlen = 0;  	handler->rxq = g_new0( char, 1 ); +	if( md->uuid == NULL ) +	{ +		struct utsname name; +		sha1_state_t sha[1]; +		 +		/* UUID == SHA1("BitlBee" + my hostname + MSN username) */ +		sha1_init( sha ); +		sha1_append( sha, (void*) "BitlBee", 7 ); +		if( uname( &name ) == 0 ) +		{ +			sha1_append( sha, (void*) name.nodename, strlen( name.nodename ) ); +		} +		sha1_append( sha, (void*) ic->acc->user, strlen( ic->acc->user ) ); +		md->uuid = sha1_random_uuid( sha ); +		memcpy( md->uuid, "b171be3e", 8 ); /* :-P */ +	} +	  	if( msn_ns_write( ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER ) )  	{  		handler->inpa = b_input_add( handler->fd, B_EV_IO_READ, msn_ns_callback, handler ); @@ -352,9 +371,11 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num  		g_free( resp );  		return st;  	} -	else if( strcmp( cmd[0], "ILN" ) == 0 ) +	else if( strcmp( cmd[0], "ILN" ) == 0 || strcmp( cmd[0], "NLN" ) == 0 )  	{  		const struct msn_away_state *st; +		const char *handle; +		int cap = 0;  		if( num_parts < 6 )  		{ @@ -362,59 +383,45 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num  			imc_logout( ic, TRUE );  			return( 0 );  		} +		/* ILN and NLN are more or less the same, except ILN has a trId +		   at the start, and NLN has a capability field at the end.  +		   Does ILN still exist BTW? */ +		if( cmd[0][1] == 'I' ) +			cmd ++; +		else +			cap = atoi( cmd[4] ); + +		handle = msn_normalize_handle( cmd[2] ); +		if( strcmp( handle, ic->acc->user ) == 0 ) +			return 1; /* That's me! */ -		http_decode( cmd[5] ); -		imcb_rename_buddy( ic, cmd[3], cmd[5] ); +		http_decode( cmd[3] ); +		imcb_rename_buddy( ic, handle, cmd[3] ); -		st = msn_away_state_by_code( cmd[2] ); +		st = msn_away_state_by_code( cmd[1] );  		if( !st )  		{  			/* FIXME: Warn/Bomb about unknown away state? */  			st = msn_away_state_list + 1;  		} -		imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN |  -		                   ( st != msn_away_state_list ? OPT_AWAY : 0 ), +		imcb_buddy_status( ic, handle, OPT_LOGGED_IN |  +		                   ( st != msn_away_state_list ? OPT_AWAY : 0 ) | +		                   ( cap & 1 ? OPT_MOBILE : 0 ),  		                   st->name, NULL ); +		 +		msn_sb_stop_keepalives( msn_sb_by_handle( ic, handle ) );  	}  	else if( strcmp( cmd[0], "FLN" ) == 0 )  	{ +		const char *handle; +		  		if( cmd[1] == NULL )  			return 1; -		imcb_buddy_status( ic, cmd[1], 0, NULL, NULL ); -		 -		msn_sb_start_keepalives( msn_sb_by_handle( ic, cmd[1] ), TRUE ); -	} -	else if( strcmp( cmd[0], "NLN" ) == 0 ) -	{ -		const struct msn_away_state *st; -		int cap; -		 -		if( num_parts < 6 ) -		{ -			imcb_error( ic, "Syntax error" ); -			imc_logout( ic, TRUE ); -			return( 0 ); -		} -		 -		http_decode( cmd[4] ); -		cap = atoi( cmd[5] ); -		imcb_rename_buddy( ic, cmd[2], cmd[4] ); -		 -		st = msn_away_state_by_code( cmd[1] ); -		if( !st ) -		{ -			/* FIXME: Warn/Bomb about unknown away state? */ -			st = msn_away_state_list + 1; -		} -		 -		imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN |  -		                   ( st != msn_away_state_list ? OPT_AWAY : 0 ) | -		                   ( cap & 1 ? OPT_MOBILE : 0 ), -		                   st->name, NULL ); -		 -		msn_sb_stop_keepalives( msn_sb_by_handle( ic, cmd[2] ) ); +		handle = msn_normalize_handle( cmd[1] ); +		imcb_buddy_status( ic, handle, 0, NULL, NULL ); +		msn_sb_start_keepalives( msn_sb_by_handle( ic, handle ), TRUE );  	}  	else if( strcmp( cmd[0], "RNG" ) == 0 )  	{ @@ -461,7 +468,7 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num  		}  		else  		{ -			sb->who = g_strdup( cmd[5] ); +			sb->who = g_strdup( msn_normalize_handle( cmd[5] ) );  		}  	}  	else if( strcmp( cmd[0], "OUT" ) == 0 ) @@ -554,8 +561,8 @@ static int msn_ns_command( struct msn_handler_data *handler, char **cmd, int num  	else if( strcmp( cmd[0], "UBX" ) == 0 )  	{  		/* Status message. */ -		if( num_parts >= 4 ) -			handler->msglen = atoi( cmd[3] ); +		if( num_parts >= 3 ) +			handler->msglen = atoi( cmd[2] );  	}  	else if( strcmp( cmd[0], "NOT" ) == 0 )  	{ @@ -667,7 +674,57 @@ static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msgl  			}  			else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 )  			{ -				/* Sorry, but this one really is *USELESS* */ +			} +			else if( g_strncasecmp( ct, "text/x-msmsgsinitialmdatanotification", 37 ) == 0 || +			         g_strncasecmp( ct, "text/x-msmsgsoimnotification", 28 ) == 0 ) +			{ +				/* We received an offline message. Or at least notification +				   that there is one waiting for us. Fetching the message(s) +				   and purging them from the server is a lot of SOAPy work +				   not worth doing IMHO. Also I thought it was possible to +				   have the notification server send them directly, I was +				   pretty sure I saw Pidgin do it.. +				    +				   At least give a notification for now, seems like a +				   reasonable thing to do. Only problem is, they'll keep +				   coming back at login time until you read them using a +				   different client. :-( */ +				 +				char *xml = get_rfc822_header( body, "Mail-Data:", blen ); +				struct xt_node *md, *m; +				 +				if( !xml ) +					return 1; +				md = xt_from_string( xml ); +				if( !md ) +					return 1; +				 +				for( m = md->children; ( m = xt_find_node( m, "M" ) ); m = m->next ) +				{ +					struct xt_node *e = xt_find_node( m->children, "E" ); +					struct xt_node *rt = xt_find_node( m->children, "RT" ); +					struct tm tp; +					time_t msgtime = 0; +					 +					if( !e || !e->text ) +						continue; +					 +					memset( &tp, 0, sizeof( tp ) ); +					if( rt && rt->text && +					    sscanf( rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.", +					            &tp.tm_year, &tp.tm_mon, &tp.tm_mday, +					            &tp.tm_hour, &tp.tm_min, &tp.tm_sec ) == 6 ) +					{ +						tp.tm_year -= 1900; +						tp.tm_mon --; +						msgtime = mktime_utc( &tp ); +						 +					} +					imcb_buddy_msg( ic, e->text, "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, msgtime ); +				} +				 +				g_free( xml ); +				xt_free_node( md );  			}  			else  			{ @@ -687,7 +744,7 @@ static int msn_ns_message( struct msn_handler_data *handler, char *msg, int msgl  		    ( psm = xt_find_node( ubx->children, "PSM" ) ) )  			psm_text = psm->text; -		imcb_buddy_status_msg( ic, cmd[1], psm_text ); +		imcb_buddy_status_msg( ic, msn_normalize_handle( cmd[1] ), psm_text );  		xt_free_node( ubx );  	}  	else if( strcmp( cmd[0], "ADL" ) == 0 ) @@ -756,7 +813,7 @@ void msn_auth_got_passport_token( struct im_connection *ic, const char *token, c  	if( token )  	{ -		msn_ns_write( ic, -1, "USR %d SSO S %s %s\r\n", ++md->trId, md->tokens[0], token ); +		msn_ns_write( ic, -1, "USR %d SSO S %s %s {%s}\r\n", ++md->trId, md->tokens[0], token, md->uuid );  	}  	else  	{ @@ -885,3 +942,51 @@ int msn_ns_finish_login( struct im_connection *ic )  	return 1;  } + +int msn_ns_sendmessage( struct im_connection *ic, bee_user_t *bu, const char *text ) +{ +	struct msn_data *md = ic->proto_data; +	char *buf; +	 +	if( strncmp( text, "\r\r\r", 3 ) == 0 ) +		/* Err. Shouldn't happen but I guess it can. Don't send others +		   any of the "SHAKE THAT THING" messages. :-D */ +		return 1; +	 +	buf = g_strdup_printf( "%s%s", MSN_MESSAGE_HEADERS, text ); +	 +	if( msn_ns_write( ic, -1, "UUM %d %s %d %d %zd\r\n%s", +	                          ++md->trId, bu->handle, +	                          1, /* type == MSN offline message */ +	                          1, /* type == IM (not nudge/typing) */ +	                          strlen( buf ), buf ) ) +		return 1; +	else +		return 0; +} + +void msn_ns_oim_send_queue( struct im_connection *ic, GSList **msgq ) +{ +	GSList *l; +	 +	for( l = *msgq; l; l = l->next ) +	{ +		struct msn_message *m = l->data; +		bee_user_t *bu = bee_user_by_handle( ic->bee, ic, m->who ); +		 +		if( bu ) +			if( !msn_ns_sendmessage( ic, bu, m->text ) ) +				return; +	} +	 +	while( *msgq != NULL ) +	{ +		struct msn_message *m = (*msgq)->data; +		 +		g_free( m->who ); +		g_free( m->text ); +		g_free( m ); +		 +		*msgq = g_slist_remove( *msgq, m ); +	} +} | 
