diff options
Diffstat (limited to 'chat-irc/bitlbee/msn.patch')
-rw-r--r-- | chat-irc/bitlbee/msn.patch | 2408 |
1 files changed, 2408 insertions, 0 deletions
diff --git a/chat-irc/bitlbee/msn.patch b/chat-irc/bitlbee/msn.patch new file mode 100644 index 0000000000..7f429b4f8a --- /dev/null +++ b/chat-irc/bitlbee/msn.patch @@ -0,0 +1,2408 @@ +diff -urN bitlbee-0.92/commands.c bitlbee-0.92.akke/commands.c +--- bitlbee-0.92/commands.c 2005-02-08 22:48:35.000000000 +0100 ++++ bitlbee-0.92.akke/commands.c 2005-05-07 02:29:45.000000000 +0200 +@@ -642,6 +642,33 @@ + 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; +@@ -665,21 +692,21 @@ + 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 -urN bitlbee-0.92/irc.c bitlbee-0.92.akke/irc.c +--- bitlbee-0.92/irc.c 2005-02-24 00:32:02.000000000 +0100 ++++ bitlbee-0.92.akke/irc.c 2005-05-07 03:15:20.000000000 +0200 +@@ -31,6 +31,43 @@ + + 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 ); +@@ -128,7 +165,27 @@ + set_add( irc, "save_on_quit", "1", set_eval_bool ); + 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 -urN bitlbee-0.92/protocols/msn/Makefile bitlbee-0.92.akke/protocols/msn/Makefile +--- bitlbee-0.92/protocols/msn/Makefile 2004-04-08 18:34:11.000000000 +0200 ++++ bitlbee-0.92.akke/protocols/msn/Makefile 2005-05-07 02:30:02.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 -urN bitlbee-0.92/protocols/msn/msn.c bitlbee-0.92.akke/protocols/msn/msn.c +--- bitlbee-0.92/protocols/msn/msn.c 2005-02-23 18:31:49.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/msn.c 2005-05-07 03:15:12.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 @@ + md->away_state = msn_away_state_list; + + msn_connections = g_slist_append( msn_connections, gc ); ++ ++ p2p_init_random(); ++ md->msnobject = NULL; + } + } + +@@ -77,6 +82,11 @@ + + while( md->switchboards ) + msn_sb_destroy( md->switchboards->data ); ++ ++ msn_cleanup_userinfolist( md ); ++ if( md->msnobject ) ++ g_free( md->msnobject ); ++ + + if( md->msgq ) + { +@@ -200,7 +210,15 @@ + 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 +259,35 @@ + 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 -urN bitlbee-0.92/protocols/msn/msn.h bitlbee-0.92.akke/protocols/msn/msn.h +--- bitlbee-0.92/protocols/msn/msn.h 2004-12-03 22:59:08.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/msn.h 2005-05-07 02:38:45.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" \ +@@ -55,6 +57,13 @@ + + #define PROFILE_URL "http://members.msn.com/" + ++struct msn_userinfo ++{ ++ char *who; ++ char *msnobject; ++}; ++ ++ + struct msn_data + { + struct gaim_connection *gc; +@@ -68,6 +77,10 @@ + GSList *switchboards; + int buddycount; + struct msn_away_state *away_state; ++ ++ /* P2P stuff */ ++ char *msnobject; ++ GSList *userinfolist; + }; + + struct msn_switchboard +@@ -87,6 +100,9 @@ + GSList *msgq; + char *who; + struct conversation *chat; ++ ++ /* P2P stuff*/ ++ GSList *p2p_sessionlist; + }; + + struct msn_away_state +diff -urN bitlbee-0.92/protocols/msn/msn_util.c bitlbee-0.92.akke/protocols/msn/msn_util.c +--- bitlbee-0.92/protocols/msn/msn_util.c 2004-05-03 22:02:52.000000000 +0200 ++++ bitlbee-0.92.akke/protocols/msn/msn_util.c 2005-05-07 03:15:25.000000000 +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 ) + { +@@ -54,7 +56,15 @@ + execute this code if we're not away. */ + if( md->away_state == msn_away_state_list ) + { +- g_snprintf( buf, sizeof( buf ), "CHG %d %s %d\r\n", ++md->trId, md->away_state->code, 0 ); ++ 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 ) ) ); + } + +@@ -318,7 +328,13 @@ + 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 -urN bitlbee-0.92/protocols/msn/msnc1.c bitlbee-0.92.akke/protocols/msn/msnc1.c +--- bitlbee-0.92/protocols/msn/msnc1.c 1970-01-01 01:00:00.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/msnc1.c 2005-05-07 03:10:01.000000000 +0200 +@@ -0,0 +1,1387 @@ ++/* ++ * 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; ++ userinfo = msn_find_userinfo( md, new_userinfo->who ); ++ int user_buddyimage_changed = 0; ++ 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 ) ++{ ++ if( !call_id ) ++ return NULL; ++ ++ GSList *tmp = sb->p2p_sessionlist; ++ ++ struct P2PPacket *packet; ++ ++ 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; ++ ++ 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 ); ++ int 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 ); ++} ++ ++void log_packet(struct P2PPacket *packet, char *dir) ++{ ++/* ++FILE *fp; ++fp=fopen("/tmp/log.akke","a"); ++fprintf(fp, "\r\n%s START-----------------------------------------------\r\n", dir); ++fprintf(fp, "header:\n"); ++fprintf(fp, " session_id: %d\n", packet->header.session_id); ++fprintf(fp, " id: %d\n", packet->header.id); ++fprintf(fp, " offset: %llu\n", packet->header.offset); ++fprintf(fp, " len: %llu\n", packet->header.total_size); ++fprintf(fp, " length: %d\n", packet->header.length); ++fprintf(fp, " flags: %d\n", packet->header.flags); ++fprintf(fp, " ack_id: %d\n", packet->header.ack_id); ++fprintf(fp, " ack_sub_id: %d\n", packet->header.ack_sub_id); ++fprintf(fp, " ack_size: %llu\n", packet->header.ack_size); ++if (packet->header.length > 0) ++{ ++ fprintf(fp, "data:\n"); ++ fprintf(fp, "%s\n", packet->data); ++} ++fprintf(fp, "footer:\n"); ++fprintf(fp, " value: %d\n", packet->footer.value); ++fprintf(fp, "\r\n%s STOP-----------------------------------------------\r\n", dir); ++fclose(fp); ++*/ ++} ++ ++ ++/* ++ * 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; ++ ++ log_packet(packet, "IN"); ++ /* 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." ); ++ char *call_id = p2p_findheader( packet, "Call-ID: {" ); ++ if( call_id ) ++ { ++ call_id[strlen( call_id )-1]=0; ++ ++ struct P2PPacket *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 -urN bitlbee-0.92/protocols/msn/msnc1.h bitlbee-0.92.akke/protocols/msn/msnc1.h +--- bitlbee-0.92/protocols/msn/msnc1.h 1970-01-01 01:00:00.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/msnc1.h 2005-05-07 02:41:33.000000000 +0200 +@@ -0,0 +1,82 @@ ++#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 -urN bitlbee-0.92/protocols/msn/msnobject.c bitlbee-0.92.akke/protocols/msn/msnobject.c +--- bitlbee-0.92/protocols/msn/msnobject.c 1970-01-01 01:00:00.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/msnobject.c 2005-05-07 02:30:12.000000000 +0200 +@@ -0,0 +1,156 @@ ++#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 -urN bitlbee-0.92/protocols/msn/msnobject.h bitlbee-0.92.akke/protocols/msn/msnobject.h +--- bitlbee-0.92/protocols/msn/msnobject.h 1970-01-01 01:00:00.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/msnobject.h 2005-05-07 02:41:29.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 -urN bitlbee-0.92/protocols/msn/ns.c bitlbee-0.92.akke/protocols/msn/ns.c +--- bitlbee-0.92/protocols/msn/ns.c 2005-02-23 18:28:41.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/ns.c 2005-05-07 02:52:38.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 @@ + 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 @@ + + 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 ); +@@ -297,6 +298,9 @@ + + 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 */ +@@ -309,6 +313,9 @@ + } + 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] ); + } +@@ -367,7 +374,7 @@ + { + 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 @@ + + 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 ) +@@ -395,7 +411,7 @@ + { + 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,7 +420,16 @@ + + 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 ) + { +@@ -451,6 +476,29 @@ + + 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 ) + { +@@ -470,17 +518,32 @@ + /* 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 -urN bitlbee-0.92/protocols/msn/sb.c bitlbee-0.92.akke/protocols/msn/sb.c +--- bitlbee-0.92/protocols/msn/sb.c 2005-02-23 16:50:24.000000000 +0100 ++++ bitlbee-0.92.akke/protocols/msn/sb.c 2005-05-07 03:15:57.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 @@ + 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 @@ + + 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' ) +@@ -137,6 +190,10 @@ + + buf[i++] = text[j]; + } ++FILE *fp; ++fp = fopen("/tmp/tmp.log","a"); ++fprintf(fp, "%s",buf); ++fclose(fp); + } + else + { +@@ -238,6 +295,7 @@ + + msn_switchboards = g_slist_remove( msn_switchboards, sb ); + md->switchboards = g_slist_remove( md->switchboards, sb ); ++ p2p_cleanup_sb ( sb ); + g_free( sb ); + } + +@@ -389,6 +447,11 @@ + } + + sb->ready = 1; ++ ++ if( sb->who ) ++ { ++ p2p_request_msnobject(sb, sb->who, NULL, NULL ); ++ } + } + else if( strcmp( cmd[0], "CAL" ) == 0 ) + { +@@ -437,7 +500,10 @@ + + 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 ) +@@ -489,6 +555,34 @@ + 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; +@@ -544,7 +638,7 @@ + + if( !num_parts ) + return( 1 ); +- ++ + if( ( body = strstr( msg, "\r\n\r\n" ) ) ) + { + body += 4; +@@ -649,6 +743,78 @@ + + 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 ); |