diff -Nupr bitlbee-1.0.2/commands.c bitlbee-1.0.2-akke/commands.c
--- bitlbee-1.0.2/commands.c	2006-04-01 20:53:38.000000000 +0200
+++ bitlbee-1.0.2-akke/commands.c	2006-04-07 18:06:47.840874980 +0200
@@ -684,6 +684,33 @@ int cmd_save( irc_t *irc, char **cmd )
 	return( 0 );
 }
 
+int user_is_blocked( user_t *u )
+{
+       char *buf;
+       struct gaim_connection *gc = u->gc;
+       GSList *l;
+       int length = strlen( u->user ) + 1 /* @ */ + strlen( u->host ) + 1 /* trailing \x00 */;
+
+       buf = g_new0( char, length + 1 );
+       if ( !buf )
+               return( 0 );
+
+       g_snprintf( buf, length, "%s@%s", u->user, u->host );
+
+        for( l = gc->deny; l; l = l->next )
+               if( g_strcasecmp( l->data, buf ) == 0 )
+                       return( 1 );
+
+       return( 0 );
+}
+
+char *blocked_string( user_t *u )
+{
+       if ( user_is_blocked( u ) )
+               return " (User is blocked!)";
+       return "";
+}
+
 int cmd_blist( irc_t *irc, char **cmd )
 {
 	int online = 0, away = 0, offline = 0;
@@ -707,21 +734,21 @@ int cmd_blist( irc_t *irc, char **cmd )
 	if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away )
 	{
 		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, proto_name[u->gc->user->protocol] );
-		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Online" );
+		irc_usermsg( irc, "%-16.16s  %-40.40s  %s%s", u->nick, s, "Online", blocked_string( u ) );
 		n_online ++;
 	}
 
 	if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away )
 	{
 		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, proto_name[u->gc->user->protocol] );
-		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, u->away );
+		irc_usermsg( irc, "%-16.16s  %-40.40s  %s%s", u->nick, s, u->away, blocked_string( u ) );
 		n_away ++;
 	}
 	
 	if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online )
 	{
 		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, proto_name[u->gc->user->protocol] );
-		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Offline" );
+		irc_usermsg( irc, "%-16.16s  %-40.40s  %s%s", u->nick, s, "Offline", blocked_string( u ) );
 		n_offline ++;
 	}
 	
diff -Nupr bitlbee-1.0.2/irc.c bitlbee-1.0.2-akke/irc.c
--- bitlbee-1.0.2/irc.c	2006-04-01 20:53:39.000000000 +0200
+++ bitlbee-1.0.2-akke/irc.c	2006-04-07 18:06:47.847873934 +0200
@@ -31,6 +31,42 @@ static gboolean irc_userping( gpointer _
 
 GSList *irc_connection_list = NULL;
 
+char *set_update_mymsnbuddyimage(  irc_t *irc, set_t *set, char *value )
+{
+	GSList *c = get_connections();
+	struct gaim_connection *conn;
+
+	if( access( value, R_OK ) == 0 ) /* buddy-image is readable ... */
+	{
+		 if( set->value )			/* stupid hack, but required:		        */
+		 {					/* We need the value before this function ends  */
+			  g_free( set->value );		/* as we call set_getstr() from the msn module  */
+		 }					/* when status is changed. And we do that here! */
+							/* I don't think there's an easier method to    */
+		 set->value = g_strdup( value );	/* trigger a call to a function when a 'set' is */
+							/* done on my_buddy_image			*/
+
+		 while( c )
+		 {
+			  conn = ( struct gaim_connection * ) c->data;	/* We set the away state to the current away state      */
+			  if( conn->protocol == PROTO_MSN )		/* This is how MSN resets it's msnobject so users know  */
+			  {						/* his buddy-image has changed...			*/
+				   if( conn->flags & OPT_LOGGED_IN )	/* Not a real 'hack' here.. it's just microsoft's	*/
+					    proto_away( conn, conn->away ); /* default... lol */
+			  }
+
+			  c = c->next;
+		 }
+	}
+	else /* buddy-image is not readable ... */
+	{
+		 irc_usermsg( irc, "Could not read file '%s'. Keeping current buddy_image...", value);
+		 return NULL;
+	}
+
+	return( value );
+}
+
 irc_t *irc_new( int fd )
 {
 	irc_t *irc = g_new0( irc_t, 1 );
@@ -129,6 +165,26 @@ irc_t *irc_new( int fd )
 	set_add( irc, "to_char", ": ", set_eval_to_char );
 	set_add( irc, "typing_notice", "false", set_eval_bool );
 	
+	/* MSN buddy/emoticon images stuff */
+	set_add( irc, "msn_images_path_buddy", "/tmp/msn", NULL );
+	set_add( irc, "msn_images_path_emoticon", "/tmp/msn", NULL );
+	set_add( irc, "msn_images_mybuddyimage", "/tmp/msn/myimage.png", set_update_mymsnbuddyimage );
+	/* MSN buddy list stuff */
+	set_add( irc, "msn_buddylist_checks", "true", set_eval_bool );
+	/* MSN notify stuff */
+	set_add( irc, "msn_notify_openwindow", "true", set_eval_bool );
+	set_add( irc, "msn_notify_closewindow", "true", set_eval_bool );
+	set_add( irc, "msn_notify_timeout", "true", set_eval_bool );
+	/* MSN font stuff */
+	set_add( irc, "msn_font_face", "MS Shell Dlg", NULL );
+	set_add( irc, "msn_font_CS", "0", set_eval_int );
+	set_add( irc, "msn_font_PF", "22", set_eval_int );
+	set_add( irc, "msn_font_color", "000000", NULL );
+	set_add( irc, "msn_font_bold", "false", set_eval_bool );
+	set_add( irc, "msn_font_italic", "false", set_eval_bool );
+	set_add( irc, "msn_font_overstrike", "false", set_eval_bool );
+	set_add( irc, "msn_font_underline", "false", set_eval_bool );
+
 	conf_loaddefaults( irc );
 	
 	return( irc );
diff -Nupr bitlbee-1.0.2/protocols/msn/Makefile bitlbee-1.0.2-akke/protocols/msn/Makefile
--- bitlbee-1.0.2/protocols/msn/Makefile	2006-04-01 20:53:39.000000000 +0200
+++ bitlbee-1.0.2-akke/protocols/msn/Makefile	2006-04-07 18:06:47.000000000 +0200
@@ -9,7 +9,7 @@
 -include ../../Makefile.settings
 
 # [SH] Program variables
-objects = msn.o msn_util.o ns.o passport.o sb.o tables.o
+objects = msn.o msn_util.o ns.o passport.o sb.o tables.o msnobject.o msnc1.o
 
 CFLAGS += -Wall
 LFLAGS += -r
diff -Nupr bitlbee-1.0.2/protocols/msn/msn.c bitlbee-1.0.2-akke/protocols/msn/msn.c
--- bitlbee-1.0.2/protocols/msn/msn.c	2006-04-01 20:53:39.000000000 +0200
+++ bitlbee-1.0.2-akke/protocols/msn/msn.c	2006-04-07 18:06:47.000000000 +0200
@@ -25,6 +25,8 @@
 
 #include "nogaim.h"
 #include "msn.h"
+#include "msnc1.h"
+#include "msnobject.h"
 
 static struct prpl *my_protocol = NULL;
 
@@ -57,6 +59,9 @@ static void msn_login( struct aim_user *
 		md->away_state = msn_away_state_list;
 		
 		msn_connections = g_slist_append( msn_connections, gc );
+		
+		p2p_init_random();
+		md->msnobject = NULL;
 	}
 }
 
@@ -78,6 +83,10 @@ static void msn_close( struct gaim_conne
 	while( md->switchboards )
 		msn_sb_destroy( md->switchboards->data );
 	
+	msn_cleanup_userinfolist( md );
+	if( md->msnobject )
+		g_free( md->msnobject );
+	
 	if( md->msgq )
 	{
 		struct msn_message *m;
@@ -200,7 +209,15 @@ static void msn_set_away( struct gaim_co
 	if( !st ) st = msn_away_state_list;
 	md->away_state = st;
 	
-	g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code );
+	msn_update_mybuddyimage(gc);
+	if (md->msnobject)
+	{
+		g_snprintf( buf, sizeof( buf ), "CHG %d %s %s %s\r\n", ++md->trId, st->code, CLIENT_ID, md->msnobject );
+	}
+	else
+	{
+		g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, st->code, 0 );
+	}
 	msn_write( gc, buf, strlen( buf ) );
 }
 
@@ -241,7 +258,35 @@ static void msn_set_info( struct gaim_co
 static void msn_get_info(struct gaim_connection *gc, char *who) 
 {
 	/* Just make an URL and let the user fetch the info */
-	serv_got_crap( gc, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who );
+	struct msn_data *md = gc->proto_data;
+	struct msn_userinfo *userinfo = msn_find_userinfo( md, who );
+	if ( userinfo )
+	{
+		char *filename = msn_imagefullpath( gc, userinfo->who, userinfo->msnobject, TYPE_BUDDY_IMAGE, NULL, "png" );
+		if( filename )
+		{
+			if( access( filename, F_OK ) == 0 )
+			{
+				serv_got_crap( gc, "%s\n%s: %s%s\n - buddy-image: %s",
+					_("User Info"), _("For now, fetch yourself"), PROFILE_URL, who, filename);
+			}
+			else
+			{
+				serv_got_crap( gc, "%s\n%s: %s%s\n - buddy-image would be %s, but it's not downloaded yet! :(",
+					_("User Info"), _("For now, fetch yourself"), PROFILE_URL, who, filename);
+			}
+		}
+		else
+		{
+			serv_got_crap( gc, "%s\n%s: %s%s\n - Could not converg msnobject to filename, msnobject: %s",
+				_("User Info"), _("For now, fetch yourself"), PROFILE_URL, who, userinfo->msnobject);
+		}
+	}
+	else
+	{
+		serv_got_crap( gc, "%s\n%s: %s%s\n - He hasn't got a buddy-image!",
+			_("User Info"), _("For now, fetch yourself"), PROFILE_URL, who );
+	}
 }
 
 static void msn_add_buddy( struct gaim_connection *gc, char *who )
diff -Nupr bitlbee-1.0.2/protocols/msn/msnc1.c bitlbee-1.0.2-akke/protocols/msn/msnc1.c
--- bitlbee-1.0.2/protocols/msn/msnc1.c	1970-01-01 01:00:00.000000000 +0100
+++ bitlbee-1.0.2-akke/protocols/msn/msnc1.c	2006-04-07 18:06:47.000000000 +0200
@@ -0,0 +1,1361 @@
+/*
+ * Implementation of the buddy/emoticon - images introduced in MSN6
+ * -----------------------------------------------------------------
+ * 
+ * This is a rather quick-implementation and could probably be
+ * optimized/corrected in many ways. But I don't even like MSN!
+ * I just implemented this because ppl kept asking why I didn't
+ * configure a buddy-image (they don't know what bitlbee is!). 
+ *
+ * So I decided to implement this stupid feature into bitlbee but
+ * I don't realy care about if the code is good or bad. The good
+ * thing is it's working and now ppl can see my face in their MSN
+ * window... And I can see theirs, but like I said, I don't care :p
+ *
+ * Enjoy!
+ *
+ * Andy Knuts (irc://akke && email://djfred@poeperkesdag.be)
+ *
+ */
+ 
+#include "nogaim.h"
+#include "msn.h"
+#include "msnc1.h"
+#include "msnobject.h"
+
+/*
+ * Sets your buddy image to the one specified in the my_buddy_image
+ * setting.
+ */
+void msn_update_mybuddyimage( struct gaim_connection *gc )
+{
+        struct msn_data *md = gc->proto_data;
+        char *filename = set_getstr( gc->irc, "msn_images_mybuddyimage" );
+
+        if ( filename && access( filename, R_OK ) == 0 )
+        {
+                if( md->msnobject )
+                        g_free( md->msnobject );
+                
+                md->msnobject = msnobject_from_params( gc->username, TYPE_BUDDY_IMAGE, filename );
+        }
+        else
+        {
+                do_error_dialog(gc, "Could not create msnobject for my buddy image. Please check your 'my_buddy_image' setting!", "MSN");
+        }
+}
+
+/*
+ * returns the userinfo ( containing msnobject etc... ) for a given user
+ */
+struct msn_userinfo *msn_find_userinfo( struct msn_data *md, char *who )
+{
+        GSList *tmp = md->userinfolist;
+
+        struct msn_userinfo *userinfo;
+
+        while( tmp != NULL )
+        {
+                userinfo = ( struct msn_userinfo * ) tmp->data;
+                if( !strcmp( userinfo->who, who ) )
+                          return userinfo;
+
+                tmp = g_slist_next( tmp );
+        }
+
+        return NULL;
+}
+
+/*
+ * deletes all data from a msn_userinfo struct
+ */
+void msn_cleanup_userinfo( struct msn_userinfo *userinfo )
+{
+	if( userinfo->who )
+	{
+		g_free( userinfo->who );
+		userinfo->who = NULL;
+	}
+	
+	if( userinfo->msnobject )
+	{
+		g_free( userinfo->msnobject );
+		userinfo->msnobject = NULL;
+	}
+}
+
+/*
+ * deleted all userinfo data from a msn_data struct
+ */
+void msn_cleanup_userinfolist( struct msn_data *md )
+{
+        GSList *tmp = md->userinfolist;
+        if( tmp )
+        {
+                while( tmp != NULL )
+                {
+	         	msn_cleanup_userinfo(( struct msn_userinfo* )tmp->data );
+		      	tmp = g_slist_next( tmp );
+                }
+
+                g_slist_free( md->userinfolist );
+                md->userinfolist = NULL;
+        }
+}
+
+/*
+ * add or update an existing userinfo in md->userinfolist GSList
+ */
+void msn_add_or_update_userinfolist( struct gaim_connection *gc, struct msn_userinfo *new_userinfo )
+{
+        struct msn_userinfo *userinfo;
+        struct msn_data *md = gc->proto_data;
+        int user_buddyimage_changed = 0;
+        userinfo = msn_find_userinfo( md, new_userinfo->who );
+        if( userinfo )
+        {
+                if( userinfo->msnobject && new_userinfo->msnobject &&
+                    strcmp(userinfo->msnobject, new_userinfo->msnobject) != 0 )
+                {
+                        user_buddyimage_changed = 1;
+                }
+                msn_cleanup_userinfo( userinfo );
+                md->userinfolist = g_slist_remove( md->userinfolist, userinfo );
+        }
+        md->userinfolist = g_slist_append( md->userinfolist, new_userinfo );
+        if( user_buddyimage_changed )
+        {
+                struct msn_switchboard *sb = msn_sb_by_handle( gc, new_userinfo->who );
+                if( sb )
+                {
+                        p2p_request_msnobject(sb, sb->who, NULL, NULL );
+                }
+        }
+}
+
+/*
+ * create a userinfo struct from the provided parameters
+ */
+
+struct msn_userinfo *userinfo_from_params( char *who, char *msnobject )
+{
+        struct msn_userinfo *userinfo;
+        userinfo = g_new( struct msn_userinfo, 1 );
+
+        if( !userinfo )
+                return NULL;
+
+        userinfo->who = g_strdup( who );
+        userinfo->msnobject = g_strdup( msnobject );
+
+        return userinfo;
+}
+
+
+/*
+ * 2 stupid functions actually ...
+ */
+void p2p_init_random()
+{
+        srand( time( NULL ) );
+}
+
+DWORD p2p_randomnr()
+{
+        return rand();
+}
+
+/*
+ * generate a random UID
+ */
+char *p2p_rand_guid()
+{
+	return g_strdup_printf( "%4X%4X-%4X-%4X-%4X-%4X%4X%4X",
+		rand() % 0xAAFF + 0x1111, rand() % 0xAAFF + 0x1111,
+		rand() % 0xAAFF + 0x1111, rand() % 0xAAFF + 0x1111,
+		rand() % 0xAAFF + 0x1111, rand() % 0xAAFF + 0x1111,
+		rand() % 0xAAFF + 0x1111, rand() % 0xAAFF + 0x1111 );
+}
+
+/*
+ * create a P2PPacket and initialize it's members to the defauls...
+ */
+struct P2PPacket *p2p_packet_new()
+{
+        struct P2PPacket *packet = g_new0( struct P2PPacket, 1 );
+
+	if( !packet )
+		return NULL;
+        
+/*
+        packet->destination = NULL;
+        packet->filename = NULL;
+        packet->call_id = NULL;
+        packet->branch = NULL;
+*/
+        packet->fd = -1;
+
+	return packet;
+}
+
+/*
+ * convert a textbuffer containing a packet into a packet struct
+ * ... returns NULL on error
+ */
+struct P2PPacket *p2p_packet_from_buffer( char *buffer, int length )
+{
+	int pos;
+	struct P2PPacket *packet;
+
+	if( length <( sizeof( struct P2PHeader ) + sizeof( struct P2PFooter ) ) )
+		return NULL;
+
+	packet = p2p_packet_new();
+	if( !packet )
+		return NULL;
+
+	pos = 0;
+
+        memcpy( &( packet->header ), buffer, sizeof( struct P2PHeader ) );
+	pos += sizeof( struct P2PHeader );
+
+	if( length < ( sizeof( struct P2PHeader ) + packet->header.length + sizeof( struct P2PFooter ) ) )
+	{
+		g_free( packet );
+		return NULL;
+	}
+
+        if( packet->header.length > 0 )
+        {
+        	memcpy( packet->data, buffer+pos, packet->header.length );
+                pos += packet->header.length;
+        }
+
+        memcpy( &( packet->footer ), buffer+pos, sizeof( struct P2PFooter ) );
+
+	return packet;
+}
+
+/*
+ * find p2p packet by call_id
+ */
+struct P2PPacket *p2p_find_packet_by_callid( struct msn_switchboard *sb, char *call_id )
+{
+        GSList *tmp;
+        struct P2PPacket *packet;
+
+        if( !call_id )
+                return NULL;
+
+	tmp = sb->p2p_sessionlist;
+        
+
+        while( tmp != NULL )
+        {
+                packet = ( struct P2PPacket * ) tmp->data;
+                if( packet->call_id && 
+                    !strcmp( packet->call_id, call_id ) )
+                          return packet;
+                          
+                tmp = g_slist_next( tmp );
+        }
+        
+        return NULL;
+                
+}
+
+/*
+ * find a session by type/value in the current session list of this sb
+ */
+struct P2PPacket *p2p_find_packet( struct msn_switchboard *sb, DWORD value, int type )
+{
+        GSList *tmp = sb->p2p_sessionlist;
+        struct P2PPacket *packet;
+        
+        if( value == 0 )
+                return NULL;
+        
+        while( tmp != NULL )
+        {
+                packet = ( struct P2PPacket * ) tmp->data;
+                switch( type )
+                {
+                        case FIND_BY_SESSION_ID:
+                                if( packet->header.session_id == value )
+                                {
+                                        return packet;
+                                }
+                                break;
+
+                        case FIND_BY_ID:
+                                if( packet->header.id == value )
+                                {
+                                        return packet;
+                                }
+                                break;
+
+                        default:
+                                return NULL;
+                }
+                              
+                tmp = g_slist_next( tmp );
+        }
+        
+        return NULL;
+}
+
+/*
+ * extracts the given header from the packet slp data by doing
+ * it's utmost best to find it!
+ */
+char *p2p_findheader( struct P2PPacket *packet, char *header )
+{
+        char *p, *tmp;
+	int length;
+
+        p = msn_findheader( packet->data, header, packet->header.length );
+
+        if( p )
+                return p;
+
+        tmp = strstr( packet->data, "\r\n\r\n" );
+        while( tmp )
+        {
+                tmp += 4;
+
+                p = msn_findheader( tmp, header, packet->header.length - ( tmp - packet->data ) );
+
+                if( p )
+                        return p;
+                
+                tmp = strstr( tmp, "\r\n\r\n" );
+        }
+
+        tmp = strstr( packet->data, header );
+
+        if( tmp )
+        {
+		char *tmp2;
+		tmp2 = strstr( tmp, "\r" );
+		if( tmp2 )
+		{
+		        tmp += strlen( header );
+			length = ( tmp2-tmp );
+                        p = g_new0( char, length+1 );
+			if( !p )
+				return NULL;
+			strncpy( p, tmp, length );
+			p[length]=0;
+			return p;
+		}
+        }
+        
+        return NULL;
+}
+
+/*
+ * free all properties of a P2PPacket
+ */
+void p2p_cleanup_packet( struct P2PPacket *packet )
+{
+	if( packet->destination )
+	{
+		g_free( packet->destination );
+                packet->destination = NULL;
+        }
+		
+	if( packet->branch )
+	{
+		g_free( packet->branch );
+                packet->branch = NULL;
+	}
+	
+	if( packet->call_id )
+	{
+		g_free( packet->call_id );
+                packet->call_id = NULL;
+        }
+        
+        if( packet->filename )
+        {
+                g_free( packet->filename );
+                packet->filename = NULL;
+        }
+        
+        if( packet->fd != -1 )
+        {
+                close( packet->fd );
+                packet->fd = -1;
+        }
+}
+
+/*
+ * gets called from sb.c every time before the sb itself gets g_free()'s
+ */
+void p2p_cleanup_sb( struct msn_switchboard *sb )
+{
+        GSList *tmp;
+
+        tmp = sb->p2p_sessionlist;
+
+        if( tmp )
+        {
+                while( tmp != NULL )
+                {
+                        p2p_cleanup_packet(( struct P2PPacket * )tmp->data );
+                        tmp = g_slist_next( tmp );
+                }
+
+                g_slist_free( sb->p2p_sessionlist );
+                sb->p2p_sessionlist = NULL;
+        }
+}
+
+/*
+ * returns a fullpath for the requested image
+ */
+char *msn_imagefullpath( struct gaim_connection *gc, char *who, char *msnobject, int type, char *emoticon_shortcut, char *ext )
+{
+        char *path = NULL, *fullpath = NULL, *sha1c, *sha1d, md5[60], filename[150];
+       	struct stat statinfo;
+       	int buffersize;
+        md5_state_t state;
+        md5_byte_t digest[16];
+        user_t *user;
+        int i;
+
+        switch( type )
+        {
+                case TYPE_BUDDY_IMAGE:
+                        path = set_getstr( gc->irc, "msn_images_path_buddy" );
+                        break;
+                case TYPE_EMOTICON_IMAGE:
+                        path = set_getstr( gc->irc, "msn_images_path_emoticon" );
+                        break;
+        }
+
+        if( !path )
+                return NULL;
+
+      	if(( stat( path, &statinfo ) ) != 0 )
+      	        return NULL;
+
+        if( !S_ISDIR( statinfo.st_mode ) )
+                return NULL;
+
+        sha1c = msnobject_get_field( "SHA1C", msnobject );
+	if( !sha1c )
+	{
+		do_error_dialog( gc, "Could not allocate memory for 'sha1c' in msn_imagefullpath()", "MSN" );
+		return NULL;
+        }
+
+        sha1d = msnobject_get_field( "SHA1D", msnobject );
+	if( !sha1d )
+	{
+		do_error_dialog( gc, "Could not allocate memory for 'sha1d' in msn_imagefullpath()", "MSN" );
+		g_free( sha1c );
+		return NULL;
+	}
+    
+        md5_init( &state );
+        md5_append( &state,( const md5_byte_t * ) sha1c, strlen( sha1c ) );
+        md5_append( &state,( const md5_byte_t * ) sha1d, strlen( sha1d ) );
+        md5_finish( &state, digest );
+
+        g_free( sha1c );
+        g_free( sha1d );
+
+	bzero( md5, sizeof( md5 ) );
+
+        for( i = 0; i < 16; i ++ )
+	        g_snprintf( md5+strlen( md5 ), 3, "%02x", digest[i] );
+
+	g_snprintf( filename, sizeof( filename ), "%s.%s", md5, ext );
+
+        user = user_findhandle( gc, who );
+        if ( user )
+        {
+                buffersize = strlen( path ) + 1 + strlen( who ) + 1 + strlen( filename );
+
+                if( emoticon_shortcut )
+                        buffersize += strlen( emoticon_shortcut );
+              
+                fullpath = g_new0( char, buffersize );
+                       
+                if ( fullpath )
+                {
+                        switch( type )
+                        {
+                                case TYPE_BUDDY_IMAGE:
+                                        g_snprintf( fullpath, buffersize, "%s/%s.%s", path, user->nick, filename );
+                                        break;
+                                case TYPE_EMOTICON_IMAGE:
+                                        g_snprintf( fullpath, buffersize, "%s/%s.emoticon.%s", path, user->nick, filename );
+                                        break;
+                        }
+                }
+                else
+                {
+                	do_error_dialog( gc, "Could not allocate memory for 'fullpath' in msn_imagefullpath()", "MSN" );
+                }
+        }
+        else
+        {
+                do_error_dialog( gc, "Could not find userhandle in msn_imagefullpath()", "MSN" );
+        }
+
+        return fullpath;
+}
+
+
+/*
+ * send packet 'packet' to the sb
+ */
+void p2p_sendpacket( struct msn_switchboard *sb, struct P2PPacket *packet )
+{
+
+        struct gaim_connection *gc = sb->gc;
+        char cmd[1024], *buffer, *p;
+        char *header;
+        int len;
+
+	if( !packet->destination )
+	{
+		do_error_dialog( gc, "Could not send packet in p2p_sendpacket(), no destination givven!", "MSN" );
+		return;
+	}
+	
+	header = "MIME-Version: 1.0\r\nContent-Type: application/x-msnmsgrp2p\r\nP2P-Dest: ";
+
+	len = strlen( header ) +
+	      strlen( packet->destination ) +
+	      4 /* \r\n\r\n */ +
+	      sizeof( struct P2PHeader ) +
+	      sizeof( struct P2PFooter );
+	      
+	if( packet->header.length > 0 )
+	        len += packet->header.length; /* length of packet->data */
+        
+        buffer = g_new0(char, len + 1);
+
+        if (!buffer)
+        {
+		do_error_dialog( gc, "Could not allocate memory for 'buffer' in p2p_sendpacket()", "MSN" );
+                return;
+        }
+        
+        g_snprintf( buffer, len, "%s%s\r\n\r\n", header, packet->destination );
+        p = buffer+strlen( buffer );
+        
+        memcpy( p, &( packet->header ), sizeof( struct P2PHeader ) );
+        p += sizeof( struct P2PHeader );
+        
+        if( packet->header.length > 0 )
+        {
+                memcpy( p, packet->data, packet->header.length );
+                p += packet->header.length;
+        }
+        
+        memcpy( p, &( packet->footer ), sizeof( struct P2PFooter ) );
+        p += sizeof( struct P2PFooter );
+
+        g_snprintf( cmd, sizeof( cmd ), "MSG %d D %d\r\n", ++sb->trId, len );
+
+        if( !( msn_sb_write( sb, cmd, strlen( cmd ) ) && msn_sb_write( sb, buffer, len ) ) )
+        {
+                do_error_dialog( gc, "Error writing to switchboard in p2p_sendpacket()", "MSN" );
+        }
+        
+        g_free( buffer );
+
+}
+
+
+/*
+ * Sends an ACK packet to the sb 
+ */
+void p2p_sendack( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet )
+{
+        if( !packet )
+                return;
+
+        packet->header.id++;
+        packet->header.offset = 0;
+	packet->header.total_size = received_packet->header.total_size;
+        packet->header.length = 0;
+	packet->header.flags = 0x2;
+	packet->header.ack_sub_id = received_packet->header.ack_id;
+        packet->header.ack_id = received_packet->header.id;
+        packet->header.ack_size = received_packet->header.length;
+        packet->footer.value = 0;
+
+        p2p_sendpacket( sb, packet );
+}
+
+/*
+ * Sends the base identifier packet to the sb
+ */
+void p2p_sendbaseidentifier( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet )
+{
+        if( !packet )
+                return;
+
+        packet->header.session_id = 0;
+        packet->header.offset = 0;
+	packet->header.total_size = received_packet->header.total_size;
+	packet->header.flags = 0x2;
+	packet->header.ack_sub_id = received_packet->header.ack_id;
+	packet->header.ack_id = received_packet->header.id;
+        packet->header.id = p2p_randomnr();
+	packet->header.ack_size = received_packet->header.length;
+        packet->header.length = 0;
+
+        packet->footer.value = 0;
+
+        p2p_sendpacket( sb, packet );
+
+        packet->header.id -= 4;        
+}
+
+/*
+ * Send's the "200 OK" message to the sb
+ */
+void p2p_send200ok( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet )
+{
+        struct gaim_connection *gc = sb->gc;
+        char body[1024];
+
+        if( !packet )
+                return;
+
+        packet->header.session_id = 0;
+        packet->header.id++;
+        packet->header.offset = 0;
+        
+        g_snprintf( body, sizeof( body ), "SessionID: %d\r\n\r\n", packet->session_id );
+        
+        bzero( packet->data, sizeof( packet->data ) );
+        
+        packet->header.total_size = g_snprintf( packet->data, sizeof( packet->data ),
+                  "MSNSLP/1.0 200 OK\r\n"
+                  "To: <msnmsgr:%s>\r\n"
+                  "From: <msnmsgr:%s>\r\n"
+                  "Via: MSNSLP/1.0/TLP ;branch={%s}\r\n"
+                  "CSeq: %d\r\n"
+                  "Call-ID: {%s}\r\n"
+                  "Max-Forwards: 0\r\n"
+                  "Content-Type: application/x-msnmsgr-sessionreqbody\r\n"
+                  "Content-Length: %d\r\n\r\n"
+                  "%s",
+                  packet->destination, gc->username, packet->branch, ++packet->cseq, 
+                  packet->call_id, strlen( body )+1 /*adding up the \x00 in the content-length*/ , body );
+
+        packet->header.total_size++; /* we need the \x00 at the end  */
+	packet->header.length = packet->header.total_size;
+	packet->header.flags = 0;
+	packet->header.ack_id = received_packet->header.id;
+	packet->header.ack_sub_id = 0;
+	packet->header.ack_size = 0;
+	
+        packet->footer.value = 0;
+
+        p2p_sendpacket( sb, packet );
+}
+
+/*
+ * Sends the DATA PREPARATION packet to the sb
+ */
+void p2p_senddataprep( struct msn_switchboard *sb, struct P2PPacket *packet )
+{
+        if( !packet )
+                return;
+
+        packet->header.session_id = packet->session_id;
+        packet->header.id++;
+        packet->header.offset = 0;
+        packet->header.total_size = 4;
+        packet->header.length = 4;
+        packet->header.flags = 0;
+        packet->header.ack_id = p2p_randomnr();
+        packet->header.ack_sub_id = 0;
+        packet->header.ack_size = 0;
+
+        bzero( packet->data, sizeof( packet->data ) );
+
+        packet->footer.value = 0x01000000;
+        
+        p2p_sendpacket( sb, packet );
+}
+
+/*
+ * Sends data( picture data ) to the sb
+ * splitting it into multiple messages if required
+ */
+void p2p_senddata( struct msn_switchboard *sb, struct P2PPacket *packet )
+{
+        int fd, bytes;
+        struct stat fileinfo;
+        
+        if( !packet )
+                return;
+
+        if( !packet->filename )
+                return;
+                
+        if( ( fd=open( packet->filename, O_RDONLY ) ) == -1 )
+                return;
+                
+        if( fstat( fd, &fileinfo ) != 0 )
+        {
+                close( fd );
+                return;
+        }
+
+        packet->header.id++;
+        packet->header.total_size = fileinfo.st_size;
+        packet->header.flags = 0x20;
+        packet->header.ack_sub_id = 0;
+        packet->header.ack_size = 0;
+        packet->header.offset = 0;
+
+        packet->footer.value = 0x01000000;
+
+#define MAX_CHUNK_SIZE 1200
+        while(( bytes = read( fd, packet->data, MAX_CHUNK_SIZE ) ) > 0 ) {
+                packet->header.ack_id = p2p_randomnr();
+                packet->header.length = bytes;
+                p2p_sendpacket( sb, packet );
+                packet->header.offset += packet->header.length;
+        }
+        
+        close( fd );
+}
+
+/*
+ * sends an INVITE for context to the packet's destination...
+ */
+void p2p_sendinvite( struct msn_switchboard *sb, struct P2PPacket *packet, char *context )
+{
+        struct gaim_connection *gc = sb->gc;
+	char body[1024];
+
+	packet->session_id = p2p_randomnr();
+
+        if( packet->fd == -1 )
+        {
+                do_error_dialog( gc, "Couldn't send an INVITE because the current packet hasn't got an open file to write to! WTF?", "MSN" );
+                return;
+        }
+
+        if( packet->branch )
+        {
+                g_free( packet->branch );
+        }
+	packet->branch = p2p_rand_guid();
+
+	if( packet->call_id )
+	{
+	        g_free( packet->call_id );
+        }
+	packet->call_id = p2p_rand_guid();
+
+        packet->header.session_id = 0;
+        packet->header.id = p2p_randomnr();
+        packet->header.offset = 0;
+
+        g_snprintf( body, sizeof( body ), 
+		"\r\n"
+		"EUF-GUID: {A4268EEC-FEC5-49E5-95C3-F126696BDBF6}\r\n"
+		"SessionID: %d\r\n"
+		"AppID: 1\r\n"
+		"Context: %s\r\n",
+		packet->session_id, context );
+
+	bzero( packet->data, sizeof( packet->data ) );
+
+        packet->header.total_size = g_snprintf( packet->data, sizeof( packet->data ),
+		"INVITE MSNMSGR:%s MSNSLP/1.0\r\n"
+		"To: <msnmsgr:%s>\r\n"
+		"From: <msnmsgr:%s>\r\n"
+		"Via: MSNSLP/1.0/TLP ;branch={%s}\r\n"
+		"CSeq: 0\r\n"
+		"Call-ID: {%s}\r\n"
+		"Max-Forwards: 0\r\n"
+		"Content-Type: application/x-msnmsgr-sessionreqbody\r\n"
+		"Content-Length: %d\r\n"
+		"%s",
+		packet->destination, packet->destination, gc->username, packet->branch, packet->call_id, strlen( body )+1, body );
+
+	packet->header.total_size++;
+
+        packet->header.length = packet->header.total_size;
+        packet->header.flags = 0;
+        packet->header.ack_id = p2p_randomnr();
+        packet->header.ack_sub_id = 0;
+        packet->header.ack_size = 0;
+
+        packet->footer.value = 0;
+
+	sb->p2p_sessionlist = g_slist_append( sb->p2p_sessionlist, packet );
+
+	packet->next_step_on_ack = BASEIDENTIFIER;
+
+        p2p_sendpacket( sb, packet );
+}
+
+/*
+ * request an msnobject from a user, it'll convert the msnobject to a context for p2p_sendinvite()
+ * makes a fullpath using msn_imagefullpath() and opens that file for writing, add the filedescriptor
+ * to the packet and then sends the invite...
+ * if emo_msnobject is NULL we'll request the user's buddy-image, else emo_msnobject 
+ * is requested as an emoticon...
+ */
+void p2p_request_msnobject( struct msn_switchboard *sb, char *destination, char *emo_msnobject, char *emoticon_shortcut)
+{
+        struct gaim_connection *gc = sb->gc;
+        struct msn_data *md = gc->proto_data;
+        char *context = NULL, *msnobject = NULL;
+        struct P2PPacket *packet;
+        int type = -1;
+
+        if( emo_msnobject == NULL ) /* we need to request the user's msnobject for buddy-image */
+        {
+                struct msn_userinfo *userinfo = msn_find_userinfo( md, destination );
+                if( userinfo )
+                {
+                        msnobject = userinfo->msnobject;
+        		context = msnobject_to_context( userinfo->msnobject );
+        		type = TYPE_BUDDY_IMAGE;
+                }
+                else
+                {
+                        /* Requesting a buddy-image from a user that doesn't have one ???
+                         * return! we shouldn't be doing anything then!
+                         */
+                        return;
+                }
+        }
+        else /* We'll request an emoticon... */
+        {
+                msnobject = emo_msnobject;
+                context = msnobject_to_context( emo_msnobject );
+                type = TYPE_EMOTICON_IMAGE;
+	}
+	
+        if( context )
+        {
+                packet = p2p_packet_new();
+
+                if ( packet )
+                {
+                        char *filename = NULL;
+                        char *emoticon_info_filename = NULL;
+                        
+                        packet->destination = g_strdup( destination );
+                        switch( type )
+                        {
+                                case TYPE_BUDDY_IMAGE:
+                                        filename = msn_imagefullpath( gc, packet->destination, msnobject, type, emoticon_shortcut, "png" );
+                                        break;
+                                case TYPE_EMOTICON_IMAGE:
+                                        filename = msn_imagefullpath( gc, packet->destination, msnobject, type, emoticon_shortcut, "png" );
+                                        if( emoticon_shortcut )
+                                        {
+                                                emoticon_info_filename = msn_imagefullpath( gc, packet->destination, msnobject, type, emoticon_shortcut, "emo" );
+                                                if( emoticon_info_filename )
+                                                {
+                                                        FILE *fp;
+                                                        fp = fopen( emoticon_info_filename, "w" );
+                                                        if( fp )
+                                                        {
+                                                                fprintf( fp, "SHORTCUT=%s\n", emoticon_shortcut );
+                                                                fprintf( fp, "PNGFILE=%s\n", filename );
+                                                                fclose( fp );
+                                                        }
+                                                        else
+                                                        {
+                                                                do_error_dialog( gc, "Could not open this emoticon's .emo file for writing!!!", "MSN" );
+                                                                g_free( filename );
+                                                                filename = NULL;
+                                                        }
+                                                        g_free( emoticon_info_filename );
+                                                        emoticon_info_filename = NULL;
+                                                }
+                                                else
+                                                {
+                                                        g_free( filename );
+                                                        filename = NULL;
+                                                }
+                                        }
+                                        else
+                                        {
+                                                /* This should never be reached! */
+                                                do_error_dialog( gc, "Requesting TYPE_EMOTICON_IMAGE without a valid emoticon_shortcut", "MSN" );
+                                        }
+                                        break;
+                                default: 
+                                        /* In fact we should never reach this peace of code! */
+                                        do_error_dialog( gc, "Requesting an unknown msnobject type? Not even trying that! ...", "MSN" );
+                                        break;
+                        }
+                        
+                        
+                        if( filename )
+                        {
+                                if( emoticon_shortcut )
+                                {
+                                        char buffer[1024];
+                                        int len = g_snprintf( buffer, sizeof( buffer ), 
+                                                "<<bitlbee>> %s is an emoticon ( %s )",
+                                                emoticon_shortcut, filename );
+                                        serv_got_im( gc, destination, buffer, 0, 0, len );
+                                }
+
+                                if( access( filename, F_OK ) == 0 )
+                                {
+                                        switch( type )
+                                        {
+                                                case TYPE_BUDDY_IMAGE:
+                                                        serv_got_crap( gc, "Not downloading buddy image from %s because we already have it cached!",
+                                                                packet->destination );
+                                                        break;
+                                                case TYPE_EMOTICON_IMAGE:
+                                                        serv_got_crap( gc, "Not downloading emoticon image from %s because we already have it cached!",
+                                                                packet->destination );
+                                                        break;
+                                        }
+                                }
+                                else
+                                {
+                                        packet->fd = open( filename, O_WRONLY|O_TRUNC|O_CREAT, 00777 );
+                                        
+                                        if ( packet->fd != -1 )
+                                        {
+                                                switch( type )
+                                                {
+                                                        case TYPE_BUDDY_IMAGE:
+                                                                serv_got_crap( gc, "Saving %s's buddy image to: %s",
+                                                                        packet->destination, filename );
+                                                                break;
+                                                        case TYPE_EMOTICON_IMAGE:
+                                                                serv_got_crap( gc, "Saving emoticon '%s' from %s to: %s",
+                                                                        emoticon_shortcut, packet->destination, filename );
+                                                                break;
+                                                }
+                                                
+                                                if( packet->filename )
+                                                {
+                                                        g_free( packet->filename );
+                                                }                                                        
+                                                packet->filename = g_strdup( filename );
+                                                packet->type = type;
+                                     
+                                                /* p2p_sendinvite will add packet to the md->p2p_sessionlist so it'll
+                                                 * be g_free()'ed at the right time!
+                                                 */
+                                                p2p_sendinvite( sb, packet, context );
+                                        }
+                                        else
+                                        {
+                                                switch( type )
+                                                {
+                                                        case TYPE_BUDDY_IMAGE:
+                                                                do_error_dialog( gc, "Couldn't write to the buddy images directory. Please check your 'msn_images_path_buddy' setting! Not requesting the msnobject!", "MSN" );
+                                                                break;
+                                                        case TYPE_EMOTICON_IMAGE:
+                                                                do_error_dialog( gc, "Couldn't write to the emoticon images directory. Please check your 'msn_images_path_emoticon' setting! Not requesting the msnobject!", "MSN" );
+                                                                break;
+                                                }
+                                        }
+                                }
+
+                                g_free( filename );
+                        }
+                        else
+                        {
+                                switch( type )
+                                {
+                                        case TYPE_BUDDY_IMAGE:
+                                                do_error_dialog( gc, "Please check your 'msn_images_path_buddy' setting. It doesn't seem to be a valid directory!", "MSN" );
+                                                break;
+                                        case TYPE_EMOTICON_IMAGE:
+                                                do_error_dialog( gc, "Please check your 'msn_images_path_emoticon' setting. It doesn't seem to be a valid directory!", "MSN" );
+                                                break;
+                                }
+                        }
+                }
+                else
+                {
+                        do_error_dialog( gc, "Could not allocate memory for 'packet' in p2p_request_msnobject()", "MSN" );
+                }
+
+                g_free( context );
+        }
+        else
+        {
+                do_error_dialog( gc, "Couldn't create context for msnobject in p2p_request_msnobject()", "MSN" );
+        }
+
+}
+
+/*
+ * Send BYE packet to sb
+ */
+void p2p_sendbye( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet )
+{
+        struct gaim_connection *gc = sb->gc;
+
+        if( !packet )
+                return;
+
+	packet->header.session_id = 0;
+        packet->header.id++;
+        packet->header.offset = 0;
+
+        bzero( packet->data, sizeof( packet->data ) );
+        
+        packet->header.total_size = g_snprintf( packet->data, sizeof( packet->data ),
+                  "BYE MSNMSGR:%s MSNSLP/1.0\r\n"
+                  "To: <msnmsgr:%s>\r\n"
+                  "From: <msnmsgr:%s>\r\n"
+                  "Via: MSNSLP/1.0/TLP ;branch={%s}\r\n"
+                  "CSeq: 0\r\n"
+                  "Call-ID: {%s}\r\n"
+                  "Max-Forwards: 0\r\n"
+                  "Content-Type: application/x-msnmsgr-sessionclosebody\r\n"
+                  "Content-Length: 3\r\n\r\n",
+                  packet->destination, packet->destination, gc->username, packet->branch, packet->call_id );
+
+        packet->header.total_size++; /* we need a \x00 at the end! */
+	packet->header.length = packet->header.total_size;
+
+	packet->header.flags = 0;
+        packet->header.ack_id = received_packet->header.id;
+	packet->header.ack_sub_id = 0;
+	packet->header.ack_size = 0;
+	
+        packet->footer.value = 0;
+        
+        p2p_sendpacket( sb, packet );
+}
+
+/*
+ * Main handler. Will parse all P2P/SLP messages and handle it appropriate..
+ */
+void p2p_handler( struct msn_switchboard *sb, struct P2PPacket *packet )
+{
+        struct gaim_connection *gc = sb->gc;
+        struct P2PPacket *tmp_packet;
+	char *call_id;
+
+        /* if this is an ACK packet */
+        if( packet->header.flags == 0x2 )
+        {
+                debug( "P2P: ACK received..." );
+
+                /* Check if any of our sessions is waiting for an ACK */
+                tmp_packet = p2p_find_packet( sb, packet->header.ack_id, FIND_BY_ID );
+                if( tmp_packet )
+                {
+                        debug( "session found by FIND_BY_ID ..." );
+                        switch( tmp_packet->next_step_on_ack )
+                        {
+                          /* Sending image part */
+                                case DATA_PREP:
+                                        debug( "Ok! Now sending data preparation..." );
+
+                                        tmp_packet->next_step_on_ack = SEND_DATA;
+                                        p2p_senddataprep( sb, tmp_packet );
+                                        
+                                        break;
+
+                                case SEND_DATA:
+                                        debug( "Ok! Now sending the data...");
+                                        
+                                        tmp_packet->next_step_on_ack = DATA_SENT;
+                                        p2p_senddata( sb, tmp_packet );
+                                        switch( tmp_packet->type )
+                                        {
+                                                case TYPE_BUDDY_IMAGE:
+                                                        serv_got_crap( gc, "%s downloaded my buddy image!",
+                                                                tmp_packet->destination );
+                                                        break;
+                                                case TYPE_EMOTICON_IMAGE:
+                                                        serv_got_crap( gc, "%s downloaded my emoticon image %s!",
+                                                                tmp_packet->destination, tmp_packet->filename );
+                                                        break;
+                                        }
+                                       
+                                        break;
+                                        
+                                case DATA_SENT:
+                                        debug( "Ok! This is the data sent ack. Nothing to be done..." );
+                                        tmp_packet->next_step_on_ack = -1;
+                                        serv_got_crap( gc, "My buddy image successfully sent to %s",
+                                                                        tmp_packet->destination );
+                                        break;
+
+                          /* Receiving image part */
+				case BASEIDENTIFIER:
+                                        debug( "Ok! This is the base identifier. Nothing to be done..." );
+					break;
+					
+                                case BYEACK:
+                                        debug( "Ok! This is an ACK to my bye msg. Deleting session..." );
+                                        p2p_cleanup_packet( tmp_packet );
+                                        sb->p2p_sessionlist = g_slist_remove( sb->p2p_sessionlist, tmp_packet );
+
+                                        break;
+                                        
+                                default:
+                                        debug( "huh? I don't expect any ACK!!! ERROR ERROR??" );
+                                        break;
+                        }
+                }
+                else
+                {
+                        debug( "hmm, i couldn't find a session for this ack. Ignoring packet...");
+                        return; /* ignore ACK packet */
+                }
+        } else
+        
+        /* Check if this is an INVITE packet */
+        if( !strncmp( packet->data, "INVITE MSNMSGR", strlen( "INVITE MSNMSGR" ) ) )
+        {
+                char *session_id = p2p_findheader( packet, "SessionID:" );
+                char *dest = p2p_findheader( packet, "From: <msnmsgr:" );
+                char *branch = p2p_findheader( packet, "branch={" );
+                char *call_id = p2p_findheader( packet, "Call-ID: {" );
+                char *cseq = p2p_findheader( packet, "CSeq:" );
+                char *content_type = p2p_findheader( packet, "Content-Type:" );
+
+                if( session_id && dest && branch && call_id && cseq && content_type )
+                {
+                        dest[strlen( dest )-1]=0;
+                        branch[strlen( branch )-1]=0;
+                        call_id[strlen( call_id )-1]=0;
+                
+                        if( !strncmp( content_type, "application/x-msnmsgr-sessionreqbody", strlen( "application/x-msnmsgr-sessionreqbody" ) ) )
+                        {
+                                char *eufguid = p2p_findheader( packet, "EUF-GUID: {" );
+                                char *appid = p2p_findheader( packet, "AppID:" );
+                                char *context = p2p_findheader( packet, "Context:" );
+                                
+                                if( eufguid && appid && context )
+                                {
+                                        eufguid[strlen( eufguid )-1]=0;
+                        
+                                        /* Check eufguid, A4268EEC-FEC5-49E5-95C3-F126696BDBF6 = emoticon or buddy image */
+                                        if( !strncmp( eufguid, "A4268EEC-FEC5-49E5-95C3-F126696BDBF6", strlen( "A4268EEC-FEC5-49E5-95C3-F126696BDBF6" ) ) )
+                                        {
+                                                /* buddy image or emoticon */
+                                                packet->destination = g_strdup( dest );
+                                                packet->session_id = atoi( session_id );
+                                                packet->fd = -1;
+                                                packet->next_step_on_ack = -1;
+
+                                                sb->p2p_sessionlist = g_slist_append( sb->p2p_sessionlist, packet );
+
+                                                p2p_sendbaseidentifier( sb, packet, packet );
+                                
+                                                debug( "Sent base identifier...");
+                                        }
+                                        
+                                  
+                                        if( !strncmp( appid, "1", 1 ) )
+                                        {
+                                        //todo: check context, if it's a buddy or emoticon and if it's valid..
+                                        //      then use msn_images_mybuddyimage and probably create a new
+                                        //      option msn_images_myemoticonimages
+                                        //      blabla.. you get the point..
+                                                char *my_buddy_image = set_getstr( gc->irc, "msn_images_mybuddyimage" );
+                                                if( access( my_buddy_image, R_OK ) == 0 )
+                                                {
+                                                        packet->next_step_on_ack = DATA_PREP;
+                                                        packet->filename = g_strdup( my_buddy_image );
+	                 		        	packet->branch = g_strdup( branch );
+        		              			packet->call_id = g_strdup( call_id );
+	        	                		packet->cseq = atoi( cseq );
+	        	                		packet->type = TYPE_BUDDY_IMAGE; // we don't support sending emoticons so this is ok for now ...
+                                                        p2p_send200ok( sb, packet, packet );
+                                                        debug( "Sent 200 OK message" );
+                                                }
+                                                else
+                                                {
+                                                        debug( "Buddy Image not sent!!" );
+                                                        do_error_dialog( gc, "Buddy image not sent!", "MSN");
+                                                        // todo: send an error back instead of leaving the session unterminated!
+                                                }
+                                        } else
+                                        
+                                        if( !strncmp( appid, "2", 1 ) )
+                                        {
+                                        // todo: for filetransfers the INVITE message kan have a totalsize != length
+                                        //       because the preview data is at the context field
+                                        //       therefor we need to concatenate INVITE messages until offset+length = totalsize
+                                        //       before parsing the invite message
+                                        //       YOU NEED TO FIX THAT *BEFORE* starting to implement the filetransfer code
+                                                do_error_dialog( gc, "TODO: Complete filetransfer code!", "MSN" );
+                                        }
+                                }
+        
+                                if( appid )
+                                        g_free( appid );
+                                if( context )
+                                        g_free( context );
+                                if( eufguid )
+                                        g_free( eufguid );
+                        }
+                }
+                
+                if( session_id )
+                        g_free( session_id );
+                if( dest )
+                        g_free( dest );
+                if( branch )
+                        g_free( branch );
+                if( call_id )
+                        g_free( call_id );
+                if( cseq )
+                        g_free( cseq );
+                if( content_type )
+                        g_free( content_type );
+        } else 
+        
+	/* If this is a 200 OK response */
+        if( !strncmp( packet->data, "MSNSLP/1.0 200 OK", strlen( "MSNSLP/1.0 200 OK" ) ) )
+        {
+                char *call_id = p2p_findheader( packet, "Call-ID: {" );
+                if( call_id )
+                {
+                        call_id[strlen( call_id )-1]=0;
+                        
+                        tmp_packet = p2p_find_packet_by_callid( sb, call_id );
+                        if( tmp_packet )
+                        {
+                                debug( "200 OK message received. Sending an ACK" );
+                                p2p_sendack( sb, tmp_packet, packet );
+                                tmp_packet->header.session_id = tmp_packet->session_id;
+                        }
+                        else
+                        {
+                                debug( "200 OK message received but i don't have a session for it... Ignoring!" );
+                        }
+
+                        g_free( call_id );
+                }
+	} else 
+	
+        /* If this is a BYE response */
+        if( !strncmp( packet->data, "BYE MSNMSGR:", strlen( "BYE MSNMSGR:" ) ) )
+        {
+                debug( "BYE message received." );
+                call_id = p2p_findheader( packet, "Call-ID: {" );
+                if( call_id )
+                {
+                        call_id[strlen( call_id )-1]=0;
+                        
+                        tmp_packet = p2p_find_packet_by_callid( sb, call_id );
+                        if( tmp_packet )
+                        {
+                                debug( "Sending an ACK + BYE message + deleting the session!" );
+                                tmp_packet->header.session_id = 0;
+                                p2p_sendack( sb, tmp_packet, packet );
+
+                                p2p_cleanup_packet( tmp_packet );                                
+                                sb->p2p_sessionlist = g_slist_remove( sb->p2p_sessionlist, tmp_packet );
+                        }
+                        else
+                        {
+                                debug( "I don't expect a BYE message. Ignoring message" );
+                        }
+                        
+                        g_free( call_id );
+                }
+        } else
+        
+        /* MSN Messenger 6.2 sends a message back with flag being 0x40
+         * right after downloading our buddy image. I can't find any
+         * '3rd-party documentation' about that flag but everything seems
+         * to be working so i guess it's a normal thing?
+         * If you know more about that flag: I'm interested to know about it!
+         * (maybe there's an error in any of my packets and 0x40 means ERROR?)
+         */
+        if( packet->header.flags == 0x40 )
+        {
+                /* IGNORE */
+        } else
+        
+        /* Check for data preparation / data messages packets */
+        if( packet->header.session_id != 0 )
+        {
+                tmp_packet = p2p_find_packet( sb, packet->header.session_id, FIND_BY_SESSION_ID );
+                if( tmp_packet )
+                {
+                        if( packet->header.total_size == 4 && packet->header.length == 4 )
+                        {
+                                /* Data preparation received */
+                                if( tmp_packet->filename )
+                                {
+                                        debug( "Data perparation received. Sending ACK..." );
+                                        p2p_sendack( sb, tmp_packet, packet );
+                                }
+                                else
+                                {
+                                        debug( "Got a data preparation message but no filename to write to. THIS SHOULD'NT HAPPEN!" );
+                                }
+                        }
+                        else
+                        {
+                                /* Data message received */
+                                debug( "Data message ... Data is comming!!!" );
+                                
+                                if( tmp_packet->fd != -1 )
+                                {
+                                        if( write( tmp_packet->fd, packet->data, packet->header.length ) == -1 )
+                                        {
+                                                debug( "Error writing buddy/emoticon data! This shouldn't hapen :(" );
+                                        }
+                                        else
+                                        {
+                                                debug( "buddy/emoticon data written successfully!" );
+                                        }
+                                }
+                                else
+                                {
+                                        debug( "Got a data packet but i don't have a file to write to. This should not happen!" );
+                                }
+
+                                if( packet->header.offset + packet->header.length >= packet->header.total_size )
+                                {
+                                      /* end of file */
+                                      debug( "File receive completed!" );
+                                      serv_got_crap( gc, "File %s received successfully!",
+                                              tmp_packet->filename );
+                                              
+                                      if( tmp_packet->fd != -1 )
+                                      {
+                                              close( tmp_packet->fd );
+                                              tmp_packet->fd = -1;
+                                              
+                                      }
+                                      p2p_sendack( sb, tmp_packet, packet );
+                                      tmp_packet->next_step_on_ack = BYEACK;
+                                      p2p_sendbye( sb, tmp_packet, packet );
+                                }
+                        }
+                }
+                else
+                {
+                        /* SHOULD NOT HAPPEN */
+                        debug( "Well this shouldn't happen, Reference: 239OJPA2" );
+                }
+        } else
+
+        /* something else */
+        {
+                /* Unsupported? */
+                debug( "received a p2p packet but don't know how to handle it (yet?)" );
+        }
+}
diff -Nupr bitlbee-1.0.2/protocols/msn/msnc1.h bitlbee-1.0.2-akke/protocols/msn/msnc1.h
--- bitlbee-1.0.2/protocols/msn/msnc1.h	1970-01-01 01:00:00.000000000 +0100
+++ bitlbee-1.0.2-akke/protocols/msn/msnc1.h	2006-04-07 18:06:47.000000000 +0200
@@ -0,0 +1,81 @@
+#ifndef MSNC1
+#define MSNC1
+
+#define DWORD unsigned int
+#define QWORD unsigned long long
+
+struct P2PHeader
+{
+        DWORD session_id;
+        DWORD id;
+        QWORD offset;
+        QWORD total_size;
+        DWORD length;
+        DWORD flags;
+        DWORD ack_id;
+        DWORD ack_sub_id;
+        QWORD ack_size;
+};
+
+struct P2PFooter
+{
+        DWORD value;
+};
+
+struct P2PPacket
+{
+	/* msn p2p stuff */
+	struct P2PHeader header;
+	char data[1352]; /* max. 1202 characters ( or 1352 in case of a Direct Connection ( not even supported by now! ) ) */
+	struct P2PFooter footer;
+	
+	/* msn slp stuff */
+	char *destination, *branch, *call_id, *filename;
+	int cseq, session_id;
+	int type, next_step_on_ack;
+	int fd;
+};
+
+enum {
+        FIND_BY_SESSION_ID = 1,
+        FIND_BY_ID,
+};
+
+enum {
+        IGNORE = 1,
+        DATA_PREP,
+        SEND_DATA,
+        DATA_SENT,
+        BASEIDENTIFIER,
+        BYEACK,
+};
+
+void msn_update_mybuddyimage( struct gaim_connection *gc );
+struct msn_userinfo *msn_find_userinfo( struct msn_data *md, char *who );
+void msn_cleanup_userinfo( struct msn_userinfo *userinfo );
+void msn_cleanup_userinfolist( struct msn_data *md );
+void msn_add_or_update_userinfolist( struct gaim_connection *gc, struct msn_userinfo *new_userinfo );
+struct msn_userinfo *userinfo_from_params( char *who, char *msnobject );
+void p2p_init_random();
+DWORD p2p_randomnr();
+char *p2p_rand_guid();
+struct P2PPacket *p2p_packet_new();
+struct P2PPacket *p2p_packet_from_buffer( char *buffer, int length );
+struct P2PPacket *p2p_find_packet_by_callid( struct msn_switchboard *sb, char *call_id );
+struct P2PPacket *p2p_find_packet( struct msn_switchboard *sb, DWORD value, int type );
+char *p2p_findheader( struct P2PPacket *packet, char *header );
+void p2p_cleanup_packet( struct P2PPacket *packet );
+void p2p_cleanup_sb( struct msn_switchboard *sb );
+char *msn_imagefullpath( struct gaim_connection *gc, char *who, char *msnobject, int type, char *emoticon_shortcut, char *ext );
+void p2p_sendpacket( struct msn_switchboard *sb, struct P2PPacket *packet );
+void p2p_sendack( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet );
+void p2p_sendbaseidentifier( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet );
+void p2p_send200ok( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet );
+void p2p_senddataprep( struct msn_switchboard *sb, struct P2PPacket *packet );
+void p2p_senddata( struct msn_switchboard *sb, struct P2PPacket *packet );
+void p2p_sendinvite( struct msn_switchboard *sb, struct P2PPacket *packet, char *context );
+void p2p_request_msnobject( struct msn_switchboard *sb, char *destination, char *msnobject, char *emoticon_shortcut );
+void p2p_sendbye( struct msn_switchboard *sb, struct P2PPacket *packet, struct P2PPacket *received_packet );
+void p2p_handler( struct msn_switchboard *sb, struct P2PPacket *packet );
+
+#endif
diff -Nupr bitlbee-1.0.2/protocols/msn/msn.h bitlbee-1.0.2-akke/protocols/msn/msn.h
--- bitlbee-1.0.2/protocols/msn/msn.h	2006-04-01 20:53:39.000000000 +0200
+++ bitlbee-1.0.2-akke/protocols/msn/msn.h	2006-04-07 18:06:47.000000000 +0200
@@ -28,6 +28,8 @@
 #define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r"
 #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r"
 
+#define CLIENT_ID "268435500"
+
 #ifdef _WIN32
 #define debug 
 #else
@@ -44,7 +46,7 @@
 #define MSN_MESSAGE_HEADERS "MIME-Version: 1.0\r\n" \
                             "Content-Type: text/plain; charset=UTF-8\r\n" \
                             "User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \
-                            "X-MMS-IM-Format: FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n" \
+                            "X-MMS-IM-Format: FN=%s; EF=%s; CO=%s; CS=%d; PF=%d\r\n" \
                             "\r\n"
 
 #define MSN_TYPING_HEADERS "MIME-Version: 1.0\r\n" \
@@ -54,6 +56,12 @@
 
 #define PROFILE_URL "http://members.msn.com/"
 
+struct msn_userinfo
+{
+        char *who;
+        char *msnobject;
+};
+
 struct msn_data
 {
 	struct gaim_connection *gc;
@@ -67,6 +75,10 @@ struct msn_data
 	GSList *switchboards;
 	int buddycount;
 	const struct msn_away_state *away_state;
+
+	/* P2P stuff */
+	char *msnobject;
+	GSList *userinfolist;
 };
 
 struct msn_switchboard
@@ -86,6 +98,9 @@ struct msn_switchboard
 	GSList *msgq;
 	char *who;
 	struct conversation *chat;
+	
+	/* P2P stuff*/
+	GSList *p2p_sessionlist;
 };
 
 struct msn_away_state
diff -Nupr bitlbee-1.0.2/protocols/msn/msnobject.c bitlbee-1.0.2-akke/protocols/msn/msnobject.c
--- bitlbee-1.0.2/protocols/msn/msnobject.c	1970-01-01 01:00:00.000000000 +0100
+++ bitlbee-1.0.2-akke/protocols/msn/msnobject.c	2006-04-07 18:06:47.000000000 +0200
@@ -0,0 +1,157 @@
+#include <libgen.h>
+
+#include "msnobject.h"
+#include "msn.h"
+
+/*
+ * BASE64 encoding, functions comes from yahoo protocol module
+ * just some little mods..
+ */
+static char msn_base64digits[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                "abcdefghijklmnopqrstuvwxyz"
+                                "0123456789+/=";
+void msn_tobase64( unsigned char *out, const unsigned char *in, int inlen )
+{
+        for ( ; inlen >= 3; inlen -= 3 )
+                {
+                        *out++ = msn_base64digits[in[0] >> 2];
+                        *out++ = msn_base64digits[( ( in[0]<<4 ) & 0x30 ) | ( in[1]>>4 )];
+                        *out++ = msn_base64digits[( ( in[1]<<2 ) & 0x3c ) | ( in[2]>>6 )];
+                        *out++ = msn_base64digits[in[2] & 0x3f];
+                        in += 3;
+                }
+        if ( inlen > 0 )
+                {
+                        unsigned char fragment;
+
+                        *out++ = msn_base64digits[in[0] >> 2];
+                        fragment = ( in[0] << 4 ) & 0x30;
+                        if ( inlen > 1 )
+                                fragment |= in[1] >> 4;
+                        *out++ = msn_base64digits[fragment];
+                        *out++ = ( inlen < 2 ) ? '='
+                                        : msn_base64digits[( in[1] << 2 ) & 0x3c];
+                        *out++ = '=';
+                }
+        *out = '\0';
+}
+
+/*
+ * convert an http-encoded msnobject to an msn context
+ * ( = base64(<http-decoded msnobject>+<\x00>) )
+ */
+char *msnobject_to_context( char *msnobject )
+{
+	char *buf1, *buf2;
+	int length = strlen( msnobject );
+	
+	buf1 = g_new0( char, length + 2 );
+	if ( !buf1 )
+		return NULL;
+
+	strncpy( buf1, msnobject, length );
+	http_decode( buf1 );
+	
+	length = strlen( buf1 );
+
+	buf2 = g_new0( char, length * 3 );
+
+	if ( !buf2 )
+	{
+		g_free( buf1 );
+		return NULL;
+	}
+
+	msn_tobase64( buf2, buf1, length + 1 );
+
+	g_free( buf1 );
+	
+	return buf2;
+}
+
+/*
+ * create a new msnobject from the specified parameters
+ */
+char *msnobject_from_params( char *creator, int type, char *filename )
+{
+	SHA_CTX SHA_Context;
+	FILE *fd;
+	struct stat statinfo;
+	unsigned char digest[20];
+
+	char buffer[1024], sha1d[200], sha1c[200], *tmp, *location;
+	int len;
+
+	if ( !filename )
+		return NULL;
+	
+	if ( ( stat( filename, &statinfo ) ) != 0 )
+		return NULL;
+		
+	if ( !( fd=fopen( filename, "r" ) ) )
+		return NULL;
+	
+	tmp = g_strdup( filename );
+	if ( !tmp )
+		return NULL;
+	location = basename( tmp );
+	g_free( tmp );
+
+	/* calculate SHA1D */
+	shaInit( &SHA_Context );
+	while ( ( len = fread( buffer, 1, sizeof( buffer ), fd ) ) > 0 )
+	{
+		shaUpdate( &SHA_Context, buffer, len );
+	}
+	shaFinal( &SHA_Context, digest );
+	msn_tobase64( sha1d, digest, 20 );
+	fclose( fd );
+	http_encode( sha1d );
+
+	/* calculate SHA1C */
+	shaInit( &SHA_Context );
+	len = g_snprintf( buffer, sizeof( buffer ),
+		"Creator%sSize%dType%dLocation%sFriendlyAAA=SHA1D%s",
+		creator, ( int )statinfo.st_size, type, location, sha1d );
+	shaUpdate( &SHA_Context, buffer, len );
+	shaFinal( &SHA_Context, digest );
+	msn_tobase64( sha1c, digest, 20 );
+	http_encode( sha1c );
+
+	/* create msnobject */
+	g_snprintf( buffer, sizeof( buffer ),
+		"%%3Cmsnobj%%20Creator%%3D%%22%s%%22%%20Size%%3D%%22%d%%22%%20Type%%3D%%22%d%%22%%20Location%%3D%%22%s%%22%%20Friendly%%3D%%22AAA%%3D%%22%%20SHA1D%%3D%%22%s%%22%%20SHA1C%%3D%%22%s%%22/%%3E",
+		creator, ( int )statinfo.st_size, type, location, sha1d, sha1c );
+
+	return g_strdup( buffer );
+}
+
+/*
+ * returns a field from an msnobject..
+ */
+char *msnobject_get_field( char *field, char *msnobject )
+{
+        char *tag = NULL, *start = NULL, *end = NULL, tmp[200];
+
+        char *decoded_msnobject = g_new0( char, strlen( msnobject ) * 3 );
+
+        if ( !decoded_msnobject )
+                return NULL;
+
+        strcpy( decoded_msnobject, msnobject );
+        http_decode( decoded_msnobject );
+
+        g_snprintf( tmp, sizeof( tmp ), "%s=\"", field );
+
+        if ( ( start = strstr( decoded_msnobject, tmp ) ) != NULL )
+        {
+                start += strlen( tmp );
+                end = strchr( start, '"' );
+                if ( end )
+                        tag = g_strndup( start, end-start );
+        }
+
+        g_free( decoded_msnobject );
+
+        return tag;
+}
diff -Nupr bitlbee-1.0.2/protocols/msn/msnobject.h bitlbee-1.0.2-akke/protocols/msn/msnobject.h
--- bitlbee-1.0.2/protocols/msn/msnobject.h	1970-01-01 01:00:00.000000000 +0100
+++ bitlbee-1.0.2-akke/protocols/msn/msnobject.h	2006-04-07 18:06:47.000000000 +0200
@@ -0,0 +1,14 @@
+#ifndef MSN_OBJECT
+#define MSN_OBJECT
+
+#include "nogaim.h"
+
+#define TYPE_EMOTICON_IMAGE 2
+#define TYPE_BUDDY_IMAGE 3
+
+void msn_tobase64( unsigned char *out, const unsigned char *in, int inlen );
+char *msnobject_to_context( char *msnobject );
+char *msnobject_from_params( char *creator, int type, char *filename );
+char *msnobject_get_field(char *field, char *msnobject );
+
+#endif
diff -Nupr bitlbee-1.0.2/protocols/msn/msn_util.c bitlbee-1.0.2-akke/protocols/msn/msn_util.c
--- bitlbee-1.0.2/protocols/msn/msn_util.c	2006-04-01 20:53:39.000000000 +0200
+++ bitlbee-1.0.2-akke/protocols/msn/msn_util.c	2006-04-07 19:25:10.454760568 +0200
@@ -26,6 +26,8 @@
 #include "nogaim.h"
 #include "msn.h"
 #include <ctype.h>
+#include "msnobject.h"
+#include "msnc1.h"
 
 int msn_write( struct gaim_connection *gc, char *s, int len )
 {
@@ -49,8 +51,25 @@ int msn_logged_in( struct gaim_connectio
 	char buf[1024];
 	
 	account_online( gc );
+
+	/* account_online() sets an away state if there is any, so only
+           execute this code if we're not away. */
+        if( md->away_state == msn_away_state_list )
+        {
+                msn_update_mybuddyimage(gc);
+                if ( md->msnobject )
+                {
+                        g_snprintf( buf, sizeof( buf ), "CHG %d %s %s %s\r\n", ++md->trId, md->away_state->code, CLIENT_ID, md->msnobject );
+                }
+                else
+                {
+                g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 );
+                }
+                return( msn_write( gc, buf, strlen( buf ) ) );
+        }
 	
 	return( 0 );
+
 }
 
 int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname_ )
@@ -310,7 +329,13 @@ int msn_handler( struct msn_handler_data
 			if( h->msglen > h->rxlen )
 				break;
 			
-			msg = g_strndup( h->rxq, h->msglen );
+                       /* maybe some info is required, why did this buddy-image patch
+                        * replace g_strndup() with g_memdup()?
+                        * Well, easy:
+                        * g_strndup() doesn't like binary data, g_memdup() does! */
+			msg = g_memdup( h->rxq, h->msglen + 1 );
+			msg[h->msglen]=0;
+
 			cmd = msn_linesplit( h->cmd_text );
 			for( count = 0; cmd[count]; count ++ );
 			
diff -Nupr bitlbee-1.0.2/protocols/msn/ns.c bitlbee-1.0.2-akke/protocols/msn/ns.c
--- bitlbee-1.0.2/protocols/msn/ns.c	2006-04-01 20:53:39.000000000 +0200
+++ bitlbee-1.0.2-akke/protocols/msn/ns.c	2006-04-07 18:06:47.000000000 +0200
@@ -26,6 +26,7 @@
 #include <ctype.h>
 #include "nogaim.h"
 #include "msn.h"
+#include "msnc1.h"
 #include "passport.h"
 #include "md5.h"
 
@@ -71,7 +72,7 @@ void msn_ns_connected( gpointer data, gi
 	md->handler->fd = md->fd;
 	md->handler->rxq = g_new0( char, 1 );
 	
-	g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId );
+	g_snprintf( s, sizeof( s ), "VER %d MSNP9 CVR0\r\n", ++md->trId );
 	if( msn_write( gc, s, strlen( s ) ) )
 	{
 		gc->inpa = gaim_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc );
@@ -105,7 +106,7 @@ static int msn_ns_command( gpointer data
 	
 	if( strcmp( cmd[0], "VER" ) == 0 )
 	{
-		if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 )
+		if( cmd[2] && strncmp( cmd[2], "MSNP9", 5 ) != 0 )
 		{
 			hide_login_progress( gc, "Unsupported protocol" );
 			signoff( gc );
@@ -296,6 +297,9 @@ static int msn_ns_command( gpointer data
 		
 		if( list & 1 ) /* FL */
 		{
+			if( set_getint( gc->irc, "msn_buddylist_checks" ) == 1 && ( list & 8 ) == 0 )
+				serv_got_crap( gc, "\0034Contact %s is in your buddy list but you don't appear in his/her one (yet?)!", cmd[1] );
+
 			add_buddy( gc, NULL, cmd[1], cmd[2] );
 		}
 		if( list & 2 ) /* AL */
@@ -308,6 +312,9 @@ static int msn_ns_command( gpointer data
 		}
 		if( list & 8 ) /* RL */
 		{
+			if( set_getint( gc->irc, "msn_buddylist_checks" ) == 1 && ( list & 1 ) == 0 )
+				serv_got_crap( gc, "\0034Contact %s has got you in his/her buddy list but you don't have him/her in yours!", cmd[1] );
+
 			if( ( list & 6 ) == 0 )
 				msn_buddy_ask( gc, cmd[1], cmd[2] );
 		}
@@ -366,7 +373,7 @@ static int msn_ns_command( gpointer data
 	{
 		const struct msn_away_state *st;
 		
-		if( num_parts != 6 )
+		if( num_parts != 6 && num_parts != 7 )
 		{
 			hide_login_progress_error( gc, "Syntax error" );
 			signoff( gc );
@@ -376,6 +383,15 @@ static int msn_ns_command( gpointer data
 		http_decode( cmd[4] );
 		serv_buddy_rename( gc, cmd[3], cmd[4] );
 		
+		if( num_parts == 7 ) /* there's an msnobject at the end! */
+		{
+			struct msn_userinfo *userinfo = userinfo_from_params(cmd[3], cmd[6]);
+			if (userinfo)
+			{
+				msn_add_or_update_userinfolist( gc, userinfo );
+			}
+		}
+		
 		st = msn_away_state_by_code( cmd[2] );
 		if( !st )
 		{
@@ -394,7 +410,7 @@ static int msn_ns_command( gpointer data
 	{
 		const struct msn_away_state *st;
 		
-		if( num_parts != 5 )
+		if( num_parts != 5 && num_parts != 6 )
 		{
 			hide_login_progress_error( gc, "Syntax error" );
 			signoff( gc );
@@ -404,6 +420,15 @@ static int msn_ns_command( gpointer data
 		http_decode( cmd[3] );
 		serv_buddy_rename( gc, cmd[2], cmd[3] );
 		
+		if( num_parts == 6 )  /* there's an msnobject at the end! */
+		{
+			struct msn_userinfo *userinfo = userinfo_from_params(cmd[2], cmd[5]);
+			if (userinfo)
+			{
+				msn_add_or_update_userinfolist( gc, userinfo );
+			}
+		}
+
 		st = msn_away_state_by_code( cmd[1] );
 		if( !st )
 		{
@@ -450,6 +475,29 @@ static int msn_ns_command( gpointer data
 		
 		sb = msn_sb_create( gc, server, port, cmd[4], session );
 		sb->who = g_strdup( cmd[5] );
+
+		if( set_getint( gc->irc, "msn_notify_openwindow" ) == 1 )
+		{
+			char buffer[1024];
+			int len;
+			user_t *u;
+			u = user_findhandle( gc, sb->who );
+			if( u )
+			{
+				len = g_snprintf( buffer, sizeof( buffer ),
+					"<<bitlbee>> *** %s has opened a conversation window. ***",
+					u->nick);
+			}
+			else
+			{
+				len = g_snprintf( buffer, sizeof( buffer ),
+					"<<bitlbee>> *** %s has opened a conversation window. ***",
+					sb->who);
+			}
+
+			serv_got_im( gc, sb->who, buffer, 0, 0, len );
+		}
+
 	}
 	else if( strcmp( cmd[0], "ADD" ) == 0 )
 	{
@@ -469,17 +517,32 @@ static int msn_ns_command( gpointer data
 			/* We got added by someone. If we don't have this person in permit/deny yet, inform the user. */
 			for( l = gc->permit; l; l = l->next )
 				if( g_strcasecmp( l->data, cmd[4] ) == 0 )
+				{
+					if( set_getint( gc->irc, "msn_buddylist_checks" ) == 1 )
+						serv_got_crap( gc, "\0034Contact %s (which is in your allow-list) has just RE-added/allowed you to his/her buddy list!",
+							cmd[4] );
 					return( 1 );
-			
+				}			
 			for( l = gc->deny; l; l = l->next )
 				if( g_strcasecmp( l->data, cmd[4] ) == 0 )
+				{
+					if( set_getint( gc->irc, "msn_buddylist_checks" ) == 1 )
+						serv_got_crap( gc, "\0034Contact %s (which is in your block-list) has just RE-added you to his/her buddy list!",
+							cmd[4] );
 					return( 1 );
+				}
 			
 			msn_buddy_ask( gc, cmd[4], cmd[5] );
 		}
 	}
 	else if( strcmp( cmd[0], "REM" ) == 0 )
 	{
+		if( num_parts == 5 && strcmp( cmd[2], "RL" ) == 0 )
+		{
+			if( set_getint( gc->irc, "msn_buddylist_checks" ) == 1 )
+				serv_got_crap( gc, "\0034Contact %s has just removed you from his/her buddy list!",
+					cmd[4] );
+		}
 	}
 	else if( strcmp( cmd[0], "OUT" ) == 0 )
 	{
diff -Nupr bitlbee-1.0.2/protocols/msn/sb.c bitlbee-1.0.2-akke/protocols/msn/sb.c
--- bitlbee-1.0.2/protocols/msn/sb.c	2006-04-01 20:53:40.000000000 +0200
+++ bitlbee-1.0.2-akke/protocols/msn/sb.c	2006-04-07 18:06:47.000000000 +0200
@@ -28,6 +28,7 @@
 #include "msn.h"
 #include "passport.h"
 #include "md5.h"
+#include "msnc1.h"
 
 static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond );
 static int msn_sb_command( gpointer data, char **cmd, int num_parts );
@@ -55,6 +56,7 @@ struct msn_switchboard *msn_sb_create( s
 	sb->fd = proxy_connect( host, port, msn_sb_connected, sb );
 	if( sb->fd < 0 )
 	{
+		p2p_cleanup_sb ( sb );
 		g_free( sb );
 		return( NULL );
 	}
@@ -126,10 +128,61 @@ int msn_sb_sendmessage( struct msn_switc
 		
 		if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) != 0 )
 		{
-			buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 );
-			i = strlen( MSN_MESSAGE_HEADERS );
+			char *tmp, *font_face, *font_color, font_colorbuffer[5], font_style[10];
+			int font_charset, font_pitchandfamily, buffer_size;
+                                
+			/* Font face stuff */
+			tmp = set_getstr( sb->gc->irc, "msn_font_face" );
+			if( !tmp )
+				tmp = "MS Shell Dlg"; /* Default font face */
+
+			font_face = g_new0( char, strlen(tmp) * 3 ); /* We don't use g_strdup() because we need	  *
+							     * a buffer 3 times as big because of http_encode() */
+			strcpy( font_face, tmp );
+			http_encode( font_face );
+
+			/* Font color stuff */
+			tmp = set_getstr( sb->gc->irc, "msn_font_color" );
+			if( !tmp )
+				tmp = "000000"; /* Default font color (=black) */
+			font_color = g_strdup( tmp );
+			if( !font_color || strlen( font_color ) != 6 )
+			{
+				do_error_dialog( sb->gc, "Please check your 'msn_font_color' setting. Message not sent!!!", "MSN" );
+				g_free( font_face );
+				return( 0 );
+			}
+			/* font color fixup: msn server wants BGR instead of RGB style..*/
+			strncpy( font_colorbuffer, font_color, 2 );
+			font_color[0] = font_color[4];
+			font_color[1] = font_color[5];
+			font_color[4] = font_colorbuffer[0];
+			font_color[5] = font_colorbuffer[1];
+
+			/* Font style styff */
+			strcpy( font_style, "" );
+			if( set_getint( sb->gc->irc, "msn_font_bold" ) == 1 )
+				strcat( font_style, "B");
+			if( set_getint( sb->gc->irc, "msn_font_italic" ) == 1 )
+				strcat( font_style, "I");
+			if( set_getint( sb->gc->irc, "msn_font_overstrike" ) == 1 )
+				strcat( font_style, "S");
+			if( set_getint( sb->gc->irc, "msn_font_underline" ) == 1 )
+				strcat( font_style, "U");
+
+			/* Font charset */
+			font_charset = set_getint( sb->gc->irc, "msn_font_CS" );
+
+			/* Font Pitch & Family */
+			font_pitchandfamily = set_getint( sb->gc->irc, "msn_font_PF" );
+
+			buffer_size = strlen( MSN_MESSAGE_HEADERS ) + strlen( font_face ) + strlen( font_style ) + strlen( font_color ) + strlen( text ) * 2;
+			buf = g_new0( char, buffer_size + 1 );
+			i = g_snprintf( buf, buffer_size, MSN_MESSAGE_HEADERS, font_face, font_style, font_color, font_charset, font_pitchandfamily );
+
+			g_free( font_color );
+			g_free( font_face );
 			
-			strcpy( buf, MSN_MESSAGE_HEADERS );
 			for( j = 0; text[j]; j ++ )
 			{
 				if( text[j] == '\n' )
@@ -241,6 +294,7 @@ void msn_sb_destroy( struct msn_switchbo
 	
 	msn_switchboards = g_slist_remove( msn_switchboards, sb );
 	md->switchboards = g_slist_remove( md->switchboards, sb );
+	p2p_cleanup_sb ( sb );
 	g_free( sb );
 }
 
@@ -392,6 +446,11 @@ static int msn_sb_command( gpointer data
 		}
 		
 		sb->ready = 1;
+
+		if( sb->who )
+		{
+			p2p_request_msnobject(sb, sb->who, NULL, NULL );
+		}
 	}
 	else if( strcmp( cmd[0], "CAL" ) == 0 )
 	{
@@ -441,6 +500,9 @@ static int msn_sb_command( gpointer data
 				sb->msgq = g_slist_remove( sb->msgq, m );
 			}
 			
+			if( sb->who )
+				p2p_request_msnobject(sb, sb->who, NULL, NULL );
+
 			return( st );
 		}
 		else if( sb->who )
@@ -492,6 +554,34 @@ static int msn_sb_command( gpointer data
 		if( sb->who )
 		{
 			/* This is a single-person chat, and the other person is leaving. */
+			char buffer[1024];
+			int len;
+
+			if( cmd[2] && *cmd[2] && set_getint( gc->irc, "msn_notify_timeout" ) == 1 )
+			{
+				len = g_snprintf( buffer, sizeof( buffer ),
+					"<<bitlbee>> *** This conversation has timed out. ***" );
+				serv_got_im( gc, sb->who, buffer, 0, 0, len );
+			}
+			else if( !cmd[2] && set_getint( gc->irc, "msn_notify_closewindow" ) == 1 )
+			{
+				user_t *u;
+				u = user_findhandle( gc, sb->who );
+				if( u )
+				{
+					len = g_snprintf( buffer, sizeof( buffer ),
+						"<<bitlbee>> *** %s has closed the conversation window. ***",
+							u->nick);
+				}
+				else
+				{
+					len = g_snprintf( buffer, sizeof( buffer ),
+						"<<bitlbee>> *** %s has closed the conversation window. ***",
+							sb->who);
+				}
+				serv_got_im( gc, sb->who, buffer, 0, 0, len );
+			}
+
 			g_free( sb->who );
 			sb->who = NULL;
 			sb->ready = 0;
@@ -676,6 +766,78 @@ static int msn_sb_message( gpointer data
 			
 			g_free( ct );
 		}
+
+		else if( g_strncasecmp( ct, "application/x-msnmsgrp2p", 24 ) == 0)
+		{
+			char *p2p = msn_findheader( msg, "P2P-Dest:", msglen );
+
+			if ( p2p )
+			{
+				struct P2PPacket *packet;
+				packet = p2p_packet_from_buffer( body, blen );
+				if ( packet )
+				{
+					p2p_handler( sb, packet );
+					if( g_slist_find( sb->p2p_sessionlist, packet ) == NULL )
+					{
+                                               /* The packet isn't used as a session specifier
+                                                * so we should g_free() it here as we don't need it
+                                                * anymore now...
+                                                * If it's the session sepcifier it'll be g_free()'d
+                                                * at the right time (when it's sb is cleaned up)!
+                                                */
+						p2p_cleanup_packet( packet );
+						g_free( packet );
+					}
+				}
+				else
+				{
+					do_error_dialog( gc, "Corrupted application/x-msnmsgrp2p message received", "MSN" );
+				}
+				g_free( p2p );
+			}
+
+			g_free( ct );
+		}
+		else if( g_strncasecmp( ct, "text/x-mms-emoticon", 19 ) == 0)
+		{
+			char *p = strchr( body, '\t' );
+			if ( p )
+			{
+				char *shortcut, *msnobject;
+
+				shortcut = g_new0( char, ( ( p-body ) + 1 ) );
+				if ( !shortcut )
+				{
+					do_error_dialog( gc, "Could not allocate memory for 'shortcut' in msn_sb_msg()", "MSN" );
+					g_free( ct );
+					return( 1 );
+				}
+				strncpy( shortcut, body, ( p-body ) );
+
+				p++;
+
+				msnobject = g_new0( char, strlen( p ) );
+				if ( !msnobject )
+				{
+					do_error_dialog( gc, "Could not allocate memory for 'msnobject' in msn_sb_msg()", "MSN" );
+					g_free( shortcut );
+					g_free( ct );
+					return( 1 );
+				}
+				strncpy( msnobject, p, ( strlen( p ) - 1 ) );
+
+				p2p_request_msnobject( sb, sb->who, msnobject, shortcut );
+
+				g_free( shortcut );
+				g_free( msnobject );
+			}
+			else
+			{
+				do_error_dialog( gc, "Corrupted text/x-mms-emoticon message received", "MSN" );
+			}
+			g_free( ct );
+		}
 		else
 		{
 			g_free( ct );
