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.c197
1 files changed, 151 insertions, 46 deletions
diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c
index a2f1b4bd..a90c8a9d 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, 0 );
+ 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 );
+ }
+}