diff options
Diffstat (limited to 'protocols/msn/msn_util.c')
| -rw-r--r-- | protocols/msn/msn_util.c | 291 | 
1 files changed, 218 insertions, 73 deletions
| diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 23447403..7fa68915 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.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 - Miscellaneous utilities                                 */ @@ -25,37 +25,41 @@  #include "nogaim.h"  #include "msn.h" +#include "md5.h" +#include "soap.h"  #include <ctype.h> -int msn_write( struct im_connection *ic, char *s, int len ) +int msn_logged_in( struct im_connection *ic )  { -	struct msn_data *md = ic->proto_data; -	int st; -	 -	st = write( md->fd, s, len ); -	if( st != len ) -	{ -		imcb_error( ic, "Short write() to main server" ); -		imc_logout( ic, TRUE ); -		return 0; -	} +	imcb_connected( ic ); -	return 1; +	return( 0 );  } -int msn_logged_in( struct im_connection *ic ) +static char *adlrml_entry( const char *handle_, msn_buddy_flags_t list )  { -	imcb_connected( ic ); +	char *domain, handle[strlen(handle_)+1]; -	return( 0 ); +	strcpy( handle, handle_ ); +	if( ( domain = strchr( handle, '@' ) ) ) +		*(domain++) = '\0'; +	else +		return NULL; +	 +	return g_markup_printf_escaped( "<ml><d n=\"%s\"><c n=\"%s\" l=\"%d\" t=\"1\"/></d></ml>", +		domain, handle, list );  } -int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *who, const char *realname_, const char *group ) +int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group )  {  	struct msn_data *md = ic->proto_data; -	char buf[1024], *realname, groupid[8]; +	char groupid[8]; +	bee_user_t *bu; +	struct msn_buddy_data *bd; +	char *adl;  	*groupid = '\0'; +#if 0  	if( group )  	{  		int i; @@ -86,9 +90,10 @@ int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *  			if( l == NULL )  			{ -				char *groupname = msn_http_encode( group ); +				char groupname[strlen(group)+1]; +				strcpy( groupname, group ); +				http_encode( groupname );  				g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 ); -				g_free( groupname );  				return msn_write( ic, buf, strlen( buf ) );  			}  			else @@ -100,20 +105,42 @@ int msn_buddy_list_add( struct im_connection *ic, const char *list, const char *  			}  		}  	} +#endif +	 +	if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) || +	       ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) || +	    !( bd = bu->data ) || bd->flags & list ) +		return 1; +	 +	bd->flags |= list; -	realname = msn_http_encode( realname_ ); -	g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s%s\r\n", ++md->trId, list, who, realname, groupid ); -	g_free( realname ); +	if( list == MSN_BUDDY_FL ) +		msn_soap_ab_contact_add( ic, bu ); +	else +		msn_soap_memlist_edit( ic, who, TRUE, list ); -	return msn_write( ic, buf, strlen( buf ) ); +	if( ( adl = adlrml_entry( who, list ) ) ) +	{ +		int st = msn_ns_write( ic, -1, "ADL %d %zd\r\n%s", +		                       ++md->trId, strlen( adl ), adl ); +		g_free( adl ); +		 +		return st; +	} +	 +	return 1;  } -int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who, const char *group ) +int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group )  {  	struct msn_data *md = ic->proto_data; -	char buf[1024], groupid[8]; +	char groupid[8]; +	bee_user_t *bu; +	struct msn_buddy_data *bd; +	char *adl;  	*groupid = '\0'; +#if 0  	if( group )  	{  		int i; @@ -124,12 +151,29 @@ int msn_buddy_list_remove( struct im_connection *ic, char *list, const char *who  				break;  			}  	} +#endif -	g_snprintf( buf, sizeof( buf ), "REM %d %s %s%s\r\n", ++md->trId, list, who, groupid ); -	if( msn_write( ic, buf, strlen( buf ) ) ) -		return( 1 ); +	if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) || +	    !( bd = bu->data ) || !( bd->flags & list ) ) +		return 1; -	return( 0 ); +	bd->flags &= ~list; +	 +	if( list == MSN_BUDDY_FL ) +		msn_soap_ab_contact_del( ic, bu ); +	else +		msn_soap_memlist_edit( ic, who, FALSE, list ); +	 +	if( ( adl = adlrml_entry( who, list ) ) ) +	{ +		int st = msn_ns_write( ic, -1, "RML %d %zd\r\n%s", +		                       ++md->trId, strlen( adl ), adl ); +		g_free( adl ); +		 +		return st; +	} +	 +	return 1;  }  struct msn_buddy_ask_data @@ -143,7 +187,7 @@ static void msn_buddy_ask_yes( void *data )  {  	struct msn_buddy_ask_data *bla = data; -	msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname, NULL ); +	msn_buddy_list_add( bla->ic, MSN_BUDDY_AL, bla->handle, bla->realname, NULL );  	imcb_ask_add( bla->ic, bla->handle, NULL ); @@ -156,26 +200,31 @@ static void msn_buddy_ask_no( void *data )  {  	struct msn_buddy_ask_data *bla = data; -	msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname, NULL ); +	msn_buddy_list_add( bla->ic, MSN_BUDDY_BL, bla->handle, bla->realname, NULL );  	g_free( bla->handle );  	g_free( bla->realname );  	g_free( bla );  } -void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ) +void msn_buddy_ask( bee_user_t *bu )  { -	struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 ); +	struct msn_buddy_ask_data *bla; +	struct msn_buddy_data *bd = bu->data;  	char buf[1024]; -	bla->ic = ic; -	bla->handle = g_strdup( handle ); -	bla->realname = g_strdup( realname ); +	if( ( bd->flags & 30 ) != 8 && ( bd->flags & 30 ) != 16 ) +		return; +	 +	bla = g_new0( struct msn_buddy_ask_data, 1 ); +	bla->ic = bu->ic; +	bla->handle = g_strdup( bu->handle ); +	bla->realname = g_strdup( bu->fullname );  	g_snprintf( buf, sizeof( buf ),  	            "The user %s (%s) wants to add you to his/her buddy list.", -	            handle, realname ); -	imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); +	            bu->handle, bu->fullname ); +	imcb_ask( bu->ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no );  }  char *msn_findheader( char *text, char *header, int len ) @@ -279,6 +328,12 @@ int msn_handler( struct msn_handler_data *h )  	if( st <= 0 )  		return( -1 ); +	if( getenv( "BITLBEE_DEBUG" ) ) +	{ +		write( 2, "->C:", 4 ); +		write( 2, h->rxq + h->rxlen - st, st ); +	} +	  	while( st )  	{  		int i; @@ -295,7 +350,7 @@ int msn_handler( struct msn_handler_data *h )  					cmd_text = g_strndup( h->rxq, i );  					cmd = msn_linesplit( cmd_text );  					for( count = 0; cmd[count]; count ++ ); -					st = h->exec_command( h->data, cmd, count ); +					st = h->exec_command( h, cmd, count );  					g_free( cmd_text );  					/* If the connection broke, don't continue. We don't even exist anymore. */ @@ -330,7 +385,7 @@ int msn_handler( struct msn_handler_data *h )  			cmd = msn_linesplit( h->cmd_text );  			for( count = 0; cmd[count]; count ++ ); -			st = h->exec_message( h->data, msg, h->msglen, cmd, count ); +			st = h->exec_message( h, msg, h->msglen, cmd, count );  			g_free( msg );  			g_free( h->cmd_text );  			h->cmd_text = NULL; @@ -366,32 +421,6 @@ int msn_handler( struct msn_handler_data *h )  	return( 1 );  } -/* The difference between this function and the normal http_encode() function -   is that this one escapes every 7-bit ASCII character because this is said -   to avoid some lame server-side checks when setting a real-name. Also, -   non-ASCII characters are not escaped because MSN servers don't seem to -   appreciate that! */ -char *msn_http_encode( const char *input ) -{ -	char *ret, *s; -	int i; -	 -	ret = s = g_new0( char, strlen( input ) * 3 + 1 ); -	for( i = 0; input[i]; i ++ ) -		if( input[i] & 128 ) -		{ -			*s = input[i]; -			s ++; -		} -		else -		{ -			g_snprintf( s, 4, "%%%02X", input[i] ); -			s += 3; -		} -	 -	return ret; -} -  void msn_msgq_purge( struct im_connection *ic, GSList **list )  {  	struct msn_message *m; @@ -432,14 +461,130 @@ void msn_msgq_purge( struct im_connection *ic, GSList **list )  	g_string_free( ret, TRUE );  } -gboolean msn_set_display_name( struct im_connection *ic, const char *rawname ) +/* Copied and heavily modified from http://tmsnc.sourceforge.net/chl.c */ +char *msn_p11_challenge( char *challenge ) +{ +	char *output, buf[256]; +	md5_state_t md5c; +	unsigned char md5Hash[16], *newHash; +	unsigned int *md5Parts, *chlStringParts, newHashParts[5]; +	long long nHigh = 0, nLow = 0; +	int i, n; + +	/* Create the MD5 hash */ +	md5_init(&md5c); +	md5_append(&md5c, (unsigned char*) challenge, strlen(challenge)); +	md5_append(&md5c, (unsigned char*) MSNP11_PROD_KEY, strlen(MSNP11_PROD_KEY)); +	md5_finish(&md5c, md5Hash); + +	/* Split it into four integers */ +	md5Parts = (unsigned int *)md5Hash; +	for (i = 0; i < 4; i ++) +	{   +		md5Parts[i] = GUINT32_TO_LE(md5Parts[i]); +		 +		/* & each integer with 0x7FFFFFFF */ +		/* and save one unmodified array for later */ +		newHashParts[i] = md5Parts[i]; +		md5Parts[i] &= 0x7FFFFFFF; +	} +	 +	/* make a new string and pad with '0' */ +	n = g_snprintf(buf, sizeof(buf)-5, "%s%s00000000", challenge, MSNP11_PROD_ID); +	/* truncate at an 8-byte boundary */ +	buf[n&=~7] = '\0'; +	 +	/* split into integers */ +	chlStringParts = (unsigned int *)buf; +	 +	/* this is magic */ +	for (i = 0; i < (n / 4) - 1; i += 2) +	{ +		long long temp; + +		chlStringParts[i]   = GUINT32_TO_LE(chlStringParts[i]); +		chlStringParts[i+1] = GUINT32_TO_LE(chlStringParts[i+1]); + +		temp  = (md5Parts[0] * (((0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF)+nHigh) + md5Parts[1])%0x7FFFFFFF; +		nHigh = (md5Parts[2] * (((long long)chlStringParts[i+1]+temp) % 0x7FFFFFFF) + md5Parts[3]) % 0x7FFFFFFF; +		nLow  = nLow + nHigh + temp; +	} +	nHigh = (nHigh+md5Parts[1]) % 0x7FFFFFFF; +	nLow = (nLow+md5Parts[3]) % 0x7FFFFFFF; +	 +	newHashParts[0] ^= nHigh; +	newHashParts[1] ^= nLow; +	newHashParts[2] ^= nHigh; +	newHashParts[3] ^= nLow; +	 +	/* swap more bytes if big endian */ +	for (i = 0; i < 4; i ++) +		newHashParts[i] = GUINT32_TO_LE(newHashParts[i]);  +	 +	/* make a string of the parts */ +	newHash = (unsigned char *)newHashParts; +	 +	/* convert to hexadecimal */ +	output = g_new(char, 33); +	for (i = 0; i < 16; i ++) +		sprintf(output + i * 2, "%02x", newHash[i]); +	 +	return output; +} + +gint msn_domaintree_cmp( gconstpointer a_, gconstpointer b_ ) +{ +	const char *a = a_, *b = b_; +	gint ret; +	 +	if( !( a = strchr( a, '@' ) ) || !( b = strchr( b, '@' ) ) || +	    ( ret = strcmp( a, b ) ) == 0 ) +		ret = strcmp( a_, b_ ); +	 +	return ret; +} + +struct msn_group *msn_group_by_name( struct im_connection *ic, const char *name )  { -	char *fn = msn_http_encode( rawname );  	struct msn_data *md = ic->proto_data; -	char buf[1024]; +	GSList *l; +	 +	for( l = md->groups; l; l = l->next ) +	{ +		struct msn_group *mg = l->data; +		 +		if( g_strcasecmp( mg->name, name ) == 0 ) +			return mg; +	} +	 +	return NULL; +} + +struct msn_group *msn_group_by_id( struct im_connection *ic, const char *id ) +{ +	struct msn_data *md = ic->proto_data; +	GSList *l; +	 +	for( l = md->groups; l; l = l->next ) +	{ +		struct msn_group *mg = l->data; +		 +		if( g_strcasecmp( mg->id, id ) == 0 ) +			return mg; +	} +	 +	return NULL; +} + +int msn_ns_set_display_name( struct im_connection *ic, const char *value ) +{ +	struct msn_data *md = ic->proto_data; +	char fn[strlen(value)*3+1]; -	g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); -	g_free( fn ); +	strcpy( fn, value ); +	http_encode( fn ); -	return msn_write( ic, buf, strlen( buf ) ) != 0; +	/* Note: We don't actually know if the server accepted the new name, +	   and won't give proper feedback yet if it doesn't. */ +	return msn_ns_write( ic, -1, "PRP %d MFN %s\r\n", ++md->trId, fn );  } | 
