aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/msn/msn_util.c
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2010-10-01 22:34:53 -0700
committerWilmer van der Gaast <wilmer@gaast.net>2010-10-01 22:34:53 -0700
commit62f53b508742804d5df6533150f17d41e6afcbb2 (patch)
treee01a02a2a730110dde6ded977458090859fe2115 /protocols/msn/msn_util.c
parent05bf2a0d55999c944ac6cf03ad85270cb2165923 (diff)
parent04cd284bce74c114fde3043c951a5c8ef9eb79ae (diff)
Merging msnp13 branch which, confusingly, upgrades the msn module to use
MSNP15. (The reason for this is that A) IMHO MSNP13 is what causes most of the pain in this upgade and B) I initially intended to only implement MSNP13 but then discovered MS doesn't support it anymore.) This fixes issues with display names being forgotten, adding contacts (and them automatically getting blocked sometimes!!), and adds support for away/status messages and some support for sending offline messages.
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 );
}