aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/msn/msn_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/msn/msn_util.c')
-rw-r--r--protocols/msn/msn_util.c291
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 );
}