diff options
Diffstat (limited to 'protocols/msn')
-rw-r--r-- | protocols/msn/Makefile | 4 | ||||
-rw-r--r-- | protocols/msn/msn.c | 303 | ||||
-rw-r--r-- | protocols/msn/msn.h | 42 | ||||
-rw-r--r-- | protocols/msn/msn_util.c | 139 | ||||
-rw-r--r-- | protocols/msn/ns.c | 298 | ||||
-rw-r--r-- | protocols/msn/passport.c | 265 | ||||
-rw-r--r-- | protocols/msn/passport.h | 92 | ||||
-rw-r--r-- | protocols/msn/sb.c | 219 |
8 files changed, 743 insertions, 619 deletions
diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index 873c831c..6a588613 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -16,6 +16,10 @@ LFLAGS += -r # [SH] Phony targets all: msn_mod.o +check: all +lcov: check +gcov: + gcov *.c .PHONY: all clean distclean diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 3c7064f8..a2e8519a 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -26,91 +26,95 @@ #include "nogaim.h" #include "msn.h" -static void msn_login( struct aim_user *acct ) +static char *msn_set_display_name( set_t *set, char *value ); + +static void msn_init( account_t *acc ) { - struct gaim_connection *gc = new_gaim_conn( acct ); - struct msn_data *md = g_new0( struct msn_data, 1 ); + set_t *s; - set_login_progress( gc, 1, "Connecting" ); + s = set_add( &acc->set, "display_name", NULL, msn_set_display_name, acc ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; + + s = set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); +} + +static void msn_login( account_t *acc ) +{ + struct im_connection *ic = imcb_new( acc ); + struct msn_data *md = g_new0( struct msn_data, 1 ); - gc->proto_data = md; + ic->proto_data = md; md->fd = -1; - if( strchr( acct->username, '@' ) == NULL ) + if( strchr( acc->user, '@' ) == NULL ) { - hide_login_progress( gc, "Invalid account name" ); - signoff( gc ); + imcb_error( ic, "Invalid account name" ); + imc_logout( ic, FALSE ); return; } - md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, gc ); + imcb_log( ic, "Connecting" ); + + md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, ic ); if( md->fd < 0 ) { - hide_login_progress( gc, "Could not connect to server" ); - signoff( gc ); - } - else - { - md->gc = gc; - md->away_state = msn_away_state_list; - - msn_connections = g_slist_append( msn_connections, gc ); + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); + return; } + + md->ic = ic; + md->away_state = msn_away_state_list; + + msn_connections = g_slist_append( msn_connections, ic ); } -static void msn_close( struct gaim_connection *gc ) +static void msn_logout( struct im_connection *ic ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; GSList *l; - if( md->fd >= 0 ) - closesocket( md->fd ); - - if( md->handler ) - { - if( md->handler->rxq ) g_free( md->handler->rxq ); - if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); - g_free( md->handler ); - } - - while( md->switchboards ) - msn_sb_destroy( md->switchboards->data ); - - if( md->msgq ) + if( md ) { - struct msn_message *m; + if( md->fd >= 0 ) + closesocket( md->fd ); - for( l = md->msgq; l; l = l->next ) + if( md->handler ) { - m = l->data; - - serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who ); - g_free( m->who ); - g_free( m->text ); - g_free( m ); + if( md->handler->rxq ) g_free( md->handler->rxq ); + if( md->handler->cmd_text ) g_free( md->handler->cmd_text ); + g_free( md->handler ); } - g_slist_free( md->msgq ); + + while( md->switchboards ) + msn_sb_destroy( md->switchboards->data ); + + msn_msgq_purge( ic, &md->msgq ); + + while( md->groupcount > 0 ) + g_free( md->grouplist[--md->groupcount] ); + g_free( md->grouplist ); + + g_free( md ); } - for( l = gc->permit; l; l = l->next ) + for( l = ic->permit; l; l = l->next ) g_free( l->data ); - g_slist_free( gc->permit ); + g_slist_free( ic->permit ); - for( l = gc->deny; l; l = l->next ) + for( l = ic->deny; l; l = l->next ) g_free( l->data ); - g_slist_free( gc->deny ); - - g_free( md ); + g_slist_free( ic->deny ); - msn_connections = g_slist_remove( msn_connections, gc ); + msn_connections = g_slist_remove( msn_connections, ic ); } -static int msn_send_im( struct gaim_connection *gc, char *who, char *message, int len, int away ) +static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away ) { struct msn_switchboard *sb; - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; - if( ( sb = msn_sb_by_handle( gc, who ) ) ) + if( ( sb = msn_sb_by_handle( ic, who ) ) ) { return( msn_sb_sendmessage( sb, message ) ); } @@ -125,7 +129,7 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in m->text = g_strdup( message ); /* FIXME: *CHECK* the reliability of using spare sb's! */ - if( ( sb = msn_sb_spare( gc ) ) ) + if( ( sb = msn_sb_spare( ic ) ) ) { debug( "Trying to use a spare switchboard to message %s", who ); @@ -143,7 +147,7 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in /* If we reach this line, there was no spare switchboard, so let's make one. */ g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( gc, buf, strlen( buf ) ) ) + if( !msn_write( ic, buf, strlen( buf ) ) ) { g_free( m->who ); g_free( m->text ); @@ -163,31 +167,22 @@ static int msn_send_im( struct gaim_connection *gc, char *who, char *message, in return( 0 ); } -static GList *msn_away_states( struct gaim_connection *gc ) +static GList *msn_away_states( struct im_connection *ic ) { - GList *l = NULL; + static GList *l = NULL; int i; - for( i = 0; msn_away_state_list[i].number > -1; i ++ ) - l = g_list_append( l, (void*) msn_away_state_list[i].name ); - - return( l ); -} - -static char *msn_get_status_string( struct gaim_connection *gc, int number ) -{ - const struct msn_away_state *st = msn_away_state_by_number( number ); + if( l == NULL ) + for( i = 0; msn_away_state_list[i].number > -1; i ++ ) + l = g_list_append( l, (void*) msn_away_state_list[i].name ); - if( st ) - return( (char*) st->name ); - else - return( "" ); + return l; } -static void msn_set_away( struct gaim_connection *gc, char *state, char *message ) +static void msn_set_away( struct im_connection *ic, char *state, char *message ) { char buf[1024]; - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; const struct msn_away_state *st; if( strcmp( state, GAIM_AWAY_CUSTOM ) == 0 ) @@ -199,72 +194,43 @@ static void msn_set_away( struct gaim_connection *gc, char *state, char *message md->away_state = st; g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code ); - msn_write( gc, buf, strlen( buf ) ); + msn_write( ic, buf, strlen( buf ) ); } -static void msn_set_info( struct gaim_connection *gc, char *info ) +static void msn_set_my_name( struct im_connection *ic, char *info ) { - int i; - char buf[1024], *fn, *s; - struct msn_data *md = gc->proto_data; - - if( strlen( info ) > 129 ) - { - do_error_dialog( gc, "Maximum name length exceeded", "MSN" ); - return; - } - - /* Of course we could use http_encode() here, but when we encode - every character, the server is less likely to complain about the - chosen name. However, the MSN server doesn't seem to like escaped - non-ASCII chars, so we keep those unescaped. */ - s = fn = g_new0( char, strlen( info ) * 3 + 1 ); - for( i = 0; info[i]; i ++ ) - if( info[i] & 128 ) - { - *s = info[i]; - s ++; - } - else - { - g_snprintf( s, 4, "%%%02X", info[i] ); - s += 3; - } - - g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn ); - msn_write( gc, buf, strlen( buf ) ); - g_free( fn ); + msn_set_display_name( set_find( &ic->acc->set, "display_name" ), info ); } -static void msn_get_info(struct gaim_connection *gc, char *who) +static void msn_get_info(struct im_connection *ic, 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 ); + imcb_log( ic, "%s\n%s: %s%s", _("User Info"), _("For now, fetch yourself"), PROFILE_URL, who ); } -static void msn_add_buddy( struct gaim_connection *gc, char *who ) +static void msn_add_buddy( struct im_connection *ic, char *who, char *group ) { - msn_buddy_list_add( gc, "FL", who, who ); + msn_buddy_list_add( ic, "FL", who, who ); } -static void msn_remove_buddy( struct gaim_connection *gc, char *who, char *group ) +static void msn_remove_buddy( struct im_connection *ic, char *who, char *group ) { - msn_buddy_list_remove( gc, "FL", who ); + msn_buddy_list_remove( ic, "FL", who ); } -static int msn_chat_send( struct gaim_connection *gc, int id, char *message ) +static void msn_chat_msg( struct groupchat *c, char *message, int flags ) { - struct msn_switchboard *sb = msn_sb_by_id( gc, id ); + struct msn_switchboard *sb = msn_sb_by_chat( c ); if( sb ) - return( msn_sb_sendmessage( sb, message ) ); - else - return( 0 ); + msn_sb_sendmessage( sb, message ); + /* FIXME: Error handling (although this can't happen unless something's + already severely broken) disappeared here! */ } -static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char *who ) +static void msn_chat_invite( struct groupchat *c, char *who, char *message ) { - struct msn_switchboard *sb = msn_sb_by_id( gc, id ); + struct msn_switchboard *sb = msn_sb_by_chat( c ); char buf[1024]; if( sb ) @@ -274,39 +240,35 @@ static void msn_chat_invite( struct gaim_connection *gc, int id, char *msg, char } } -static void msn_chat_leave( struct gaim_connection *gc, int id ) +static void msn_chat_leave( struct groupchat *c ) { - struct msn_switchboard *sb = msn_sb_by_id( gc, id ); + struct msn_switchboard *sb = msn_sb_by_chat( c ); if( sb ) msn_sb_write( sb, "OUT\r\n", 5 ); } -static int msn_chat_open( struct gaim_connection *gc, char *who ) +static struct groupchat *msn_chat_with( struct im_connection *ic, char *who ) { struct msn_switchboard *sb; - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; char buf[1024]; - if( ( sb = msn_sb_by_handle( gc, who ) ) ) + if( ( sb = msn_sb_by_handle( ic, who ) ) ) { debug( "Converting existing switchboard to %s to a groupchat", who ); - msn_sb_to_chat( sb ); - return( 1 ); + return msn_sb_to_chat( sb ); } else { struct msn_message *m; - if( ( sb = msn_sb_spare( gc ) ) ) + if( ( sb = msn_sb_spare( ic ) ) ) { debug( "Trying to reuse an existing switchboard as a groupchat with %s", who ); g_snprintf( buf, sizeof( buf ), "CAL %d %s\r\n", ++sb->trId, who ); if( msn_sb_write( sb, buf, strlen( buf ) ) ) - { - msn_sb_to_chat( sb ); - return( 1 ); - } + return msn_sb_to_chat( sb ); } /* If the stuff above failed for some reason: */ @@ -314,7 +276,7 @@ static int msn_chat_open( struct gaim_connection *gc, char *who ) /* Request a new switchboard. */ g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); - if( !msn_write( gc, buf, strlen( buf ) ) ) + if( !msn_write( ic, buf, strlen( buf ) ) ) return( 0 ); /* Create a magic message. This is quite hackish, but who cares? :-P */ @@ -325,78 +287,111 @@ static int msn_chat_open( struct gaim_connection *gc, char *who ) /* Queue the magic message and cross your fingers. */ md->msgq = g_slist_append( md->msgq, m ); - return( 1 ); + /* FIXME: Can I try to return something here already? */ + return NULL; } - return( 0 ); + return NULL; } -static void msn_keepalive( struct gaim_connection *gc ) +static void msn_keepalive( struct im_connection *ic ) { - msn_write( gc, "PNG\r\n", strlen( "PNG\r\n" ) ); + msn_write( ic, "PNG\r\n", strlen( "PNG\r\n" ) ); } -static void msn_add_permit( struct gaim_connection *gc, char *who ) +static void msn_add_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_add( gc, "AL", who, who ); + msn_buddy_list_add( ic, "AL", who, who ); } -static void msn_rem_permit( struct gaim_connection *gc, char *who ) +static void msn_rem_permit( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( gc, "AL", who ); + msn_buddy_list_remove( ic, "AL", who ); } -static void msn_add_deny( struct gaim_connection *gc, char *who ) +static void msn_add_deny( struct im_connection *ic, char *who ) { struct msn_switchboard *sb; - msn_buddy_list_add( gc, "BL", who, who ); + msn_buddy_list_add( ic, "BL", who, who ); /* If there's still a conversation with this person, close it. */ - if( ( sb = msn_sb_by_handle( gc, who ) ) ) + if( ( sb = msn_sb_by_handle( ic, who ) ) ) { msn_sb_destroy( sb ); } } -static void msn_rem_deny( struct gaim_connection *gc, char *who ) +static void msn_rem_deny( struct im_connection *ic, char *who ) { - msn_buddy_list_remove( gc, "BL", who ); + msn_buddy_list_remove( ic, "BL", who ); } -static int msn_send_typing( struct gaim_connection *gc, char *who, int typing ) +static int msn_send_typing( struct im_connection *ic, char *who, int typing ) { - if( typing ) - return( msn_send_im( gc, who, TYPING_NOTIFICATION_MESSAGE, strlen( TYPING_NOTIFICATION_MESSAGE ), 0 ) ); + if( typing & OPT_TYPING ) + return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ) ); else return( 1 ); } -void msn_init() +static char *msn_set_display_name( set_t *set, char *value ) +{ + account_t *acc = set->data; + struct im_connection *ic = acc->ic; + struct msn_data *md; + char buf[1024], *fn; + + /* Double-check. */ + if( ic == NULL ) + return NULL; + + md = ic->proto_data; + + if( strlen( value ) > 129 ) + { + imcb_log( ic, "Maximum name length exceeded" ); + return NULL; + } + + fn = msn_http_encode( value ); + + g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, ic->acc->user, fn ); + msn_write( ic, buf, strlen( buf ) ); + g_free( fn ); + + /* Returning NULL would be better, because the server still has to + confirm the name change. However, it looks a bit confusing to the + user. */ + return value; +} + +void msn_initmodule() { struct prpl *ret = g_new0(struct prpl, 1); + ret->name = "msn"; ret->login = msn_login; - ret->close = msn_close; - ret->send_im = msn_send_im; + ret->init = msn_init; + ret->logout = msn_logout; + ret->buddy_msg = msn_buddy_msg; ret->away_states = msn_away_states; - ret->get_status_string = msn_get_status_string; ret->set_away = msn_set_away; - ret->set_info = msn_set_info; ret->get_info = msn_get_info; + ret->set_my_name = msn_set_my_name; ret->add_buddy = msn_add_buddy; ret->remove_buddy = msn_remove_buddy; - ret->chat_send = msn_chat_send; + ret->chat_msg = msn_chat_msg; ret->chat_invite = msn_chat_invite; ret->chat_leave = msn_chat_leave; - ret->chat_open = msn_chat_open; + ret->chat_with = msn_chat_with; ret->keepalive = msn_keepalive; ret->add_permit = msn_add_permit; ret->rem_permit = msn_rem_permit; ret->add_deny = msn_add_deny; ret->rem_deny = msn_rem_deny; ret->send_typing = msn_send_typing; - ret->cmp_buddynames = g_strcasecmp; + ret->handle_cmp = g_strcasecmp; register_protocol(ret); } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 0cd174f2..c8f4f4c6 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -28,11 +28,9 @@ #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" -#ifdef _WIN32 -#define debug +#ifdef DEBUG +#define debug( text... ) imcb_log( ic, text ); #else -#define debug( text... ) irc_usermsg( IRC, text ); -#undef debug #define debug( text... ) #endif @@ -56,7 +54,7 @@ struct msn_data { - struct gaim_connection *gc; + struct im_connection *ic; int fd; struct msn_handler_data *handler; @@ -65,8 +63,10 @@ struct msn_data GSList *msgq; GSList *switchboards; - const struct msn_away_state *away_state; + int sb_failures; + time_t first_sb_failure; + const struct msn_away_state *away_state; int buddycount; int groupcount; char **grouplist; @@ -74,7 +74,7 @@ struct msn_data struct msn_switchboard { - struct gaim_connection *gc; + struct im_connection *ic; int fd; gint inp; @@ -88,7 +88,7 @@ struct msn_switchboard GSList *msgq; char *who; - struct conversation *chat; + struct groupchat *chat; }; struct msn_away_state @@ -145,17 +145,19 @@ GSList *msn_connections; GSList *msn_switchboards; /* ns.c */ -void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ); +gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); /* msn_util.c */ -int msn_write( struct gaim_connection *gc, char *s, int len ); -int msn_logged_in( struct gaim_connection *gc ); -int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname ); -int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ); -void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ); +int msn_write( struct im_connection *ic, char *s, int len ); +int msn_logged_in( struct im_connection *ic ); +int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname ); +int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who ); +void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ); char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); +char *msn_http_encode( const char *input ); +void msn_msgq_purge( struct im_connection *ic, GSList **list ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); @@ -165,11 +167,11 @@ const struct msn_status_code *msn_status_by_number( int number ); /* sb.c */ int msn_sb_write( struct msn_switchboard *sb, char *s, int len ); -struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session ); -struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle ); -struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id ); -struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ); +struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ); +struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ); +struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ); +struct msn_switchboard *msn_sb_spare( struct im_connection *ic ); int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ); -void msn_sb_to_chat( struct msn_switchboard *sb ); +struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ); void msn_sb_destroy( struct msn_switchboard *sb ); -void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ); +gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index c3bd73cc..fae2877d 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -27,57 +27,41 @@ #include "msn.h" #include <ctype.h> -int msn_write( struct gaim_connection *gc, char *s, int len ) +int msn_write( struct im_connection *ic, char *s, int len ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; int st; st = write( md->fd, s, len ); if( st != len ) { - hide_login_progress_error( gc, "Short write() to main server" ); - signoff( gc ); + imcb_error( ic, "Short write() to main server" ); + imc_logout( ic, TRUE ); return( 0 ); } return( 1 ); } -int msn_logged_in( struct gaim_connection *gc ) +int msn_logged_in( struct im_connection *ic ) { - account_online( gc ); + imcb_connected( ic ); return( 0 ); } -int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname_ ) +int msn_buddy_list_add( struct im_connection *ic, char *list, char *who, char *realname_ ) { - struct msn_data *md = gc->proto_data; - GSList *l, **lp = NULL; + struct msn_data *md = ic->proto_data; char buf[1024], *realname; - if( strcmp( list, "AL" ) == 0 ) - lp = &gc->permit; - else if( strcmp( list, "BL" ) == 0 ) - lp = &gc->deny; - - if( lp ) - for( l = *lp; l; l = l->next ) - if( g_strcasecmp( l->data, who ) == 0 ) - return( 1 ); - - realname = g_new0( char, strlen( realname_ ) * 3 + 1 ); - strcpy( realname, realname_ ); - http_encode( realname ); + realname = msn_http_encode( realname_ ); g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname ); - if( msn_write( gc, buf, strlen( buf ) ) ) + if( msn_write( ic, buf, strlen( buf ) ) ) { g_free( realname ); - if( lp ) - *lp = g_slist_append( *lp, g_strdup( who ) ); - return( 1 ); } @@ -86,52 +70,31 @@ int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char return( 0 ); } -int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ) +int msn_buddy_list_remove( struct im_connection *ic, char *list, char *who ) { - struct msn_data *md = gc->proto_data; - GSList *l = NULL, **lp = NULL; + struct msn_data *md = ic->proto_data; char buf[1024]; - if( strcmp( list, "AL" ) == 0 ) - lp = &gc->permit; - else if( strcmp( list, "BL" ) == 0 ) - lp = &gc->deny; - - if( lp ) - { - for( l = *lp; l; l = l->next ) - if( g_strcasecmp( l->data, who ) == 0 ) - break; - - if( !l ) - return( 1 ); - } - g_snprintf( buf, sizeof( buf ), "REM %d %s %s\r\n", ++md->trId, list, who ); - if( msn_write( gc, buf, strlen( buf ) ) ) - { - if( lp ) - *lp = g_slist_remove( *lp, l->data ); - + if( msn_write( ic, buf, strlen( buf ) ) ) return( 1 ); - } return( 0 ); } struct msn_buddy_ask_data { - struct gaim_connection *gc; + struct im_connection *ic; char *handle; char *realname; }; static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) { - msn_buddy_list_add( bla->gc, "AL", bla->handle, bla->realname ); + msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname ); - if( find_buddy( bla->gc, bla->handle ) == NULL ) - show_got_added( bla->gc, bla->handle, NULL ); + if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) + imcb_ask_add( bla->ic, bla->handle, NULL ); g_free( bla->handle ); g_free( bla->realname ); @@ -140,26 +103,26 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla ) { - msn_buddy_list_add( bla->gc, "BL", bla->handle, bla->realname ); + msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname ); g_free( bla->handle ); g_free( bla->realname ); g_free( bla ); } -void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ) +void msn_buddy_ask( struct im_connection *ic, char *handle, char *realname ) { struct msn_buddy_ask_data *bla = g_new0( struct msn_buddy_ask_data, 1 ); char buf[1024]; - bla->gc = gc; + bla->ic = ic; bla->handle = g_strdup( handle ); bla->realname = g_strdup( realname ); g_snprintf( buf, sizeof( buf ), "The user %s (%s) wants to add you to his/her buddy list.", handle, realname ); - do_ask_dialog( gc, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); + imcb_ask( ic, buf, bla, msn_buddy_ask_yes, msn_buddy_ask_no ); } char *msn_findheader( char *text, char *header, int len ) @@ -349,3 +312,63 @@ int msn_handler( struct msn_handler_data *h ) return( 1 ); } + +/* The difference between this function and the normal http_encode() function + is that this one escapes every 7-bit ASCII character because this is said + to avoid some lame server-side checks when setting a real-name. Also, + non-ASCII characters are not escaped because MSN servers don't seem to + appreciate that! */ +char *msn_http_encode( const char *input ) +{ + char *ret, *s; + int i; + + ret = s = g_new0( char, strlen( input ) * 3 + 1 ); + for( i = 0; input[i]; i ++ ) + if( input[i] & 128 ) + { + *s = input[i]; + s ++; + } + else + { + g_snprintf( s, 4, "%%%02X", input[i] ); + s += 3; + } + + return ret; +} + +void msn_msgq_purge( struct im_connection *ic, GSList **list ) +{ + struct msn_message *m; + GString *ret; + GSList *l; + + l = *list; + if( l == NULL ) + return; + + m = l->data; + ret = g_string_sized_new( 1024 ); + g_string_printf( ret, "Warning: Cleaning up MSN (switchboard) connection with unsent " + "messages to %s:", m->who ? m->who : "unknown recipient" ); + + while( l ) + { + m = l->data; + + g_string_append_printf( ret, "\n%s", m->text ); + + g_free( m->who ); + g_free( m->text ); + g_free( m ); + + l = l->next; + } + g_slist_free( *list ); + *list = NULL; + + imcb_log( ic, ret->str ); + g_string_free( ret, TRUE ); +} diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 90d525ef..ff7da6ed 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -29,34 +29,34 @@ #include "passport.h" #include "md5.h" -static void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ); +static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ); static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_id( struct passport_reply *rep ); +static void msn_auth_got_passport_token( struct msn_auth_data *mad ); -void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ) +gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; struct msn_data *md; char s[1024]; - if( !g_slist_find( msn_connections, gc ) ) - return; + if( !g_slist_find( msn_connections, ic ) ) + return FALSE; if( source == -1 ) { - hide_login_progress( gc, "Could not connect to server" ); - signoff( gc ); - return; + imcb_error( ic, "Could not connect to server" ); + imc_logout( ic, TRUE ); + return FALSE; } - md = gc->proto_data; + md = ic->proto_data; if( !md->handler ) { md->handler = g_new0( struct msn_handler_data, 1 ); - md->handler->data = gc; + md->handler->data = ic; md->handler->exec_command = msn_ns_command; md->handler->exec_message = msn_ns_message; } @@ -72,29 +72,35 @@ void msn_ns_connected( gpointer data, gint source, GaimInputCondition cond ) md->handler->rxq = g_new0( char, 1 ); g_snprintf( s, sizeof( s ), "VER %d MSNP8 CVR0\r\n", ++md->trId ); - if( msn_write( gc, s, strlen( s ) ) ) + if( msn_write( ic, s, strlen( s ) ) ) { - gc->inpa = gaim_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, gc ); - set_login_progress( gc, 1, "Connected to server, waiting for reply" ); + ic->inpa = b_input_add( md->fd, GAIM_INPUT_READ, msn_ns_callback, ic ); + imcb_log( ic, "Connected to server, waiting for reply" ); } + + return FALSE; } -void msn_ns_callback( gpointer data, gint source, GaimInputCondition cond ) +static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition cond ) { - struct gaim_connection *gc = data; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = data; + struct msn_data *md = ic->proto_data; if( msn_handler( md->handler ) == -1 ) /* Don't do this on ret == 0, it's already done then. */ { - hide_login_progress( gc, "Error while reading from server" ); - signoff( gc ); + imcb_error( ic, "Error while reading from server" ); + imc_logout( ic, TRUE ); + + return FALSE; } + else + return TRUE; } static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { - struct gaim_connection *gc = data; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = data; + struct msn_data *md = ic->proto_data; char buf[1024]; if( num_parts == 0 ) @@ -107,20 +113,20 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { if( cmd[2] && strncmp( cmd[2], "MSNP8", 5 ) != 0 ) { - hide_login_progress( gc, "Unsupported protocol" ); - signoff( gc ); + imcb_error( ic, "Unsupported protocol" ); + imc_logout( ic, FALSE ); return( 0 ); } g_snprintf( buf, sizeof( buf ), "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", - ++md->trId, gc->username ); - return( msn_write( gc, buf, strlen( buf ) ) ); + ++md->trId, ic->acc->user ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "CVR" ) == 0 ) { /* We don't give a damn about the information we just received */ - g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, gc->username ); - return( msn_write( gc, buf, strlen( buf ) ) ); + g_snprintf( buf, sizeof( buf ), "USR %d TWN I %s\r\n", ++md->trId, ic->acc->user ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "XFR" ) == 0 ) { @@ -129,24 +135,24 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 6 && strcmp( cmd[2], "NS" ) == 0 ) { - gaim_input_remove( gc->inpa ); - gc->inpa = 0; + b_event_remove( ic->inpa ); + ic->inpa = 0; closesocket( md->fd ); server = strchr( cmd[3], ':' ); if( !server ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } *server = 0; port = atoi( server + 1 ); server = cmd[3]; - set_login_progress( gc, 1, "Transferring to other server" ); + imcb_log( ic, "Transferring to other server" ); - md->fd = proxy_connect( server, port, msn_ns_connected, gc ); + md->fd = proxy_connect( server, port, msn_ns_connected, ic ); } else if( num_parts == 6 && strcmp( cmd[2], "SB" ) == 0 ) { @@ -155,8 +161,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) server = strchr( cmd[3], ':' ); if( !server ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } *server = 0; @@ -165,13 +171,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[4], "CKI" ) != 0 ) { - hide_login_progress_error( gc, "Unknown authentication method for switchboard" ); - signoff( gc ); + imcb_error( ic, "Unknown authentication method for switchboard" ); + imc_logout( ic, TRUE ); return( 0 ); } debug( "Connecting to a new switchboard with key %s", cmd[5] ); - sb = msn_sb_create( gc, server, port, cmd[5], MSN_SB_NEW ); + sb = msn_sb_create( ic, server, port, cmd[5], MSN_SB_NEW ); if( md->msgq ) { @@ -197,8 +203,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -207,29 +213,37 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { /* Time for some Passport black magic... */ - if( !passport_get_id( msn_auth_got_passport_id, gc, gc->username, gc->password, cmd[4] ) ) + if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) { - hide_login_progress_error( gc, "Error while contacting Passport server" ); - signoff( gc ); + imcb_error( ic, "Error while contacting Passport server" ); + imc_logout( ic, TRUE ); return( 0 ); } } else if( num_parts == 7 && strcmp( cmd[2], "OK" ) == 0 ) { + set_t *s; + http_decode( cmd[4] ); - strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); - gc->displayname[sizeof(gc->displayname)-1] = 0; + strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); + ic->displayname[sizeof(ic->displayname)-1] = 0; - set_login_progress( gc, 1, "Authenticated, getting buddy list" ); + if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) + { + g_free( s->value ); + s->value = g_strdup( cmd[4] ); + } + + imcb_log( ic, "Authenticated, getting buddy list" ); g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); - return( msn_write( gc, buf, strlen( buf ) ) ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else { - hide_login_progress( gc, "Unknown authentication type" ); - signoff( gc ); + imcb_error( ic, "Unknown authentication type" ); + imc_logout( ic, FALSE ); return( 0 ); } } @@ -237,8 +251,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) { if( num_parts != 4 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -246,8 +260,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( md->handler->msglen <= 0 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -261,14 +275,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) md->grouplist = g_new0( char *, md->groupcount ); if( !*cmd[3] || md->buddycount == 0 ) - msn_logged_in( gc ); + msn_logged_in( ic ); } else { /* Hrrm... This SYN reply doesn't really look like something we expected. Let's assume everything is okay. */ - msn_logged_in( gc ); + msn_logged_in( ic ); } } else if( strcmp( cmd[0], "LST" ) == 0 ) @@ -277,8 +291,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 4 && num_parts != 5 ) { - hide_login_progress( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -290,36 +304,37 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) char *group = NULL; int num; - if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 ) + if( cmd[4] != NULL && sscanf( cmd[4], "%d", &num ) == 1 && num < md->groupcount ) group = md->grouplist[num]; - add_buddy( gc, group, cmd[1], cmd[2] ); + imcb_add_buddy( ic, cmd[1], group ); + imcb_rename_buddy( ic, cmd[1], cmd[2] ); } if( list & 2 ) /* AL */ { - gc->permit = g_slist_append( gc->permit, g_strdup( cmd[1] ) ); + ic->permit = g_slist_append( ic->permit, g_strdup( cmd[1] ) ); } if( list & 4 ) /* BL */ { - gc->deny = g_slist_append( gc->deny, g_strdup( cmd[1] ) ); + ic->deny = g_slist_append( ic->deny, g_strdup( cmd[1] ) ); } if( list & 8 ) /* RL */ { if( ( list & 6 ) == 0 ) - msn_buddy_ask( gc, cmd[1], cmd[2] ); + msn_buddy_ask( ic, cmd[1], cmd[2] ); } if( --md->buddycount == 0 ) { - if( gc->flags & OPT_LOGGED_IN ) + if( ic->flags & OPT_LOGGED_IN ) { - serv_got_crap( gc, "Successfully transferred to different server" ); + imcb_log( ic, "Successfully transferred to different server" ); 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( msn_write( ic, buf, strlen( buf ) ) ); } else { - msn_logged_in( gc ); + msn_logged_in( ic ); } } } @@ -329,8 +344,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 4 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -348,8 +363,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 3 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -362,7 +377,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) for( i = 0; i < 16; i ++ ) g_snprintf( buf + strlen( buf ), 3, "%02x", digest[i] ); - return( msn_write( gc, buf, strlen( buf ) ) ); + return( msn_write( ic, buf, strlen( buf ) ) ); } else if( strcmp( cmd[0], "ILN" ) == 0 ) { @@ -370,13 +385,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 6 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } http_decode( cmd[4] ); - serv_buddy_rename( gc, cmd[3], cmd[4] ); + imcb_rename_buddy( ic, cmd[3], cmd[4] ); st = msn_away_state_by_code( cmd[2] ); if( !st ) @@ -385,12 +400,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) st = msn_away_state_list; } - serv_got_update( gc, cmd[3], 1, 0, 0, 0, st->number, 0 ); + imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN | + ( st->number ? OPT_AWAY : 0 ), st->name, NULL ); } else if( strcmp( cmd[0], "FLN" ) == 0 ) { if( cmd[1] ) - serv_got_update( gc, cmd[1], 0, 0, 0, 0, 0, 0 ); + imcb_buddy_status( ic, cmd[1], 0, NULL, NULL ); } else if( strcmp( cmd[0], "NLN" ) == 0 ) { @@ -398,13 +414,13 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 5 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } http_decode( cmd[3] ); - serv_buddy_rename( gc, cmd[2], cmd[3] ); + imcb_rename_buddy( ic, cmd[2], cmd[3] ); st = msn_away_state_by_code( cmd[1] ); if( !st ) @@ -413,7 +429,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) st = msn_away_state_list; } - serv_got_update( gc, cmd[2], 1, 0, 0, 0, st->number, 0 ); + imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | + ( st->number ? OPT_AWAY : 0 ), st->name, NULL ); } else if( strcmp( cmd[0], "RNG" ) == 0 ) { @@ -423,8 +440,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts != 7 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } @@ -433,8 +450,8 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) server = strchr( cmd[2], ':' ); if( !server ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } *server = 0; @@ -443,14 +460,14 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[3], "CKI" ) != 0 ) { - hide_login_progress_error( gc, "Unknown authentication method for switchboard" ); - signoff( gc ); + imcb_error( ic, "Unknown authentication method for switchboard" ); + imc_logout( ic, TRUE ); return( 0 ); } debug( "Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4] ); - sb = msn_sb_create( gc, server, port, cmd[4], session ); + sb = msn_sb_create( ic, server, port, cmd[4], session ); sb->who = g_strdup( cmd[5] ); } else if( strcmp( cmd[0], "ADD" ) == 0 ) @@ -463,74 +480,91 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( strchr( cmd[4], '@' ) == NULL ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); - return( 0 ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); + return 0; } - /* 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 ) + /* We got added by someone. If we don't have this + person in permit/deny yet, inform the user. */ + for( l = ic->permit; l; l = l->next ) if( g_strcasecmp( l->data, cmd[4] ) == 0 ) - return( 1 ); + return 1; - for( l = gc->deny; l; l = l->next ) + for( l = ic->deny; l; l = l->next ) if( g_strcasecmp( l->data, cmd[4] ) == 0 ) - return( 1 ); + return 1; - msn_buddy_ask( gc, cmd[4], cmd[5] ); + msn_buddy_ask( ic, cmd[4], cmd[5] ); + } + else if( num_parts >= 6 && strcmp( cmd[2], "FL" ) == 0 ) + { + http_decode( cmd[5] ); + imcb_add_buddy( ic, cmd[4], NULL ); + imcb_rename_buddy( ic, cmd[4], cmd[5] ); } } else if( strcmp( cmd[0], "OUT" ) == 0 ) { + int allow_reconnect = TRUE; + if( cmd[1] && strcmp( cmd[1], "OTH" ) == 0 ) { - hide_login_progress_error( gc, "Someone else logged in with your account" ); - gc->wants_to_die = 1; + imcb_error( ic, "Someone else logged in with your account" ); + allow_reconnect = FALSE; } else if( cmd[1] && strcmp( cmd[1], "SSD" ) == 0 ) { - hide_login_progress_error( gc, "Terminating session because of server shutdown" ); + imcb_error( ic, "Terminating session because of server shutdown" ); } else { - hide_login_progress_error( gc, "Session terminated by remote server (reason unknown)" ); + imcb_error( ic, "Session terminated by remote server (reason unknown)" ); } - signoff( gc ); + imc_logout( ic, allow_reconnect ); return( 0 ); } else if( strcmp( cmd[0], "REA" ) == 0 ) { if( num_parts != 5 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } - if( g_strcasecmp( cmd[3], gc->username ) == 0 ) + if( g_strcasecmp( cmd[3], ic->acc->user ) == 0 ) { + set_t *s; + http_decode( cmd[4] ); - strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); - gc->displayname[sizeof(gc->displayname)-1] = 0; + strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); + ic->displayname[sizeof(ic->displayname)-1] = 0; + + if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) + { + g_free( s->value ); + s->value = g_strdup( cmd[4] ); + } } else { /* This is not supposed to happen, but let's handle it anyway... */ http_decode( cmd[4] ); - serv_buddy_rename( gc, cmd[3], cmd[4] ); + imcb_rename_buddy( ic, cmd[3], cmd[4] ); } } else if( strcmp( cmd[0], "IPG" ) == 0 ) { - do_error_dialog( gc, "Received IPG command, we don't handle them yet.", "MSN" ); + imcb_error( ic, "Received IPG command, we don't handle them yet." ); md->handler->msglen = atoi( cmd[1] ); if( md->handler->msglen <= 0 ) { - hide_login_progress_error( gc, "Syntax error" ); - signoff( gc ); + imcb_error( ic, "Syntax error" ); + imc_logout( ic, TRUE ); return( 0 ); } } @@ -539,18 +573,17 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) int num = atoi( cmd[0] ); const struct msn_status_code *err = msn_status_by_number( num ); - g_snprintf( buf, sizeof( buf ), "Error reported by MSN server: %s", err->text ); - do_error_dialog( gc, buf, "MSN" ); + imcb_error( ic, "Error reported by MSN server: %s", err->text ); if( err->flags & STATUS_FATAL ) { - signoff( gc ); + imc_logout( ic, TRUE ); return( 0 ); } } else { - debug( "Received unknown command from main server: %s", cmd[0] ); + /* debug( "Received unknown command from main server: %s", cmd[0] ); */ } return( 1 ); @@ -558,7 +591,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ) { - struct gaim_connection *gc = data; + struct im_connection *ic = data; char *body; int blen = 0; @@ -594,7 +627,7 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int if( mtype && strcmp( mtype, "1" ) == 0 ) { if( arg1 ) - serv_got_crap( gc, "The server is going down for maintenance in %s minutes.", arg1 ); + imcb_log( ic, "The server is going down for maintenance in %s minutes.", arg1 ); } if( arg1 ) g_free( arg1 ); @@ -609,9 +642,9 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int char *inbox = msn_findheader( body, "Inbox-Unread:", blen ); char *folders = msn_findheader( body, "Folders-Unread:", blen ); - if( inbox && folders ) + if( inbox && folders && set_getbool( &ic->acc->set, "mail_notifications" ) ) { - serv_got_crap( gc, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); + imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); } } else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 ) @@ -619,9 +652,9 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int char *from = msn_findheader( body, "From-Addr:", blen ); char *fromname = msn_findheader( body, "From:", blen ); - if( from && fromname ) + if( from && fromname && set_getbool( &ic->acc->set, "mail_notifications" ) ) { - serv_got_crap( gc, "Received an e-mail message from %s <%s>.", fromname, from ); + imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from ); } } else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 ) @@ -640,21 +673,26 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -static void msn_auth_got_passport_id( struct passport_reply *rep ) +static void msn_auth_got_passport_token( struct msn_auth_data *mad ) { - struct gaim_connection *gc = rep->data; - struct msn_data *md = gc->proto_data; - char *key = rep->result; - char buf[1024]; + struct im_connection *ic = mad->data; + struct msn_data *md; - if( key == NULL ) + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + if( mad->token ) { - hide_login_progress( gc, "Error during Passport authentication" ); - signoff( gc ); + char buf[1024]; + + g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); + msn_write( ic, buf, strlen( buf ) ); } else { - g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); - msn_write( gc, buf, strlen( buf ) ); + imcb_error( ic, "Error during Passport authentication: %s", mad->error ); + imc_logout( ic, TRUE ); } } diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 34703432..565d15f3 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -1,8 +1,7 @@ -/* passport.c +/** passport.c * - * Functions to login to microsoft passport service for Messenger - * Copyright (C) 2004 Wouter Paesen <wouter@blue-gate.be> - * Copyright (C) 2004 Wilmer van der Gaast <wilmer@gaast.net> + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast <wilmer@gaast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -23,189 +22,149 @@ #include "passport.h" #include "msn.h" #include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "xmltree.h" #include <ctype.h> #include <errno.h> -#define MSN_BUF_LEN 8192 +static int passport_get_token_real( struct msn_auth_data *mad ); +static void passport_get_token_ready( struct http_request *req ); -static char *prd_cached = NULL; - -static int passport_get_id_real( gpointer func, gpointer data, char *header ); -static void passport_get_id_ready( struct http_request *req ); - -static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); -static void passport_retrieve_dalogin_ready( struct http_request *req ); - -static char *passport_create_header( char *cookie, char *email, char *pwd ); -static void destroy_reply( struct passport_reply *rep ); - -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) { - char *header = passport_create_header( cookie, username, password ); + struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); + int i; - if( prd_cached == NULL ) - return passport_retrieve_dalogin( func, data, header ); - else - return passport_get_id_real( func, data, header ); + mad->username = g_strdup( username ); + mad->password = g_strdup( password ); + mad->cookie = g_strdup( cookie ); + + mad->callback = func; + mad->data = data; + + mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); + mad->ttl = 3; /* Max. # of redirects. */ + + /* HTTP-escape stuff and s/,/&/ */ + http_decode( mad->cookie ); + for( i = 0; mad->cookie[i]; i ++ ) + if( mad->cookie[i] == ',' ) + mad->cookie[i] = '&'; + + /* Microsoft doesn't allow password longer than 16 chars and silently + fails authentication if you give the "full version" of your passwd. */ + if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) + mad->password[MAX_PASSPORT_PWLEN] = 0; + + return passport_get_token_real( mad ); } -static int passport_get_id_real( gpointer func, gpointer data, char *header ) +static int passport_get_token_real( struct msn_auth_data *mad ) { - struct passport_reply *rep; - char *server, *dummy, *reqs; + char *post_payload, *post_request; struct http_request *req; + url_t url; - rep = g_new0( struct passport_reply, 1 ); - rep->data = data; - rep->func = func; - - server = g_strdup( prd_cached ); - dummy = strchr( server, '/' ); - - if( dummy == NULL ) - { - destroy_reply( rep ); - return( 0 ); - } + url_set( &url, mad->url ); - reqs = g_malloc( strlen( header ) + strlen( dummy ) + 128 ); - sprintf( reqs, "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); + post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, + mad->username, + mad->password, + mad->cookie ); - *dummy = 0; - req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); + post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, + url.file, url.host, + (int) strlen( post_payload ), + post_payload ); + + req = http_dorequest( url.host, url.port, 1, post_request, + passport_get_token_ready, mad ); - g_free( server ); - g_free( reqs ); + g_free( post_request ); + g_free( post_payload ); - if( req == NULL ) - destroy_reply( rep ); - - return( req != NULL ); + return req != NULL; } -static void passport_get_id_ready( struct http_request *req ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); + +static const struct xt_handler_entry passport_xt_handlers[] = { + { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, + { "S:Fault", "S:Envelope", passport_xt_handle_fault }, + { NULL, NULL, NULL } +}; + +static void passport_get_token_ready( struct http_request *req ) { - struct passport_reply *rep = req->data; + struct msn_auth_data *mad = req->data; + struct xt_parser *parser; - if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers ) - { - destroy_reply( rep ); - return; - } + g_free( mad->url ); + g_free( mad->error ); + mad->url = mad->error = NULL; if( req->status_code == 200 ) { - char *dummy; - - if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) - { - char *responseend; - - dummy += strlen( "from-PP='" ); - responseend = strchr( dummy, '\'' ); - if( responseend ) - *responseend = 0; - - rep->result = g_strdup( dummy ); - } + parser = xt_new( passport_xt_handlers, mad ); + xt_feed( parser, req->reply_body, req->body_size ); + xt_handle( parser, NULL, -1 ); + xt_free( parser ); + } + else + { + mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, + req->status_string ? req->status_string : "unknown" ); } - rep->func( rep ); - destroy_reply( rep ); -} - -static char *passport_create_header( char *cookie, char *email, char *pwd ) -{ - char *buffer = g_new0( char, 2048 ); - char *currenttoken; - char *email_enc, *pwd_enc; - - email_enc = g_new0( char, strlen( email ) * 3 + 1 ); - strcpy( email_enc, email ); - http_encode( email_enc ); - - pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); - strcpy( pwd_enc, pwd ); - http_encode( pwd_enc ); - - currenttoken = strstr( cookie, "lc=" ); - if( currenttoken == NULL ) - return( NULL ); - - g_snprintf( buffer, 2048, - "Authorization: Passport1.4 OrgVerb=GET," - "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," - "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, - currenttoken ); - - g_free( email_enc ); - g_free( pwd_enc ); + if( mad->error == NULL && mad->token == NULL ) + mad->error = g_strdup( "Could not parse Passport server response" ); - return( buffer ); + if( mad->url && mad->token == NULL ) + { + passport_get_token_real( mad ); + } + else + { + mad->callback( mad ); + + g_free( mad->url ); + g_free( mad->username ); + g_free( mad->password ); + g_free( mad->cookie ); + g_free( mad->token ); + g_free( mad->error ); + g_free( mad ); + } } -#define PPR_REQUEST "GET /rdr/pprdr.asp HTTP/1.0\r\n\r\n" -static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) { - struct passport_reply *rep = g_new0( struct passport_reply, 1 ); - struct http_request *req; - - rep->data = data; - rep->func = func; - rep->header = header; - - req = http_dorequest( "nexus.passport.com", 443, 1, PPR_REQUEST, passport_retrieve_dalogin_ready, rep ); + struct msn_auth_data *mad = data; + char *s; - if( !req ) - destroy_reply( rep ); + if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) + mad->token = g_memdup( node->text, node->text_len + 1 ); - return( req != NULL ); + return XT_HANDLED; } -static void passport_retrieve_dalogin_ready( struct http_request *req ) +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) { - struct passport_reply *rep = req->data; - char *dalogin; - char *urlend; + struct msn_auth_data *mad = data; + struct xt_node *code = xt_find_node( node->children, "faultcode" ); + struct xt_node *string = xt_find_node( node->children, "faultstring" ); + struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); - if( !g_slist_find( msn_connections, rep->data ) || !req->finished || !req->reply_headers ) - { - destroy_reply( rep ); - return; - } - - dalogin = strstr( req->reply_headers, "DALogin=" ); - - if( !dalogin ) - goto failure; - - dalogin += strlen( "DALogin=" ); - urlend = strchr( dalogin, ',' ); - if( urlend ) - *urlend = 0; - - /* strip the http(s):// part from the url */ - urlend = strstr( urlend, "://" ); - if( urlend ) - dalogin = urlend + strlen( "://" ); - - if( prd_cached == NULL ) - prd_cached = g_strdup( dalogin ); + if( redirect && redirect->text_len && mad->ttl-- > 0 ) + mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); - if( passport_get_id_real( rep->func, rep->data, rep->header ) ) - { - destroy_reply( rep ); - return; - } + if( code == NULL || code->text_len == 0 ) + mad->error = g_strdup( "Unknown error" ); + else + mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? + string->text : "no description available" ); -failure: - rep->func( rep ); - destroy_reply( rep ); -} - -static void destroy_reply( struct passport_reply *rep ) -{ - g_free( rep->result ); - g_free( rep->header ); - g_free( rep ); + return XT_HANDLED; } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index f7e6ebb6..517d2e91 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -1,10 +1,7 @@ -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__ /* passport.h * - * Functions to login to Microsoft Passport Service for Messenger - * Copyright (C) 2004 Wouter Paesen <wouter@blue-gate.be>, - * Wilmer van der Gaast <wilmer@gaast.net> + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast <wilmer@gaast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -17,9 +14,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener + for the specs! */ + +#ifndef __PASSPORT_H__ +#define __PASSPORT_H__ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -32,14 +35,79 @@ #endif #include "nogaim.h" -struct passport_reply +#define MAX_PASSPORT_PWLEN 16 + +struct msn_auth_data { - void (*func)( struct passport_reply * ); - void *data; - char *result; - char *header; + char *url; + int ttl; + + char *username; + char *password; + char *cookie; + + /* The end result, the only thing we'll really be interested in + once finished. */ + char *token; + char *error; /* Yeah, or that... */ + + void (*callback)( struct msn_auth_data *mad ); + gpointer data; }; -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); +#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" + +#define SOAP_AUTHENTICATION_REQUEST \ +"POST %s HTTP/1.0\r\n" \ +"Accept: text/*\r\n" \ +"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ +"Host: %s\r\n" \ +"Content-Length: %d\r\n" \ +"Cache-Control: no-cache\r\n" \ +"\r\n" \ +"%s" + +#define SOAP_AUTHENTICATION_PAYLOAD \ +"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" \ +"<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:wsse=\"http://schemas.xmlsoap.org/ws/2003/06/secext\" xmlns:saml=\"urn:oasis:names:tc:SAML:1.0:assertion\" xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2002/12/policy\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/03/addressing\" xmlns:wssc=\"http://schemas.xmlsoap.org/ws/2004/04/sc\" xmlns:wst=\"http://schemas.xmlsoap.org/ws/2004/04/trust\">" \ + "<Header>" \ + "<ps:AuthInfo xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"PPAuthInfo\">" \ + "<ps:HostingApp>{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}</ps:HostingApp>" \ + "<ps:BinaryVersion>4</ps:BinaryVersion>" \ + "<ps:UIVersion>1</ps:UIVersion>" \ + "<ps:Cookies></ps:Cookies>" \ + "<ps:RequestParams>AQAAAAIAAABsYwQAAAAzMDg0</ps:RequestParams>" \ + "</ps:AuthInfo>" \ + "<wsse:Security>" \ + "<wsse:UsernameToken Id=\"user\">" \ + "<wsse:Username>%s</wsse:Username>" \ + "<wsse:Password>%s</wsse:Password>" \ + "</wsse:UsernameToken>" \ + "</wsse:Security>" \ + "</Header>" \ + "<Body>" \ + "<ps:RequestMultipleSecurityTokens xmlns:ps=\"http://schemas.microsoft.com/Passport/SoapServices/PPCRL\" Id=\"RSTS\">" \ + "<wst:RequestSecurityToken Id=\"RST0\">" \ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ + "<wsp:AppliesTo>" \ + "<wsa:EndpointReference>" \ + "<wsa:Address>http://Passport.NET/tb</wsa:Address>" \ + "</wsa:EndpointReference>" \ + "</wsp:AppliesTo>" \ + "</wst:RequestSecurityToken>" \ + "<wst:RequestSecurityToken Id=\"RST1\">" \ + "<wst:RequestType>http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue</wst:RequestType>" \ + "<wsp:AppliesTo>" \ + "<wsa:EndpointReference>" \ + "<wsa:Address>messenger.msn.com</wsa:Address>" \ + "</wsa:EndpointReference>" \ + "</wsp:AppliesTo>" \ + "<wsse:PolicyReference URI=\"?%s\"></wsse:PolicyReference>" \ + "</wst:RequestSecurityToken>" \ + "</ps:RequestMultipleSecurityTokens>" \ + "</Body>" \ +"</Envelope>" + +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ); #endif /* __PASSPORT_H__ */ diff --git a/protocols/msn/sb.c b/protocols/msn/sb.c index 34b0a30a..18c41ef5 100644 --- a/protocols/msn/sb.c +++ b/protocols/msn/sb.c @@ -29,7 +29,7 @@ #include "passport.h" #include "md5.h" -static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond ); +static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ); static int msn_sb_command( gpointer data, char **cmd, int num_parts ); static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); @@ -47,9 +47,9 @@ int msn_sb_write( struct msn_switchboard *sb, char *s, int len ) return( 1 ); } -struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, int port, char *key, int session ) +struct msn_switchboard *msn_sb_create( struct im_connection *ic, char *host, int port, char *key, int session ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; struct msn_switchboard *sb = g_new0( struct msn_switchboard, 1 ); sb->fd = proxy_connect( host, port, msn_sb_connected, sb ); @@ -59,7 +59,7 @@ struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, i return( NULL ); } - sb->gc = gc; + sb->ic = ic; sb->key = g_strdup( key ); sb->session = session; @@ -69,9 +69,9 @@ struct msn_switchboard *msn_sb_create( struct gaim_connection *gc, char *host, i return( sb ); } -struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *handle ) +struct msn_switchboard *msn_sb_by_handle( struct im_connection *ic, char *handle ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; struct msn_switchboard *sb; GSList *l; @@ -85,25 +85,25 @@ struct msn_switchboard *msn_sb_by_handle( struct gaim_connection *gc, char *hand return( NULL ); } -struct msn_switchboard *msn_sb_by_id( struct gaim_connection *gc, int id ) +struct msn_switchboard *msn_sb_by_chat( struct groupchat *c ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = c->ic->proto_data; struct msn_switchboard *sb; GSList *l; for( l = md->switchboards; l; l = l->next ) { sb = l->data; - if( sb->chat && sb->chat->id == id ) + if( sb->chat == c ) return( sb ); } return( NULL ); } -struct msn_switchboard *msn_sb_spare( struct gaim_connection *gc ) +struct msn_switchboard *msn_sb_spare( struct im_connection *ic ) { - struct msn_data *md = gc->proto_data; + struct msn_data *md = ic->proto_data; struct msn_switchboard *sb; GSList *l; @@ -121,12 +121,13 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) { if( sb->ready ) { - char cmd[1024], *buf; + char *packet, *buf; int i, j; + /* Build the message. Convert LF to CR-LF for normal messages. */ if( strcmp( text, TYPING_NOTIFICATION_MESSAGE ) != 0 ) { - buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 ); + buf = g_new0( char, sizeof( MSN_MESSAGE_HEADERS ) + strlen( text ) * 2 + 1 ); i = strlen( MSN_MESSAGE_HEADERS ); strcpy( buf, MSN_MESSAGE_HEADERS ); @@ -140,20 +141,22 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) } else { - i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->gc->username ); - buf = g_new0( char, strlen( MSN_TYPING_HEADERS ) + strlen( sb->gc->username ) ); - i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->gc->username ); + i = strlen( MSN_TYPING_HEADERS ) + strlen( sb->ic->acc->user ); + buf = g_new0( char, i ); + i = g_snprintf( buf, i, MSN_TYPING_HEADERS, sb->ic->acc->user ); } - g_snprintf( cmd, sizeof( cmd ), "MSG %d N %d\r\n", ++sb->trId, i ); - if( msn_sb_write( sb, cmd, strlen( cmd ) ) && msn_sb_write( sb, buf, i ) ) + /* Build the final packet (MSG command + the message). */ + packet = g_strdup_printf( "MSG %d N %d\r\n%s", ++sb->trId, i, buf ); + g_free( buf ); + if( msn_sb_write( sb, packet, strlen( packet ) ) ) { - g_free( buf ); + g_free( packet ); return( 1 ); } else { - g_free( buf ); + g_free( packet ); return( 0 ); } } @@ -173,18 +176,18 @@ int msn_sb_sendmessage( struct msn_switchboard *sb, char *text ) } } -void msn_sb_to_chat( struct msn_switchboard *sb ) +struct groupchat *msn_sb_to_chat( struct msn_switchboard *sb ) { - struct gaim_connection *gc = sb->gc; + struct im_connection *ic = sb->ic; char buf[1024]; /* Create the groupchat structure. */ g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); - sb->chat = serv_got_joined_chat( gc, ++msn_chat_id, buf ); + sb->chat = imcb_chat_new( ic, buf ); /* Populate the channel. */ - if( sb->who ) add_chat_buddy( sb->chat, sb->who ); - add_chat_buddy( sb->chat, gc->username ); + if( sb->who ) imcb_chat_add_buddy( sb->chat, sb->who ); + imcb_chat_add_buddy( sb->chat, ic->acc->user ); /* And make sure the switchboard doesn't look like a regular chat anymore. */ if( sb->who ) @@ -192,41 +195,25 @@ void msn_sb_to_chat( struct msn_switchboard *sb ) g_free( sb->who ); sb->who = NULL; } + + return sb->chat; } void msn_sb_destroy( struct msn_switchboard *sb ) { - struct gaim_connection *gc = sb->gc; - struct msn_data *md = gc->proto_data; + struct im_connection *ic = sb->ic; + struct msn_data *md = ic->proto_data; debug( "Destroying switchboard: %s", sb->who ? sb->who : sb->key ? sb->key : "" ); - if( sb->msgq ) - { - struct msn_message *m; - GSList *l; - - for( l = sb->msgq; l; l = l->next ) - { - m = l->data; - - g_free( m->who ); - g_free( m->text ); - g_free( m ); - } - g_slist_free( sb->msgq ); - - serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with " - "unsent message to %s, you'll have to resend it.", - sb->who ? sb->who : "(unknown)" ); - } + msn_msgq_purge( ic, &sb->msgq ); if( sb->key ) g_free( sb->key ); if( sb->who ) g_free( sb->who ); if( sb->chat ) { - serv_got_chat_left( gc, sb->chat->id ); + imcb_chat_free( sb->chat ); } if( sb->handler ) @@ -236,7 +223,7 @@ void msn_sb_destroy( struct msn_switchboard *sb ) g_free( sb->handler ); } - if( sb->inp ) gaim_input_remove( sb->inp ); + if( sb->inp ) b_event_remove( sb->inp ); closesocket( sb->fd ); msn_switchboards = g_slist_remove( msn_switchboards, sb ); @@ -244,25 +231,25 @@ void msn_sb_destroy( struct msn_switchboard *sb ) g_free( sb ); } -void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) +gboolean msn_sb_connected( gpointer data, gint source, b_input_condition cond ) { struct msn_switchboard *sb = data; - struct gaim_connection *gc; + struct im_connection *ic; struct msn_data *md; char buf[1024]; /* Are we still alive? */ if( !g_slist_find( msn_switchboards, sb ) ) - return; + return FALSE; - gc = sb->gc; - md = gc->proto_data; + ic = sb->ic; + md = ic->proto_data; if( source != sb->fd ) { - debug( "ERROR %d while connecting to switchboard server", 1 ); + debug( "Error %d while connecting to switchboard server", 1 ); msn_sb_destroy( sb ); - return; + return FALSE; } /* Prepare the callback */ @@ -274,31 +261,80 @@ void msn_sb_connected( gpointer data, gint source, GaimInputCondition cond ) sb->handler->exec_message = msn_sb_message; if( sb->session == MSN_SB_NEW ) - g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, gc->username, sb->key ); + g_snprintf( buf, sizeof( buf ), "USR %d %s %s\r\n", ++sb->trId, ic->acc->user, sb->key ); else - g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, gc->username, sb->key, sb->session ); + g_snprintf( buf, sizeof( buf ), "ANS %d %s %s %d\r\n", ++sb->trId, ic->acc->user, sb->key, sb->session ); if( msn_sb_write( sb, buf, strlen( buf ) ) ) - sb->inp = gaim_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); + sb->inp = b_input_add( sb->fd, GAIM_INPUT_READ, msn_sb_callback, sb ); else - debug( "ERROR %d while connecting to switchboard server", 2 ); + debug( "Error %d while connecting to switchboard server", 2 ); + + return FALSE; } -static void msn_sb_callback( gpointer data, gint source, GaimInputCondition cond ) +static gboolean msn_sb_callback( gpointer data, gint source, b_input_condition cond ) { struct msn_switchboard *sb = data; + struct im_connection *ic = sb->ic; + struct msn_data *md = ic->proto_data; if( msn_handler( sb->handler ) == -1 ) { - debug( "ERROR: Switchboard died" ); + time_t now = time( NULL ); + + if( now - md->first_sb_failure > 600 ) + { + /* It's not really the first one, but the start of this "series". + With this, the warning below will be shown only if this happens + at least three times in ten minutes. This algorithm isn't + perfect, but for this purpose it will do. */ + md->first_sb_failure = now; + md->sb_failures = 0; + } + + debug( "Error: Switchboard died" ); + if( ++ md->sb_failures >= 3 ) + imcb_log( ic, "Warning: Many switchboard failures on MSN connection. " + "There might be problems delivering your messages." ); + + if( sb->msgq != NULL ) + { + char buf[1024]; + + if( md->msgq == NULL ) + { + md->msgq = sb->msgq; + } + else + { + GSList *l; + + for( l = md->msgq; l->next; l = l->next ); + l->next = sb->msgq; + } + sb->msgq = NULL; + + debug( "Moved queued messages back to the main queue, creating a new switchboard to retry." ); + g_snprintf( buf, sizeof( buf ), "XFR %d SB\r\n", ++md->trId ); + if( !msn_write( ic, buf, strlen( buf ) ) ) + return FALSE; + } + msn_sb_destroy( sb ); + + return FALSE; + } + else + { + return TRUE; } } static int msn_sb_command( gpointer data, char **cmd, int num_parts ) { struct msn_switchboard *sb = data; - struct gaim_connection *gc = sb->gc; + struct im_connection *ic = sb->ic; char buf[1024]; if( !num_parts ) @@ -309,8 +345,8 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) if( strcmp( cmd[0], "XFR" ) == 0 ) { - hide_login_progress_error( gc, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); - signoff( gc ); + imcb_error( ic, "Received an XFR from a switchboard server, unable to comply! This is likely to be a bug, please report it!" ); + imc_logout( ic, TRUE ); return( 0 ); } else if( strcmp( cmd[0], "USR" ) == 0 ) @@ -362,17 +398,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) if( num == 1 ) { g_snprintf( buf, sizeof( buf ), "MSN groupchat session %d", sb->session ); - sb->chat = serv_got_joined_chat( gc, ++msn_chat_id, buf ); + sb->chat = imcb_chat_new( ic, buf ); g_free( sb->who ); sb->who = NULL; } - add_chat_buddy( sb->chat, cmd[4] ); + imcb_chat_add_buddy( sb->chat, cmd[4] ); if( num == tot ) { - add_chat_buddy( sb->chat, gc->username ); + imcb_chat_add_buddy( sb->chat, ic->acc->user ); } } } @@ -450,11 +486,11 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) /* This SB is a one-to-one chat right now, but someone else is joining. */ msn_sb_to_chat( sb ); - add_chat_buddy( sb->chat, cmd[1] ); + imcb_chat_add_buddy( sb->chat, cmd[1] ); } else if( sb->chat ) { - add_chat_buddy( sb->chat, cmd[1] ); + imcb_chat_add_buddy( sb->chat, cmd[1] ); sb->ready = 1; } else @@ -479,6 +515,17 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } } + else if( strcmp( cmd[0], "NAK" ) == 0 ) + { + if( sb->who ) + { + imcb_log( ic, "The MSN servers could not deliver one of your messages to %s.", sb->who ); + } + else + { + imcb_log( ic, "The MSN servers could not deliver one of your groupchat messages to all participants." ); + } + } else if( strcmp( cmd[0], "BYE" ) == 0 ) { if( num_parts < 2 ) @@ -504,7 +551,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( sb->chat ) { - remove_chat_buddy( sb->chat, cmd[1], "" ); + imcb_chat_remove_buddy( sb->chat, cmd[1], "" ); } else { @@ -516,8 +563,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) int num = atoi( cmd[0] ); const struct msn_status_code *err = msn_status_by_number( num ); - g_snprintf( buf, sizeof( buf ), "Error reported by switchboard server: %s", err->text ); - do_error_dialog( gc, buf, "MSN" ); + imcb_error( ic, "Error reported by switchboard server: %s", err->text ); if( err->flags & STATUS_SB_FATAL ) { @@ -526,31 +572,20 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else if( err->flags & STATUS_FATAL ) { - signoff( gc ); + imc_logout( ic, TRUE ); return 0; } else if( err->flags & STATUS_SB_IM_SPARE ) { if( sb->who ) { - struct msn_message *m; - GSList *l; - /* Apparently some invitation failed. We might want to use this board later, so keep it as a spare. */ g_free( sb->who ); sb->who = NULL; /* Also clear the msgq, otherwise someone else might get them. */ - for( l = sb->msgq; l; l = l->next ) - { - m = l->data; - g_free( m->who ); - g_free( m->text ); - g_free( m ); - } - g_slist_free( sb->msgq ); - sb->msgq = NULL; + msn_msgq_purge( ic, &sb->msgq ); } /* Do NOT return 0 here, we want to keep this sb. */ @@ -558,7 +593,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) } else { - debug( "Received unknown command from switchboard server: %s", cmd[0] ); + /* debug( "Received unknown command from switchboard server: %s", cmd[0] ); */ } return( 1 ); @@ -567,7 +602,7 @@ static int msn_sb_command( gpointer data, char **cmd, int num_parts ) static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ) { struct msn_switchboard *sb = data; - struct gaim_connection *gc = sb->gc; + struct im_connection *ic = sb->ic; char *body; int blen = 0; @@ -596,11 +631,11 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int if( sb->who ) { - serv_got_im( gc, cmd[1], body, 0, 0, blen ); + imcb_buddy_msg( ic, cmd[1], body, 0, 0 ); } else if( sb->chat ) { - serv_got_chat_in( gc, sb->chat->id, cmd[1], 0, body, 0 ); + imcb_chat_msg( sb->chat, cmd[1], body, 0, 0 ); } else { @@ -655,11 +690,11 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int if( sb->who ) { - serv_got_im( gc, cmd[1], buf, 0, 0, strlen( buf ) ); + imcb_buddy_msg( ic, cmd[1], buf, 0, 0 ); } else if( sb->chat ) { - serv_got_chat_in( gc, sb->chat->id, cmd[1], 0, buf, 0 ); + imcb_chat_msg( sb->chat, cmd[1], buf, 0, 0 ); } else { @@ -672,7 +707,7 @@ static int msn_sb_message( gpointer data, char *msg, int msglen, char **cmd, int if( who ) { - serv_got_typing( gc, who, 5, 1 ); + imcb_buddy_typing( ic, who, OPT_TYPING ); g_free( who ); } |