diff options
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/jabber/io.c | 42 | ||||
-rw-r--r-- | protocols/jabber/iq.c | 29 | ||||
-rw-r--r-- | protocols/jabber/jabber.c | 22 | ||||
-rw-r--r-- | protocols/jabber/jabber.h | 7 | ||||
-rw-r--r-- | protocols/jabber/jabber_util.c | 9 | ||||
-rw-r--r-- | protocols/jabber/presence.c | 17 | ||||
-rw-r--r-- | protocols/msn/msn.c | 22 | ||||
-rw-r--r-- | protocols/msn/msn.h | 7 | ||||
-rw-r--r-- | protocols/msn/msn_util.c | 8 | ||||
-rw-r--r-- | protocols/msn/ns.c | 74 | ||||
-rw-r--r-- | protocols/msn/tables.c | 37 | ||||
-rw-r--r-- | protocols/nogaim.c | 159 | ||||
-rw-r--r-- | protocols/nogaim.h | 23 | ||||
-rw-r--r-- | protocols/oscar/oscar.c | 39 | ||||
-rw-r--r-- | protocols/yahoo/libyahoo2.c | 366 | ||||
-rw-r--r-- | protocols/yahoo/yahoo.c | 41 | ||||
-rw-r--r-- | protocols/yahoo/yahoo2_types.h | 23 |
17 files changed, 458 insertions, 467 deletions
diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 10efad37..a14ad21c 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -374,39 +374,13 @@ static xt_status jabber_pkt_features( struct xt_node *node, gpointer data ) } if( ( c = xt_find_node( node->children, "bind" ) ) ) - { - reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); - xt_add_attr( reply, "xmlns", XMLNS_BIND ); - reply = jabber_make_packet( "iq", "set", NULL, reply ); - jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); - - if( !jabber_write_packet( ic, reply ) ) - return XT_ABORT; - - jd->flags |= JFLAG_WAIT_BIND; - } + jd->flags |= JFLAG_WANT_BIND; if( ( c = xt_find_node( node->children, "session" ) ) ) - { - reply = xt_new_node( "session", NULL, NULL ); - xt_add_attr( reply, "xmlns", XMLNS_SESSION ); - reply = jabber_make_packet( "iq", "set", NULL, reply ); - jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); - - if( !jabber_write_packet( ic, reply ) ) - return XT_ABORT; - - jd->flags |= JFLAG_WAIT_SESSION; - } + jd->flags |= JFLAG_WANT_SESSION; - /* This flag is already set if we authenticated via SASL, so now - we can resume the session in the new stream, if we don't have - to bind/initialize the session. */ - if( jd->flags & JFLAG_AUTHENTICATED && ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) - { - if( !jabber_get_roster( ic ) ) - return XT_ABORT; - } + if( jd->flags & JFLAG_AUTHENTICATED ) + return jabber_pkt_bind_sess( ic, NULL, NULL ); return XT_HANDLED; } @@ -440,6 +414,7 @@ static xt_status jabber_pkt_proceed_tls( struct xt_node *node, gpointer data ) imcb_log( ic, "Converting stream to TLS" ); + jd->flags |= JFLAG_STARTTLS_DONE; jd->ssl = ssl_starttls( jd->fd, jabber_connected_ssl, ic ); return XT_HANDLED; @@ -530,9 +505,10 @@ gboolean jabber_start_stream( struct im_connection *ic ) if( jd->r_inpa <= 0 ) jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); - greet = g_strdup_printf( "<?xml version='1.0' ?>" - "<stream:stream to=\"%s\" xmlns=\"jabber:client\" " - "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", jd->server ); + greet = g_strdup_printf( "%s<stream:stream to=\"%s\" xmlns=\"jabber:client\" " + "xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", + ( jd->flags & JFLAG_STARTTLS_DONE ) ? "" : "<?xml version='1.0' ?>", + jd->server ); st = jabber_write( ic, greet, strlen( greet ) ); diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 875b5c81..1b76a761 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -297,24 +297,39 @@ static xt_status jabber_finish_iq_auth( struct im_connection *ic, struct xt_node xt_status jabber_pkt_bind_sess( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) { struct jabber_data *jd = ic->proto_data; - struct xt_node *c; + struct xt_node *c, *reply = NULL; char *s; - if( ( c = xt_find_node( node->children, "bind" ) ) ) + if( node && ( c = xt_find_node( node->children, "bind" ) ) ) { c = xt_find_node( c->children, "jid" ); if( c && c->text_len && ( s = strchr( c->text, '/' ) ) && strcmp( s + 1, set_getstr( &ic->acc->set, "resource" ) ) != 0 ) imcb_log( ic, "Server changed session resource string to `%s'", s + 1 ); - - jd->flags &= ~JFLAG_WAIT_BIND; } - else + + if( jd->flags & JFLAG_WANT_BIND ) { - jd->flags &= ~JFLAG_WAIT_SESSION; + reply = xt_new_node( "bind", NULL, xt_new_node( "resource", set_getstr( &ic->acc->set, "resource" ), NULL ) ); + xt_add_attr( reply, "xmlns", XMLNS_BIND ); + jd->flags &= ~JFLAG_WANT_BIND; + } + else if( jd->flags & JFLAG_WANT_SESSION ) + { + reply = xt_new_node( "session", NULL, NULL ); + xt_add_attr( reply, "xmlns", XMLNS_SESSION ); + jd->flags &= ~JFLAG_WANT_SESSION; } - if( ( jd->flags & ( JFLAG_WAIT_BIND | JFLAG_WAIT_SESSION ) ) == 0 ) + if( reply != NULL ) + { + reply = jabber_make_packet( "iq", "set", NULL, reply ); + jabber_cache_add( ic, reply, jabber_pkt_bind_sess ); + + if( !jabber_write_packet( ic, reply ) ) + return XT_ABORT; + } + else if( ( jd->flags & ( JFLAG_WANT_BIND | JFLAG_WANT_SESSION ) ) == 0 ) { if( !jabber_get_roster( ic ) ) return XT_ABORT; diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index b8e88c26..a1fb8817 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -66,7 +66,7 @@ static void jabber_init( account_t *acc ) s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; - s = set_add( &acc->set, "resource_select", "priority", NULL, acc ); + s = set_add( &acc->set, "resource_select", "activity", NULL, acc ); s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK; @@ -79,6 +79,8 @@ static void jabber_init( account_t *acc ) s = set_add( &acc->set, "xmlconsole", "false", set_eval_bool, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; + + acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE; } static void jabber_generate_id_hash( struct jabber_data *jd ); @@ -363,10 +365,11 @@ static void jabber_get_info( struct im_connection *ic, char *who ) while( bud ) { - imcb_log( ic, "Buddy %s (%d) information:\nAway state: %s\nAway message: %s", - bud->full_jid, bud->priority, - bud->away_state ? bud->away_state->full_name : "(none)", - bud->away_message ? : "(none)" ); + imcb_log( ic, "Buddy %s (%d) information:", bud->full_jid, bud->priority ); + if( bud->away_state ) + imcb_log( ic, "Away state: %s", bud->away_state->full_name ); + imcb_log( ic, "Status message: %s", bud->away_message ? : "(none)" ); + bud = bud->next; } @@ -376,11 +379,12 @@ static void jabber_get_info( struct im_connection *ic, char *who ) static void jabber_set_away( struct im_connection *ic, char *state_txt, char *message ) { struct jabber_data *jd = ic->proto_data; - struct jabber_away_state *state; - /* Save all this info. We need it, for example, when changing the priority setting. */ - state = (void *) jabber_away_state_by_name( state_txt ); - jd->away_state = state ? state : (void *) jabber_away_state_list; /* Fall back to "Away" if necessary. */ + /* state_txt == NULL -> Not away. + Unknown state -> fall back to the first defined away state. */ + jd->away_state = state_txt ? jabber_away_state_by_name( state_txt ) + ? : jabber_away_state_list : NULL; + g_free( jd->away_message ); jd->away_message = ( message && *message ) ? g_strdup( message ) : NULL; diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 1180d2b9..8e3bf036 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -39,12 +39,13 @@ typedef enum JFLAG_AUTHENTICATED = 2, /* Set when we're successfully authenticatd. */ JFLAG_STREAM_RESTART = 4, /* Set when we want to restart the stream (after SASL or TLS). */ - JFLAG_WAIT_SESSION = 8, /* Set if we sent a <session> tag and need a reply + JFLAG_WANT_SESSION = 8, /* Set if the server wants a <session/> tag before we continue. */ - JFLAG_WAIT_BIND = 16, /* ... for <bind> tag. */ + JFLAG_WANT_BIND = 16, /* ... for <bind> tag. */ JFLAG_WANT_TYPING = 32, /* Set if we ever sent a typing notification, this activates all XEP-85 related code. */ JFLAG_XMLCONSOLE = 64, /* If the user added an xmlconsole buddy. */ + JFLAG_STARTTLS_DONE = 128, /* If a plaintext session was converted to TLS. */ } jabber_flags_t; typedef enum @@ -83,7 +84,7 @@ struct jabber_data /* After changing one of these two (or the priority setting), call presence_send_update() to inform the server about the changes. */ - struct jabber_away_state *away_state; + const struct jabber_away_state *away_state; char *away_message; md5_state_t cached_id_prefix; diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 19a73b6a..185d3878 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -227,10 +227,9 @@ xt_status jabber_cache_handle_packet( struct im_connection *ic, struct xt_node * const struct jabber_away_state jabber_away_state_list[] = { { "away", "Away" }, - { "chat", "Free for Chat" }, + { "chat", "Free for Chat" }, /* WTF actually uses this? */ { "dnd", "Do not Disturb" }, { "xa", "Extended Away" }, - { "", "Online" }, { "", NULL } }; @@ -238,6 +237,9 @@ const struct jabber_away_state *jabber_away_state_by_code( char *code ) { int i; + if( code == NULL ) + return NULL; + for( i = 0; jabber_away_state_list[i].full_name; i ++ ) if( g_strcasecmp( jabber_away_state_list[i].code, code ) == 0 ) return jabber_away_state_list + i; @@ -249,6 +251,9 @@ const struct jabber_away_state *jabber_away_state_by_name( char *name ) { int i; + if( name == NULL ) + return NULL; + for( i = 0; jabber_away_state_list[i].full_name; i ++ ) if( g_strcasecmp( jabber_away_state_list[i].full_name, name ) == 0 ) return jabber_away_state_list + i; diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 939bc888..28aaea1b 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -189,13 +189,12 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) { int is_away = 0; - if( send_presence->away_state && !( *send_presence->away_state->code == 0 || - strcmp( send_presence->away_state->code, "chat" ) == 0 ) ) + if( send_presence->away_state && + strcmp( send_presence->away_state->code, "chat" ) != 0 ) is_away = OPT_AWAY; imcb_buddy_status( ic, send_presence->bare_jid, OPT_LOGGED_IN | is_away, - ( is_away && send_presence->away_state ) ? - send_presence->away_state->full_name : NULL, + is_away ? send_presence->away_state->full_name : NULL, send_presence->away_message ); } @@ -208,17 +207,15 @@ int presence_send_update( struct im_connection *ic ) { struct jabber_data *jd = ic->proto_data; struct xt_node *node, *cap; - char *show = jd->away_state->code; - char *status = jd->away_message; struct groupchat *c; int st; node = jabber_make_packet( "presence", NULL, NULL, NULL ); xt_add_child( node, xt_new_node( "priority", set_getstr( &ic->acc->set, "priority" ), NULL ) ); - if( show && *show ) - xt_add_child( node, xt_new_node( "show", show, NULL ) ); - if( status ) - xt_add_child( node, xt_new_node( "status", status, NULL ) ); + if( jd->away_state ) + xt_add_child( node, xt_new_node( "show", jd->away_state->code, NULL ) ); + if( jd->away_message ) + xt_add_child( node, xt_new_node( "status", jd->away_message, NULL ) ); /* This makes the packet slightly bigger, but clients interested in capabilities can now cache the discovery info. This reduces the diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 046b2772..8930847d 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -26,6 +26,10 @@ #include "nogaim.h" #include "msn.h" +int msn_chat_id; +GSList *msn_connections; +GSList *msn_switchboards; + static char *msn_set_display_name( set_t *set, char *value ); static void msn_init( account_t *acc ) @@ -138,8 +142,9 @@ static GList *msn_away_states( struct im_connection *ic ) int i; 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 ); + for( i = 0; *msn_away_state_list[i].code; i ++ ) + if( *msn_away_state_list[i].name ) + l = g_list_append( l, (void*) msn_away_state_list[i].name ); return l; } @@ -148,17 +153,14 @@ static void msn_set_away( struct im_connection *ic, char *state, char *message ) { char buf[1024]; struct msn_data *md = ic->proto_data; - const struct msn_away_state *st; - if( strcmp( state, GAIM_AWAY_CUSTOM ) == 0 ) - st = msn_away_state_by_name( "Away" ); + if( state ) + md->away_state = msn_away_state_by_name( state ) ? : + msn_away_state_list + 1; else - st = msn_away_state_by_name( state ); - - if( !st ) st = msn_away_state_list; - md->away_state = st; + md->away_state = msn_away_state_list; - g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, st->code ); + g_snprintf( buf, sizeof( buf ), "CHG %d %s\r\n", ++md->trId, md->away_state->code ); msn_write( ic, buf, strlen( buf ) ); } diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index 7c849acf..84914bc3 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -96,7 +96,6 @@ struct msn_switchboard struct msn_away_state { - int number; char code[4]; char name[16]; }; @@ -135,7 +134,7 @@ struct msn_handler_data #define STATUS_SB_IM_SPARE 4 /* Make one-to-one conversation switchboard available again, invite failed. */ #define STATUS_SB_CHAT_SPARE 8 /* Same, but also for groupchats (not used yet). */ -int msn_chat_id; +extern int msn_chat_id; extern const struct msn_away_state msn_away_state_list[]; extern const struct msn_status_code msn_status_code_list[]; @@ -144,8 +143,8 @@ extern const struct msn_status_code msn_status_code_list[]; is down already (for example, when an impatient user disabled the connection), the callback should check whether it's still listed here before doing *anything* else. */ -GSList *msn_connections; -GSList *msn_switchboards; +extern GSList *msn_connections; +extern GSList *msn_switchboards; /* ns.c */ gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 58ad22f8..668a8b8a 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -170,9 +170,9 @@ char *msn_findheader( char *text, char *header, int len ) while( i < len && ( text[i] == '\r' || text[i] == '\n' ) ) i ++; /* End of headers? */ - if( strncmp( text + i - 2, "\n\n", 2 ) == 0 || - strncmp( text + i - 4, "\r\n\r\n", 4 ) == 0 || - strncmp( text + i - 2, "\r\r", 2 ) == 0 ) + if( ( i >= 4 && strncmp( text + i - 4, "\r\n\r\n", 4 ) == 0 ) || + ( i >= 2 && ( strncmp( text + i - 2, "\n\n", 2 ) == 0 || + strncmp( text + i - 2, "\r\r", 2 ) == 0 ) ) ) { break; } @@ -373,6 +373,6 @@ void msn_msgq_purge( struct im_connection *ic, GSList **list ) g_slist_free( *list ); *list = NULL; - imcb_log( ic, ret->str ); + imcb_log( ic, "%s", ret->str ); g_string_free( ret, TRUE ); } diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index fe48f96d..d78d753a 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -228,19 +228,26 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) return( 0 ); } } - else if( num_parts == 7 && strcmp( cmd[2], "OK" ) == 0 ) + else if( num_parts >= 7 && strcmp( cmd[2], "OK" ) == 0 ) { set_t *s; - http_decode( cmd[4] ); - - strncpy( ic->displayname, cmd[4], sizeof( ic->displayname ) ); - ic->displayname[sizeof(ic->displayname)-1] = 0; - - if( ( s = set_find( &ic->acc->set, "display_name" ) ) ) + if( num_parts == 7 ) { - g_free( s->value ); - s->value = g_strdup( cmd[4] ); + http_decode( cmd[4] ); + + 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 + { + imcb_log( ic, "Warning: Friendly name in server response was corrupted" ); } imcb_log( ic, "Authenticated, getting buddy list" ); @@ -419,11 +426,12 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( !st ) { /* FIXME: Warn/Bomb about unknown away state? */ - st = msn_away_state_list; + st = msn_away_state_list + 1; } - imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN | - ( st->number ? OPT_AWAY : 0 ), st->name, NULL ); + imcb_buddy_status( ic, cmd[3], OPT_LOGGED_IN | + ( st != msn_away_state_list ? OPT_AWAY : 0 ), + st->name, NULL ); } else if( strcmp( cmd[0], "FLN" ) == 0 ) { @@ -448,11 +456,12 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( !st ) { /* FIXME: Warn/Bomb about unknown away state? */ - st = msn_away_state_list; + st = msn_away_state_list + 1; } - imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | - ( st->number ? OPT_AWAY : 0 ), st->name, NULL ); + imcb_buddy_status( ic, cmd[2], OPT_LOGGED_IN | + ( st != msn_away_state_list ? OPT_AWAY : 0 ), + st->name, NULL ); } else if( strcmp( cmd[0], "RNG" ) == 0 ) { @@ -662,8 +671,8 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int imcb_log( ic, "The server is going down for maintenance in %s minutes.", arg1 ); } - if( arg1 ) g_free( arg1 ); - if( mtype ) g_free( mtype ); + g_free( arg1 ); + g_free( mtype ); } else if( g_strncasecmp( ct, "text/x-msmsgsprofile", 20 ) == 0 ) { @@ -671,25 +680,30 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int } else if( g_strncasecmp( ct, "text/x-msmsgsinitialemailnotification", 37 ) == 0 ) { - char *inbox = msn_findheader( body, "Inbox-Unread:", blen ); - char *folders = msn_findheader( body, "Folders-Unread:", blen ); - - if( inbox && folders && set_getbool( &ic->acc->set, "mail_notifications" ) ) + if( set_getbool( &ic->acc->set, "mail_notifications" ) ) { - imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); + char *inbox = msn_findheader( body, "Inbox-Unread:", blen ); + char *folders = msn_findheader( body, "Folders-Unread:", blen ); + + if( inbox && folders ) + imcb_log( ic, "INBOX contains %s new messages, plus %s messages in other folders.", inbox, folders ); + + g_free( inbox ); + g_free( folders ); } - - g_free( inbox ); - g_free( folders ); } else if( g_strncasecmp( ct, "text/x-msmsgsemailnotification", 30 ) == 0 ) { - char *from = msn_findheader( body, "From-Addr:", blen ); - char *fromname = msn_findheader( body, "From:", blen ); - - if( from && fromname && set_getbool( &ic->acc->set, "mail_notifications" ) ) + if( set_getbool( &ic->acc->set, "mail_notifications" ) ) { - imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from ); + char *from = msn_findheader( body, "From-Addr:", blen ); + char *fromname = msn_findheader( body, "From:", blen ); + + if( from && fromname ) + imcb_log( ic, "Received an e-mail message from %s <%s>.", fromname, from ); + + g_free( from ); + g_free( fromname ); } } else if( g_strncasecmp( ct, "text/x-msmsgsactivemailnotification", 35 ) == 0 ) diff --git a/protocols/msn/tables.c b/protocols/msn/tables.c index 5ba9ea73..42b12aa9 100644 --- a/protocols/msn/tables.c +++ b/protocols/msn/tables.c @@ -28,48 +28,37 @@ const struct msn_away_state msn_away_state_list[] = { - { 0, "NLN", "Available" }, - { 1, "BSY", "Busy" }, - { 3, "IDL", "Idle" }, - { 5, "BRB", "Be Right Back" }, - { 7, "AWY", "Away" }, - { 9, "PHN", "On the Phone" }, - { 11, "LUN", "Out to Lunch" }, - { 13, "HDN", "Hidden" }, - { -1, "", "" } + { "NLN", "" }, + { "AWY", "Away" }, + { "BSY", "Busy" }, + { "IDL", "Idle" }, + { "BRB", "Be Right Back" }, + { "PHN", "On the Phone" }, + { "LUN", "Out to Lunch" }, + { "HDN", "Hidden" }, + { "", "" } }; -const struct msn_away_state *msn_away_state_by_number( int number ) -{ - int i; - - for( i = 0; msn_away_state_list[i].number > -1; i ++ ) - if( msn_away_state_list[i].number == number ) - return( msn_away_state_list + i ); - - return( NULL ); -} - const struct msn_away_state *msn_away_state_by_code( char *code ) { int i; - for( i = 0; msn_away_state_list[i].number > -1; i ++ ) + for( i = 0; *msn_away_state_list[i].code; i ++ ) if( g_strcasecmp( msn_away_state_list[i].code, code ) == 0 ) return( msn_away_state_list + i ); - return( NULL ); + return NULL; } const struct msn_away_state *msn_away_state_by_name( char *name ) { int i; - for( i = 0; msn_away_state_list[i].number > -1; i ++ ) + for( i = 0; *msn_away_state_list[i].code; i ++ ) if( g_strcasecmp( msn_away_state_list[i].name, name ) == 0 ) return( msn_away_state_list + i ); - return( NULL ); + return NULL; } const struct msn_status_code msn_status_code_list[] = diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 21f7dcb1..c326e378 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2006 Wilmer van der Gaast and others * + * Copyright 2002-2010 Wilmer van der Gaast and others * \********************************************************************/ /* @@ -97,7 +97,19 @@ GList *protocols = NULL; void register_protocol (struct prpl *p) { - protocols = g_list_append(protocols, p); + int i; + gboolean refused = global.conf->protocols != NULL; + + for (i = 0; global.conf->protocols && global.conf->protocols[i]; i++) + { + if (g_strcasecmp(p->name, global.conf->protocols[i]) == 0) + refused = FALSE; + } + + if (refused) + log_message(LOGLVL_WARNING, "Protocol %s disabled\n", p->name); + else + protocols = g_list_append(protocols, p); } struct prpl *find_protocol(const char *name) @@ -267,9 +279,8 @@ void imcb_connected( struct im_connection *ic ) ic->keepalive = b_timeout_add( 60000, send_keepalive, ic ); ic->flags |= OPT_LOGGED_IN; - /* Also necessary when we're not away, at least for some of the - protocols. */ - imc_set_away( ic, u->away ); + /* Necessary to send initial presence status, even if we're not away. */ + imc_away_send_update( ic ); /* Apparently we're connected successfully, so reset the exponential backoff timer. */ @@ -371,7 +382,7 @@ void imcb_ask( struct im_connection *ic, char *msg, void *data, /* list.c */ -void imcb_add_buddy( struct im_connection *ic, char *handle, char *group ) +void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group ) { user_t *u; char nick[MAX_NICK_LENGTH+1], *s; @@ -445,9 +456,10 @@ struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ) return( b ); } -void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) +void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname ) { user_t *u = user_findhandle( ic, handle ); + char *set; if( !u || !realname ) return; @@ -460,9 +472,26 @@ void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ) if( ( ic->flags & OPT_LOGGED_IN ) && set_getbool( &ic->irc->set, "display_namechanges" ) ) imcb_log( ic, "User `%s' changed name to `%s'", u->nick, u->realname ); } + + set = set_getstr( &ic->acc->set, "nick_source" ); + if( strcmp( set, "handle" ) != 0 ) + { + char *name = g_strdup( realname ); + + if( strcmp( set, "first_name" ) == 0 ) + { + int i; + for( i = 0; name[i] && !isspace( name[i] ); i ++ ) {} + name[i] = '\0'; + } + + imcb_buddy_nick_hint( ic, handle, name ); + + g_free( name ); + } } -void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ) +void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group ) { user_t *u; @@ -472,7 +501,7 @@ void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ) /* Mainly meant for ICQ (and now also for Jabber conferences) to allow IM modules to suggest a nickname for a handle. */ -void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) +void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick ) { user_t *u = user_findhandle( ic, handle ); char newnick[MAX_NICK_LENGTH+1], *orig_nick; @@ -617,11 +646,9 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, oa = u->away != NULL; oo = u->online; - if( u->away ) - { - g_free( u->away ); - u->away = NULL; - } + g_free( u->away ); + g_free( u->status_msg ); + u->away = u->status_msg = NULL; if( ( flags & OPT_LOGGED_IN ) && !u->online ) { @@ -659,7 +686,10 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, u->away = g_strdup( "Away" ); } } - /* else waste_any_state_information_for_now(); */ + else + { + u->status_msg = g_strdup( message ); + } /* LISPy... */ if( ( set_getbool( &ic->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ @@ -684,7 +714,7 @@ void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, } } -void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at ) +void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at ) { irc_t *irc = ic->irc; char *wrapped; @@ -817,7 +847,7 @@ void imcb_chat_free( struct groupchat *c ) } } -void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ) +void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at ) { struct im_connection *ic = c->ic; char *wrapped; @@ -889,7 +919,7 @@ void imcb_chat_topic( struct groupchat *c, char *who, char *topic, time_t set_at /* buddy_chat.c */ -void imcb_chat_add_buddy( struct groupchat *b, char *handle ) +void imcb_chat_add_buddy( struct groupchat *b, const char *handle ) { user_t *u = user_findhandle( b->ic, handle ); int me = 0; @@ -924,7 +954,7 @@ void imcb_chat_add_buddy( struct groupchat *b, char *handle ) } /* This function is one BIG hack... :-( EREWRITE */ -void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ) +void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason ) { user_t *u; int me = 0; @@ -1069,51 +1099,30 @@ int imc_chat_msg( struct groupchat *c, char *msg, int flags ) return 1; } -static char *imc_away_alias_find( GList *gcm, char *away ); +static char *imc_away_state_find( GList *gcm, char *away, char **message ); -int imc_set_away( struct im_connection *ic, char *away ) +int imc_away_send_update( struct im_connection *ic ) { - GList *m, *ms; - char *s; - - if( !away ) away = ""; - ms = m = ic->acc->prpl->away_states( ic ); + char *away, *msg = NULL; - while( m ) + away = set_getstr( &ic->acc->set, "away" ) ? + : set_getstr( &ic->irc->set, "away" ); + if( away && *away ) { - if( *away ) - { - if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 ) - break; - } - else - { - if( g_strcasecmp( m->data, "Available" ) == 0 ) - break; - if( g_strcasecmp( m->data, "Online" ) == 0 ) - break; - } - m = m->next; - } - - if( m ) - { - ic->acc->prpl->set_away( ic, m->data, *away ? away : NULL ); + GList *m = ic->acc->prpl->away_states( ic ); + msg = ic->acc->flags & ACC_FLAG_AWAY_MESSAGE ? away : NULL; + away = imc_away_state_find( m, away, &msg ) ? : m->data; } - else + else if( ic->acc->flags & ACC_FLAG_STATUS_MESSAGE ) { - s = imc_away_alias_find( ms, away ); - if( s ) - { - ic->acc->prpl->set_away( ic, s, away ); - if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "Setting away state to %s", s ); - } - else - ic->acc->prpl->set_away( ic, GAIM_AWAY_CUSTOM, away ); + away = NULL; + msg = set_getstr( &ic->acc->set, "status" ) ? + : set_getstr( &ic->irc->set, "status" ); } - return( 1 ); + ic->acc->prpl->set_away( ic, away, msg ); + + return 1; } static char *imc_away_alias_list[8][5] = @@ -1128,16 +1137,33 @@ static char *imc_away_alias_list[8][5] = { NULL } }; -static char *imc_away_alias_find( GList *gcm, char *away ) +static char *imc_away_state_find( GList *gcm, char *away, char **message ) { GList *m; int i, j; + for( m = gcm; m; m = m->next ) + if( g_strncasecmp( m->data, away, strlen( m->data ) ) == 0 ) + { + /* At least the Yahoo! module works better if message + contains no data unless it adds something to what + we have in state already. */ + if( strlen( m->data ) == strlen( away ) ) + *message = NULL; + + return m->data; + } + for( i = 0; *imc_away_alias_list[i]; i ++ ) { + int keep_message; + for( j = 0; imc_away_alias_list[i][j]; j ++ ) if( g_strncasecmp( away, imc_away_alias_list[i][j], strlen( imc_away_alias_list[i][j] ) ) == 0 ) + { + keep_message = strlen( away ) != strlen( imc_away_alias_list[i][j] ); break; + } if( !imc_away_alias_list[i][j] ) /* If we reach the end, this row */ continue; /* is not what we want. Next! */ @@ -1145,17 +1171,22 @@ static char *imc_away_alias_find( GList *gcm, char *away ) /* Now find an entry in this row which exists in gcm */ for( j = 0; imc_away_alias_list[i][j]; j ++ ) { - m = gcm; - while( m ) - { + for( m = gcm; m; m = m->next ) if( g_strcasecmp( imc_away_alias_list[i][j], m->data ) == 0 ) - return( imc_away_alias_list[i][j] ); - m = m->next; - } + { + if( !keep_message ) + *message = NULL; + + return imc_away_alias_list[i][j]; + } } + + /* No need to look further, apparently this state doesn't + have any good alias for this protocol. */ + break; } - return( NULL ); + return NULL; } void imc_add_allow( struct im_connection *ic, char *handle ) diff --git a/protocols/nogaim.h b/protocols/nogaim.h index dc6154e2..a523a3a5 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -48,7 +48,6 @@ #define BUDDY_ALIAS_MAXLEN 388 /* because MSN names can be 387 characters */ #define WEBSITE "http://www.bitlbee.org/" -#define GAIM_AWAY_CUSTOM "Custom" /* Sharing flags between all kinds of things. I just hope I won't hit any limits before 32-bit machines become extinct. ;-) */ @@ -217,8 +216,8 @@ struct prpl { void (* chat_topic) (struct groupchat *, char *topic); /* You can tell what away states your protocol supports, so that - * BitlBee will try to map the IRC away reasons to them, or use - * GAIM_AWAY_CUSTOM when calling skype_set_away(). */ + * BitlBee will try to map the IRC away reasons to them. If your + * protocol doesn't have any, just return one generic "Away". */ GList *(* away_states)(struct im_connection *ic); /* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* @@ -275,11 +274,11 @@ G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, const char *handle, /* This function should be called for each handle which are visible to the * user, usually after a login, or if the user added a buddy and the IM * server confirms that the add was successful. Don't forget to do this! */ -G_MODULE_EXPORT void imcb_add_buddy( struct im_connection *ic, char *handle, char *group ); -G_MODULE_EXPORT void imcb_remove_buddy( struct im_connection *ic, char *handle, char *group ); +G_MODULE_EXPORT void imcb_add_buddy( struct im_connection *ic, const char *handle, const char *group ); +G_MODULE_EXPORT void imcb_remove_buddy( struct im_connection *ic, const char *handle, char *group ); G_MODULE_EXPORT struct buddy *imcb_find_buddy( struct im_connection *ic, char *handle ); -G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, char *handle, char *realname ); -G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ); +G_MODULE_EXPORT void imcb_rename_buddy( struct im_connection *ic, const char *handle, const char *realname ); +G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, const char *handle, const char *nick ); /* Buddy activity */ /* To manipulate the status of a handle. @@ -289,7 +288,7 @@ G_MODULE_EXPORT void imcb_buddy_nick_hint( struct im_connection *ic, char *handl G_MODULE_EXPORT void imcb_buddy_status( struct im_connection *ic, const char *handle, int flags, const char *state, const char *message ); /* Not implemented yet! */ G_MODULE_EXPORT void imcb_buddy_times( struct im_connection *ic, const char *handle, time_t login, time_t idle ); /* Call when a handle says something. 'flags' and 'sent_at may be just 0. */ -G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, char *handle, char *msg, uint32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_buddy_msg( struct im_connection *ic, const char *handle, char *msg, uint32_t flags, time_t sent_at ); G_MODULE_EXPORT void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ); G_MODULE_EXPORT void imcb_clean_handle( struct im_connection *ic, char *handle ); @@ -302,11 +301,11 @@ G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, * the user her/himself. At that point the group chat will be visible to the * user, too. */ G_MODULE_EXPORT struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle ); -G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, char *handle ); +G_MODULE_EXPORT void imcb_chat_add_buddy( struct groupchat *b, const char *handle ); /* To remove a handle from a group chat. Reason can be NULL. */ -G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, char *handle, char *reason ); +G_MODULE_EXPORT void imcb_chat_remove_buddy( struct groupchat *b, const char *handle, const char *reason ); /* To tell BitlBee 'who' said 'msg' in 'c'. 'flags' and 'sent_at' can be 0. */ -G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, char *who, char *msg, uint32_t flags, time_t sent_at ); +G_MODULE_EXPORT void imcb_chat_msg( struct groupchat *c, const char *who, char *msg, uint32_t flags, time_t sent_at ); /* System messages specific to a groupchat, so they can be displayed in the right context. */ G_MODULE_EXPORT void imcb_chat_log( struct groupchat *c, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); /* To tell BitlBee 'who' changed the topic of 'c' to 'topic'. */ @@ -314,7 +313,7 @@ G_MODULE_EXPORT void imcb_chat_topic( struct groupchat *c, char *who, char *topi G_MODULE_EXPORT void imcb_chat_free( struct groupchat *c ); /* Actions, or whatever. */ -int imc_set_away( struct im_connection *ic, char *away ); +int imc_away_send_update( struct im_connection *ic ); int imc_buddy_msg( struct im_connection *ic, char *handle, char *msg, int flags ); int imc_chat_msg( struct groupchat *c, char *msg, int flags ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 1118c26d..f0e65f9a 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -379,6 +379,8 @@ static void oscar_init(account_t *acc) s = set_add( &acc->set, "web_aware", "false", set_eval_bool, acc ); s->flags |= ACC_SET_OFFLINE_ONLY; } + + acc->flags |= ACC_FLAG_AWAY_MESSAGE; } static void oscar_login(account_t *acc) { @@ -1951,6 +1953,8 @@ static void oscar_get_away(struct im_connection *g, char *who) { static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message) { + if (state == NULL) + state = ""; if (!g_strcasecmp(state, _("Visible"))) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); @@ -1958,7 +1962,9 @@ static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, } else if (!g_strcasecmp(state, _("Invisible"))) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE); return; - } /* else... */ + } else if (message == NULL) { + message = state; + } if (od->rights.maxawaymsglen == 0) imcb_error(ic, "oscar_set_away_aim called before locate rights received"); @@ -2001,7 +2007,7 @@ static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, no_message = TRUE; } - if (!g_strcasecmp(state, "Online")) { + if (state == NULL) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else if (!g_strcasecmp(state, "Away")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); @@ -2026,7 +2032,7 @@ static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, } else if (!g_strcasecmp(state, "Invisible")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE); ic->away = g_strdup(msg); - } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) { + } else { if (no_message) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else { @@ -2275,20 +2281,21 @@ static void oscar_rem_deny(struct im_connection *ic, char *who) { static GList *oscar_away_states(struct im_connection *ic) { struct oscar_data *od = ic->proto_data; - GList *m = NULL; - - if (!od->icq) - return g_list_append(m, GAIM_AWAY_CUSTOM); - m = g_list_append(m, "Online"); - m = g_list_append(m, "Away"); - m = g_list_append(m, "Do Not Disturb"); - m = g_list_append(m, "Not Available"); - m = g_list_append(m, "Occupied"); - m = g_list_append(m, "Free For Chat"); - m = g_list_append(m, "Invisible"); - - return m; + if (od->icq) { + static GList *m = NULL; + m = g_list_append(m, "Away"); + m = g_list_append(m, "Do Not Disturb"); + m = g_list_append(m, "Not Available"); + m = g_list_append(m, "Occupied"); + m = g_list_append(m, "Free For Chat"); + m = g_list_append(m, "Invisible"); + return m; + } else { + static GList *m = NULL; + m = g_list_append(m, "Away"); + return m; + } } static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index a1755cc9..1bfc2e59 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -854,55 +854,6 @@ static int is_same_bud(const void * a, const void * b) { return strcmp(subject->id, object->id); } -static YList * bud_str2list(char *rawlist) -{ - YList * l = NULL; - - char **lines; - char **split; - char **buddies; - char **tmp, **bud; - - lines = y_strsplit(rawlist, "\n", -1); - for (tmp = lines; *tmp; tmp++) { - struct yahoo_buddy *newbud; - - split = y_strsplit(*tmp, ":", 2); - if (!split) - continue; - if (!split[0] || !split[1]) { - y_strfreev(split); - continue; - } - buddies = y_strsplit(split[1], ",", -1); - - for (bud = buddies; bud && *bud; bud++) { - newbud = y_new0(struct yahoo_buddy, 1); - newbud->id = strdup(*bud); - newbud->group = strdup(split[0]); - - if(y_list_find_custom(l, newbud, is_same_bud)) { - FREE(newbud->id); - FREE(newbud->group); - FREE(newbud); - continue; - } - - newbud->real_name = NULL; - - l = y_list_append(l, newbud); - - NOTICE(("Added buddy %s to group %s", newbud->id, newbud->group)); - } - - y_strfreev(buddies); - y_strfreev(split); - } - y_strfreev(lines); - - return l; -} - static char * getcookie(char *rawcookie) { char * cookie=NULL; @@ -1359,140 +1310,154 @@ static void yahoo_process_message(struct yahoo_input_data *yid, struct yahoo_pac y_list_free(messages); } - -static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +static void yahoo_process_status(struct yahoo_input_data *yid, + struct yahoo_packet *pkt) { YList *l; struct yahoo_data *yd = yid->yd; - struct user - { - char *name; /* 7 name */ - int state; /* 10 state */ - int flags; /* 13 flags, bit 0 = pager, bit 1 = chat, bit 2 = game */ - int mobile; /* 60 mobile */ - char *msg; /* 19 custom status message */ - int away; /* 47 away (or invisible)*/ - int buddy_session; /* 11 state */ - int f17; /* 17 in chat? then what about flags? */ - int idle; /* 137 seconds idle */ - int f138; /* 138 state */ - char *f184; /* 184 state */ - int f192; /* 192 state */ - int f10001; /* 10001 state */ - int f10002; /* 10002 state */ - int f198; /* 198 state */ - char *f197; /* 197 state */ - char *f205; /* 205 state */ - int f213; /* 213 state */ - } *u; + struct yahoo_process_status_entry *u; YList *users = 0; - + if (pkt->service == YAHOO_SERVICE_LOGOFF && pkt->status == -1) { - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_DUPL, NULL); + YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id, + YAHOO_LOGIN_DUPL, NULL); return; } + /* Status updates may be spread accross multiple packets and not + even on buddy boundaries, so keeping some state is important. + So, continue where we left off, and only add a user entry to + the list once it's complete (301-315 End buddy). */ + u = yd->half_user; + for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; switch (pair->key) { - case 0: /* we won't actually do anything with this */ + case 300: /* Begin buddy */ + if (!strcmp(pair->value, "315") && !u) { + u = yd->half_user = y_new0(struct yahoo_process_status_entry, 1); + } + break; + case 301: /* End buddy */ + if (!strcmp(pair->value, "315") && u) { + /* Sometimes user info comes in an odd format with no + "begin buddy" but *with* an "end buddy". Don't add + it twice. */ + if (!y_list_find(users, u)) + users = y_list_prepend(users, u); + u = yd->half_user = NULL; + } + break; + case 0: /* we won't actually do anything with this */ NOTICE(("key %d:%s", pair->key, pair->value)); break; - case 1: /* we don't get the full buddy list here. */ + case 1: /* we don't get the full buddy list here. */ if (!yd->logged_in) { - yd->logged_in = TRUE; - if(yd->current_status < 0) + yd->logged_in = 1; + if (yd->current_status < 0) yd->current_status = yd->initial_status; - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL); + YAHOO_CALLBACK(ext_yahoo_login_response) (yd-> + client_id, YAHOO_LOGIN_OK, NULL); } break; - case 8: /* how many online buddies we have */ + case 8: /* how many online buddies we have */ NOTICE(("key %d:%s", pair->key, pair->value)); break; - case 7: /* the current buddy */ - u = y_new0(struct user, 1); + case 7: /* the current buddy */ + if (!u) { + /* This will only happen in case of a single level message */ + u = y_new0(struct yahoo_process_status_entry, 1); + users = y_list_prepend(users, u); + } u->name = pair->value; - users = y_list_prepend(users, u); break; - case 10: /* state */ - ((struct user*)users->data)->state = strtol(pair->value, NULL, 10); + case 10: /* state */ + u->state = strtol(pair->value, NULL, 10); break; - case 19: /* custom status message */ - ((struct user*)users->data)->msg = pair->value; + case 19: /* custom status message */ + u->msg = pair->value; break; - case 47: /* is it an away message or not */ - ((struct user*)users->data)->away = atoi(pair->value); + case 47: /* is it an away message or not. Not applicable for YMSG16 anymore */ + u->away = atoi(pair->value); break; - case 137: /* seconds idle */ - ((struct user*)users->data)->idle = atoi(pair->value); + case 137: /* seconds idle */ + u->idle = atoi(pair->value); break; - case 11: /* this is the buddy's session id */ - ((struct user*)users->data)->buddy_session = atoi(pair->value); + case 11: /* this is the buddy's session id */ + u->buddy_session = atoi(pair->value); break; - case 17: /* in chat? */ - ((struct user*)users->data)->f17 = atoi(pair->value); + case 17: /* in chat? */ + u->f17 = atoi(pair->value); break; - case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ - ((struct user*)users->data)->flags = atoi(pair->value); + case 13: /* bitmask, bit 0 = pager, bit 1 = chat, bit 2 = game */ + u->flags = atoi(pair->value); break; - case 60: /* SMS -> 1 MOBILE USER */ + case 60: /* SMS -> 1 MOBILE USER */ /* sometimes going offline makes this 2, but invisible never sends it */ - ((struct user*)users->data)->mobile = atoi(pair->value); + u->mobile = atoi(pair->value); break; case 138: - ((struct user*)users->data)->f138 = atoi(pair->value); + u->f138 = atoi(pair->value); break; case 184: - ((struct user*)users->data)->f184 = pair->value; + u->f184 = pair->value; break; case 192: - ((struct user*)users->data)->f192 = atoi(pair->value); + u->f192 = atoi(pair->value); break; case 10001: - ((struct user*)users->data)->f10001 = atoi(pair->value); + u->f10001 = atoi(pair->value); break; case 10002: - ((struct user*)users->data)->f10002 = atoi(pair->value); + u->f10002 = atoi(pair->value); break; case 198: - ((struct user*)users->data)->f198 = atoi(pair->value); + u->f198 = atoi(pair->value); break; case 197: - ((struct user*)users->data)->f197 = pair->value; + u->f197 = pair->value; break; case 205: - ((struct user*)users->data)->f205 = pair->value; + u->f205 = pair->value; break; case 213: - ((struct user*)users->data)->f213 = atoi(pair->value); + u->f213 = atoi(pair->value); break; - case 16: /* Custom error message */ - YAHOO_CALLBACK(ext_yahoo_error)(yd->client_id, pair->value, 0, E_CUSTOM); + case 16: /* Custom error message */ + YAHOO_CALLBACK(ext_yahoo_error) (yd->client_id, + pair->value, 0, E_CUSTOM); break; default: - WARNING(("unknown status key %d:%s", pair->key, pair->value)); + WARNING(("unknown status key %d:%s", pair->key, + pair->value)); break; } } - + while (users) { YList *t = users; - struct user *u = users->data; + struct yahoo_process_status_entry *u = users->data; if (u->name != NULL) { - if (pkt->service == YAHOO_SERVICE_LOGOFF) { /* || u->flags == 0) { Not in YMSG16 */ - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0); + if (pkt->service == + YAHOO_SERVICE_LOGOFF + /*|| u->flags == 0 No flags for YMSG16 */ ) { + YAHOO_CALLBACK(ext_yahoo_status_changed) (yd-> + client_id, u->name, + YAHOO_STATUS_OFFLINE, NULL, 1, 0, 0); } else { /* Key 47 always seems to be 1 for YMSG16 */ - if(!u->state) + if (!u->state) u->away = 0; else u->away = 1; - YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, u->name, u->state, u->msg, u->away, u->idle, u->mobile); + YAHOO_CALLBACK(ext_yahoo_status_changed) (yd-> + client_id, u->name, u->state, u->msg, + u->away, u->idle, u->mobile); } } @@ -1502,7 +1467,8 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack } } -static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +static void yahoo_process_buddy_list(struct yahoo_input_data *yid, + struct yahoo_packet *pkt) { struct yahoo_data *yd = yid->yd; YList *l; @@ -1514,134 +1480,117 @@ static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_ for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; - switch(pair->key) { + switch (pair->key) { case 300: case 301: case 302: + break; /* Separators. Our logic does not need them */ case 303: - if ( 315 == atoi(pair->value) ) + if (318 == atoi(pair->value)) last_packet = 1; break; case 65: - g_free(cur_group); cur_group = strdup(pair->value); break; case 7: newbud = y_new0(struct yahoo_buddy, 1); newbud->id = strdup(pair->value); - if(cur_group) + if (cur_group) newbud->group = strdup(cur_group); - else { - struct yahoo_buddy *lastbud = (struct yahoo_buddy *)y_list_nth( - yd->buddies, y_list_length(yd->buddies)-1)->data; + else if (yd->buddies) { + struct yahoo_buddy *lastbud = + (struct yahoo_buddy *)y_list_nth(yd-> + buddies, + y_list_length(yd->buddies) - 1)->data; newbud->group = strdup(lastbud->group); - } + } else + newbud->group = strdup("Buddies"); yd->buddies = y_list_append(yd->buddies, newbud); break; } } - - g_free(cur_group); /* we could be getting multiple packets here */ - if (last_packet) + if (pkt->hash && !last_packet) return; - YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies); + YAHOO_CALLBACK(ext_yahoo_got_buddies) (yd->client_id, yd->buddies); - /*** We login at the very end of the packet communication */ + /* Logged in */ if (!yd->logged_in) { - yd->logged_in = TRUE; - if(yd->current_status < 0) + yd->logged_in = 1; + if (yd->current_status < 0) yd->current_status = yd->initial_status; - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL); + YAHOO_CALLBACK(ext_yahoo_login_response) (yd->client_id, + YAHOO_LOGIN_OK, NULL); + + /* + yahoo_set_away(yd->client_id, yd->initial_status, NULL, + (yd->initial_status == YAHOO_STATUS_AVAILABLE) ? 0 : 1); + + yahoo_get_yab(yd->client_id); + */ } + } -static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +static void yahoo_process_list(struct yahoo_input_data *yid, + struct yahoo_packet *pkt) { struct yahoo_data *yd = yid->yd; YList *l; - if (!yd->logged_in) { - yd->logged_in = TRUE; - if(yd->current_status < 0) - yd->current_status = yd->initial_status; - YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, YAHOO_LOGIN_OK, NULL); - } - + /* we could be getting multiple packets here */ for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; - switch(pair->key) { - case 87: /* buddies */ - if(!yd->rawbuddylist) - yd->rawbuddylist = strdup(pair->value); - else { - yd->rawbuddylist = y_string_append(yd->rawbuddylist, pair->value); - } - break; - - case 88: /* ignore list */ - if(!yd->ignorelist) - yd->ignorelist = strdup("Ignore:"); - yd->ignorelist = y_string_append(yd->ignorelist, pair->value); - break; - - case 89: /* identities */ + switch (pair->key) { + case 89: /* identities */ { - char **identities = y_strsplit(pair->value, ",", -1); - int i; - for(i=0; identities[i]; i++) - yd->identities = y_list_append(yd->identities, + char **identities = + y_strsplit(pair->value, ",", -1); + int i; + for (i = 0; identities[i]; i++) + yd->identities = + y_list_append(yd->identities, strdup(identities[i])); - y_strfreev(identities); + y_strfreev(identities); } - YAHOO_CALLBACK(ext_yahoo_got_identities)(yd->client_id, yd->identities); + YAHOO_CALLBACK(ext_yahoo_got_identities) (yd->client_id, + yd->identities); break; - case 59: /* cookies */ - if(yd->ignorelist) { - yd->ignore = bud_str2list(yd->ignorelist); - FREE(yd->ignorelist); - YAHOO_CALLBACK(ext_yahoo_got_ignore)(yd->client_id, yd->ignore); - } - if(yd->rawbuddylist) { - yd->buddies = bud_str2list(yd->rawbuddylist); - FREE(yd->rawbuddylist); - YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies); - } - - if(pair->value[0]=='Y') { + case 59: /* cookies */ + if (pair->value[0] == 'Y') { FREE(yd->cookie_y); FREE(yd->login_cookie); yd->cookie_y = getcookie(pair->value); yd->login_cookie = getlcookie(yd->cookie_y); - } else if(pair->value[0]=='T') { + } else if (pair->value[0] == 'T') { FREE(yd->cookie_t); yd->cookie_t = getcookie(pair->value); - } else if(pair->value[0]=='C') { + } else if (pair->value[0] == 'C') { FREE(yd->cookie_c); yd->cookie_c = getcookie(pair->value); - } - - if(yd->cookie_y && yd->cookie_t) - YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id); + } break; - case 3: /* my id */ - case 90: /* 1 */ - case 100: /* 0 */ - case 101: /* NULL */ - case 102: /* NULL */ - case 93: /* 86400/1440 */ + case 3: /* my id */ + case 90: /* 1 */ + case 100: /* 0 */ + case 101: /* NULL */ + case 102: /* NULL */ + case 93: /* 86400/1440 */ break; } } + + if (yd->cookie_y && yd->cookie_t) /* We don't get cookie_c anymore */ + YAHOO_CALLBACK(ext_yahoo_got_cookies) (yd->client_id); } static void yahoo_process_verify(struct yahoo_input_data *yid, struct yahoo_packet *pkt) @@ -2392,10 +2341,16 @@ static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had) static void yahoo_https_auth_token_finish(struct http_request *req) { struct yahoo_https_auth_data *had = req->data; - struct yahoo_input_data *yid = had->yid; - struct yahoo_data *yd = yid->yd; + struct yahoo_input_data *yid; + struct yahoo_data *yd; int st; + if (y_list_find(inputs, had->yid) == NULL) + return; + + yid = had->yid; + yd = yid->yd; + if (req->status_code != 200) { YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL); goto fail; @@ -2435,12 +2390,18 @@ static void yahoo_https_auth_init(struct yahoo_https_auth_data *had) static void yahoo_https_auth_finish(struct http_request *req) { struct yahoo_https_auth_data *had = req->data; - struct yahoo_input_data *yid = had->yid; - struct yahoo_data *yd = yid->yd; + struct yahoo_input_data *yid; + struct yahoo_data *yd; struct yahoo_packet *pack; - char *crumb; + char *crumb = NULL; int st; + if (y_list_find(inputs, had->yid) == NULL) + return; + + yid = had->yid; + yd = yid->yd; + md5_byte_t result[16]; md5_state_t ctx; @@ -4079,14 +4040,8 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away) return; yd = yid->yd; - old_status = yd->current_status; - - if (msg && strncmp(msg,"Invisible",9)) { - yd->current_status = YAHOO_STATUS_CUSTOM; - } else { - yd->current_status = state; - } + yd->current_status = state; /* Thank you libpurple :) */ if (yd->current_status == YAHOO_STATUS_INVISIBLE) { @@ -4101,15 +4056,8 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away) pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_STATUS_UPDATE, yd->current_status, yd->session_id); snprintf(s, sizeof(s), "%d", yd->current_status); yahoo_packet_hash(pkt, 10, s); - - if (yd->current_status == YAHOO_STATUS_CUSTOM) { - yahoo_packet_hash(pkt, 19, msg); - } else { - yahoo_packet_hash(pkt, 19, ""); - } - + yahoo_packet_hash(pkt, 19, msg && state == YAHOO_STATUS_CUSTOM ? msg : ""); yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); - yahoo_send_packet(yid, pkt, 0); yahoo_packet_free(pkt); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index ac57d4b6..b61f6ff9 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -129,6 +129,8 @@ static char *byahoo_strip( const char *in ) static void byahoo_init( account_t *acc ) { set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc ); + + acc->flags |= ACC_FLAG_AWAY_MESSAGE | ACC_FLAG_STATUS_MESSAGE; } static void byahoo_login( account_t *acc ) @@ -196,29 +198,12 @@ static int byahoo_send_typing( struct im_connection *ic, char *who, int typing ) static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) { struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; - char *away; - - away = NULL; - if( state && msg && g_strcasecmp( state, msg ) != 0 ) + if( state && msg == NULL ) { - yd->current_status = YAHOO_STATUS_CUSTOM; - away = ""; - } - else if( state ) - { - /* Set msg to NULL since (if it isn't NULL already) it's equal - to state. msg must be empty if we want to use an existing - away state. */ - msg = NULL; - - away = ""; - if( g_strcasecmp( state, "Available" ) == 0 ) - { - yd->current_status = YAHOO_STATUS_AVAILABLE; - away = NULL; - } - else if( g_strcasecmp( state, "Be Right Back" ) == 0 ) + /* Use these states only if msg doesn't contain additional + info since away messages are only supported with CUSTOM. */ + if( g_strcasecmp( state, "Be Right Back" ) == 0 ) yd->current_status = YAHOO_STATUS_BRB; else if( g_strcasecmp( state, "Busy" ) == 0 ) yd->current_status = YAHOO_STATUS_BUSY; @@ -238,17 +223,15 @@ static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) yd->current_status = YAHOO_STATUS_STEPPEDOUT; else if( g_strcasecmp( state, "Invisible" ) == 0 ) yd->current_status = YAHOO_STATUS_INVISIBLE; - else if( g_strcasecmp( state, GAIM_AWAY_CUSTOM ) == 0 ) - { - yd->current_status = YAHOO_STATUS_AVAILABLE; - - away = NULL; - } + else + yd->current_status = YAHOO_STATUS_CUSTOM; } + else if( msg ) + yd->current_status = YAHOO_STATUS_CUSTOM; else yd->current_status = YAHOO_STATUS_AVAILABLE; - yahoo_set_away( yd->y2_id, yd->current_status, msg, away != NULL ? 2 : 0 ); + yahoo_set_away( yd->y2_id, yd->current_status, msg, state ? 2 : 0 ); } static GList *byahoo_away_states( struct im_connection *ic ) @@ -257,7 +240,6 @@ static GList *byahoo_away_states( struct im_connection *ic ) if( m == NULL ) { - m = g_list_append( m, "Available" ); m = g_list_append( m, "Be Right Back" ); m = g_list_append( m, "Busy" ); m = g_list_append( m, "Not At Home" ); @@ -268,7 +250,6 @@ static GList *byahoo_away_states( struct im_connection *ic ) m = g_list_append( m, "Out To Lunch" ); m = g_list_append( m, "Stepped Out" ); m = g_list_append( m, "Invisible" ); - m = g_list_append( m, GAIM_AWAY_CUSTOM ); } return m; diff --git a/protocols/yahoo/yahoo2_types.h b/protocols/yahoo/yahoo2_types.h index 3507e13a..f05acb3c 100644 --- a/protocols/yahoo/yahoo2_types.h +++ b/protocols/yahoo/yahoo2_types.h @@ -195,6 +195,8 @@ struct yahoo_data { char *ignorelist; void *server_settings; + + struct yahoo_process_status_entry *half_user; }; struct yab { @@ -260,6 +262,27 @@ struct yahoo_chat_member { char *location; }; +struct yahoo_process_status_entry { + char *name; /* 7 name */ + int state; /* 10 state */ + int flags; /* 13 flags, bit 0 = pager, bit 1 = chat, bit 2 = game */ + int mobile; /* 60 mobile */ + char *msg; /* 19 custom status message */ + int away; /* 47 away (or invisible) */ + int buddy_session; /* 11 state */ + int f17; /* 17 in chat? then what about flags? */ + int idle; /* 137 seconds idle */ + int f138; /* 138 state */ + char *f184; /* 184 state */ + int f192; /* 192 state */ + int f10001; /* 10001 state */ + int f10002; /* 10002 state */ + int f198; /* 198 state */ + char *f197; /* 197 state */ + char *f205; /* 205 state */ + int f213; /* 213 state */ +}; + #ifdef __cplusplus } #endif |