aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/msn
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/msn')
-rw-r--r--protocols/msn/Makefile4
-rw-r--r--protocols/msn/msn.c303
-rw-r--r--protocols/msn/msn.h42
-rw-r--r--protocols/msn/msn_util.c139
-rw-r--r--protocols/msn/ns.c298
-rw-r--r--protocols/msn/passport.c265
-rw-r--r--protocols/msn/passport.h92
-rw-r--r--protocols/msn/sb.c219
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 );
}