From ad9feec0895ea0b9acf1be3f24c9a2d5c8cc9782 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 30 Aug 2008 19:59:58 +0100 Subject: Added chat.c to keep track of chatrooms the user cares about. --- Makefile | 2 +- bitlbee.h | 1 + chat.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ chat.h | 42 +++++++++++++++++++++++++ irc.h | 6 +--- 5 files changed, 150 insertions(+), 6 deletions(-) create mode 100644 chat.c create mode 100644 chat.h diff --git a/Makefile b/Makefile index bae2e770..20feb067 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ -include Makefile.settings # Program variables -objects = account.o bitlbee.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o +objects = account.o bitlbee.o chat.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h subdirs = lib protocols diff --git a/bitlbee.h b/bitlbee.h index c203d18e..31caab9f 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -128,6 +128,7 @@ #include "commands.h" #include "account.h" #include "nick.h" +#include "chat.h" #include "conf.h" #include "log.h" #include "ini.h" diff --git a/chat.c b/chat.c new file mode 100644 index 00000000..b4b87117 --- /dev/null +++ b/chat.c @@ -0,0 +1,105 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2008 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Keep track of chatrooms the user is interested in */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "bitlbee.h" + +struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) +{ + struct chat *c, *l; + + if( !chat_chanok( channel ) ) + return NULL; + + for( c = irc->chatrooms; c; c = c->next ) + { + if( chat_chancmp( channel, c->channel ) == 0 ) + return NULL; + + if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 ) + return NULL; + + l = c; + } + + if( irc->chatrooms == NULL ) + irc->chatrooms = c = g_new0( struct chat, 1 ); + else + l->next = c = g_new0( struct chat, 1 ); + + c->acc = acc; + c->handle = g_strdup( handle ); + c->channel = g_strdup( channel ); + + set_add( &c->set, "auto_join", "false", set_eval_bool, c ); + set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); + set_add( &c->set, "nick", NULL, NULL, c ); + + return c; +} + +struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle ) +{ + struct chat *c; + + for( c = irc->chatrooms; c; c = c->next ) + { + if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 ) + break; + } + + return c; +} + +struct chat *chat_bychannel( irc_t *irc, char *channel ) +{ + struct chat *c; + + for( c = irc->chatrooms; c; c = c->next ) + { + if( chat_chancmp( channel, c->channel ) == 0 ) + break; + } + + return c; +} + +int chat_chancmp( char *a, char *b ) +{ + if( !chat_chanok( a ) || !chat_chanok( b ) ) + return 0; + + if( a[0] == b[0] ) + return nick_cmp( a + 1, b + 1 ); + else + return -1; +} + +int chat_chanok( char *a ) +{ + if( strchr( "&#", a[0] ) != NULL ) + return nick_ok( a + 1 ); + else + return 0; +} diff --git a/chat.h b/chat.h new file mode 100644 index 00000000..6dbe5228 --- /dev/null +++ b/chat.h @@ -0,0 +1,42 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2008 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Keep track of chatrooms the user is interested in */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +struct chat +{ + account_t *acc; + + char *handle; + char *channel; + set_t *set; + + struct chat *next; +}; + +struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ); +struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle ); +struct chat *chat_bychannel( irc_t *irc, char *channel ); + +int chat_chancmp( char *a, char *b ); +int chat_chanok( char *a ); diff --git a/irc.h b/irc.h index b8c52925..e341b2da 100644 --- a/irc.h +++ b/irc.h @@ -47,11 +47,6 @@ typedef enum USTATUS_SHUTDOWN = 8 } irc_status_t; -typedef struct channel -{ - char *name; -} channel_t; - typedef struct irc { int fd; @@ -86,6 +81,7 @@ typedef struct irc struct query *queries; struct account *accounts; + struct chat *chatrooms; struct __USER *users; GHashTable *userhash; -- cgit v1.2.3 From 1917a1ec17dde7c159af5ec65d6455c3348bb250 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 30 Aug 2008 20:43:38 +0100 Subject: Added support for loading chatroom data from user .xml files. --- storage_xml.c | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index 8b205c5a..d8c5ffb7 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -28,7 +28,6 @@ #include "base64.h" #include "arc.h" #include "md5.h" -#include #if GLIB_CHECK_VERSION(2,8,0) #include @@ -54,6 +53,8 @@ struct xml_parsedata irc_t *irc; char *current_setting; account_t *current_account; + struct chat *current_chat; + set_t **current_set_head; char *given_nick; char *given_pass; xml_pass_st pass_st; @@ -172,7 +173,16 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) + { + if( xd->current_chat != NULL ) + xd->current_set_head = &xd->current_chat->set; + else if( xd->current_account != NULL ) + xd->current_set_head = &xd->current_account->set; + else + xd->current_set_head = &xd->irc->set; + xd->current_setting = g_strdup( setting ); + } else g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Missing attributes for %s element", element_name ); @@ -194,6 +204,23 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na "Missing attributes for %s element", element_name ); } } + else if( g_strcasecmp( element_name, "chat" ) == 0 ) + { + char *handle, *channel; + + handle = xml_attr( attr_names, attr_values, "handle" ); + channel = xml_attr( attr_names, attr_values, "channel" ); + + if( xd->current_account && handle && channel ) + { + xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel ); + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + } + } else { g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, @@ -214,13 +241,16 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name { xd->current_account = NULL; } + else if( g_strcasecmp( element_name, "chat" ) == 0 ) + { + xd->current_chat = NULL; + } } static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize text_len, gpointer data, GError **error ) { char text[text_len+1]; struct xml_parsedata *xd = data; - irc_t *irc = xd->irc; strncpy( text, text_orig, text_len ); text[text_len] = 0; @@ -233,8 +263,7 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize te } else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting ) { - set_setstr( xd->current_account ? &xd->current_account->set : &irc->set, - xd->current_setting, (char*) text ); + set_setstr( xd->current_set_head, xd->current_setting, (char*) text ); g_free( xd->current_setting ); xd->current_setting = NULL; } -- cgit v1.2.3 From b84800d89604dee6fd837a2b8ab549346607e774 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 30 Aug 2008 22:30:13 +0100 Subject: Support for saving the chatroom list. Also removed the hack that was used to not save non-existent settings now that those simply aren't possible anymore. --- storage_xml.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index d8c5ffb7..240bb589 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -437,7 +437,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) g_free( pass_buf ); for( set = irc->set; set; set = set->next ) - if( set->value && set->def ) + if( set->value ) if( !xml_printf( fd, 1, "%s\n", set->key, set->value ) ) goto write_error; @@ -446,6 +446,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) unsigned char *pass_cr; char *pass_b64; int pass_len; + struct chat *c; pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password, 12 ); pass_b64 = base64_encode( pass_cr, pass_len ); @@ -464,7 +465,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) goto write_error; for( set = acc->set; set; set = set->next ) - if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) ) + if( set->value && !( set->flags & ACC_SET_NOSAVE ) ) if( !xml_printf( fd, 2, "%s\n", set->key, set->value ) ) goto write_error; @@ -478,6 +479,25 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) ) goto write_error; + for( c = irc->chatrooms; c; c = c->next ) + { + if( c->acc != acc ) + continue; + + if( !xml_printf( fd, 2, "\n", + c->handle, c->channel, "room" ) ) + goto write_error; + + for( set = c->set; set; set = set->next ) + if( set->value && !( set->flags & ACC_SET_NOSAVE ) ) + if( !xml_printf( fd, 3, "%s\n", + set->key, set->value ) ) + goto write_error; + + if( !xml_printf( fd, 2, "\n" ) ) + goto write_error; + } + if( !xml_printf( fd, 1, "\n" ) ) goto write_error; } -- cgit v1.2.3 From a9a7287a9698aa6038958da5074da1169d63ea9d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 30 Aug 2008 23:04:29 +0100 Subject: Added "chat" command, deprecated join_chat. Stuff is still incomplete, have to figure out a sane way to implement "chat set". --- root_commands.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/root_commands.c b/root_commands.c index 88127acb..4f45c6d9 100644 --- a/root_commands.c +++ b/root_commands.c @@ -267,7 +267,7 @@ static void cmd_account( irc_t *irc, char **cmd ) return; } - prpl = find_protocol(cmd[2]); + prpl = find_protocol( cmd[2] ); if( prpl == NULL ) { @@ -504,7 +504,7 @@ static void cmd_account( irc_t *irc, char **cmd ) } else { - irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] ); + irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[1] ); } } @@ -1002,6 +1002,58 @@ static void cmd_qlist( irc_t *irc, char **cmd ) static void cmd_join_chat( irc_t *irc, char **cmd ) { + irc_usermsg( irc, "This command is now obsolete. " + "Please try the `chat' command instead." ); +} + +static void cmd_chat( irc_t *irc, char **cmd ) +{ + account_t *acc; + struct chat *c; + + if( g_strcasecmp( cmd[1], "add" ) == 0 ) + { + if( !( cmd[2] && cmd[3] && cmd[4] ) ) + { + irc_usermsg( irc, "Not enough parameters given (need %d)", 4 ); + return; + } + + if( !( acc = account_get( irc, cmd[2] ) ) ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + + if( ( c = chat_add( irc, acc, cmd[3], cmd[4] ) ) ) + irc_usermsg( irc, "Chatroom added successfully." ); + else + irc_usermsg( irc, "Could not add chatroom." ); + } + else if( g_strcasecmp( cmd[1], "list" ) == 0 ) + { + int i = 0; + + if( strchr( irc->umode, 'b' ) ) + irc_usermsg( irc, "Chatroom list:" ); + + for( c = irc->chatrooms; c; c = c->next ) + { + irc_usermsg( irc, "%2d. %s(%s) %s, %s", i, c->acc->prpl->name, + c->acc->user, c->handle, c->channel ); + + i ++; + } + irc_usermsg( irc, "End of chatroom list" ); + } + else + { + irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] ); + } + + + +#if 0 account_t *a; struct im_connection *ic; char *chat, *channel, *nick = NULL, *password = NULL; @@ -1070,6 +1122,7 @@ static void cmd_join_chat( irc_t *irc, char **cmd ) irc_usermsg( irc, "Tried to join chat, not sure if this was successful" ); g_free( channel ); } +#endif } const command_t commands[] = { @@ -1092,5 +1145,6 @@ const command_t commands[] = { { "nick", 1, cmd_nick, 0 }, { "qlist", 0, cmd_qlist, 0 }, { "join_chat", 2, cmd_join_chat, 0 }, + { "chat", 1, cmd_chat, 0 }, { NULL } }; -- cgit v1.2.3 From 131c6b640e9921844fcf528de1a74682cfc6c768 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 30 Aug 2008 23:26:45 +0100 Subject: Added chat_get(), similar to account_get() (find an account by number or other criteria). --- chat.c | 35 +++++++++++++++++++++++++++++++++++ chat.h | 1 + 2 files changed, 36 insertions(+) diff --git a/chat.c b/chat.c index b4b87117..8c201216 100644 --- a/chat.c +++ b/chat.c @@ -85,6 +85,41 @@ struct chat *chat_bychannel( irc_t *irc, char *channel ) return c; } +struct chat *chat_get( irc_t *irc, char *id ) +{ + struct chat *c, *ret = NULL; + int nr; + + if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 ) + { + for( c = irc->chatrooms; c; c = c->next ) + if( ( nr-- ) == 0 ) + return c; + + return NULL; + } + + for( c = irc->chatrooms; c; c = c->next ) + { + if( strstr( c->handle, id ) ) + { + if( !ret ) + ret = c; + else + return NULL; + } + else if( strstr( c->channel, id ) ) + { + if( !ret ) + ret = c; + else + return NULL; + } + } + + return ret; +} + int chat_chancmp( char *a, char *b ) { if( !chat_chanok( a ) || !chat_chanok( b ) ) diff --git a/chat.h b/chat.h index 6dbe5228..6793b646 100644 --- a/chat.h +++ b/chat.h @@ -37,6 +37,7 @@ struct chat struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ); struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle ); struct chat *chat_bychannel( irc_t *irc, char *channel ); +struct chat *chat_get( irc_t *irc, char *id ); int chat_chancmp( char *a, char *b ); int chat_chanok( char *a ); -- cgit v1.2.3 From e7bc722f096562914f54da2e1f8a0f3614763c1d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 01:04:53 +0100 Subject: Integrated cmd_set() and the "account set" into one fully unreadable cmd_set_real() function and using this to get a proper "chat set" command. --- chat.c | 8 +- root_commands.c | 250 ++++++++++++++++++++++++++++---------------------------- 2 files changed, 131 insertions(+), 127 deletions(-) diff --git a/chat.c b/chat.c index 8c201216..41de1401 100644 --- a/chat.c +++ b/chat.c @@ -28,6 +28,7 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) { struct chat *c, *l; + set_t *s; if( !chat_chanok( channel ) ) return NULL; @@ -52,9 +53,10 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) c->handle = g_strdup( handle ); c->channel = g_strdup( channel ); - set_add( &c->set, "auto_join", "false", set_eval_bool, c ); - set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); - set_add( &c->set, "nick", NULL, NULL, c ); + s = set_add( &c->set, "auto_join", "false", set_eval_bool, c ); + s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); + s = set_add( &c->set, "nick", NULL, NULL, c ); + s->flags |= SET_NULL_OK; return c; } diff --git a/root_commands.c b/root_commands.c index 4f45c6d9..89fc4776 100644 --- a/root_commands.c +++ b/root_commands.c @@ -247,6 +247,116 @@ static void cmd_showset( irc_t *irc, set_t **head, char *key ) irc_usermsg( irc, "%s is empty", key ); } +typedef set_t** (*cmd_set_findhead)( irc_t*, char* ); + +static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) +{ + char *set_full = NULL, *set_name = NULL, *tmp; + set_t **head; + + if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 ) + set_full = cmd[2]; + else + set_full = cmd[1]; + + if( findhead == NULL ) + { + set_name = set_full; + + head = &irc->set; + } + else + { + char *id; + + if( !set_full ) + { + /* FIXME: Broken # */ + irc_usermsg( irc, "Not enough parameters given (need %d)", 3 ); + return 0; + } + + if( ( tmp = strchr( set_full, '/' ) ) ) + { + id = g_strndup( set_full, ( tmp - set_full ) ); + set_name = tmp + 1; + } + else + { + id = g_strdup( set_full ); + } + + if( ( head = findhead( irc, id ) ) == NULL ) + { + g_free( id ); + irc_usermsg( irc, "Could not find setting." ); + return 0; + } + g_free( id ); + } + + if( cmd[1] && cmd[2] && set_name ) + { + set_t *s = set_find( head, set_name ); + int st; + + /* + if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY ) + { + irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); + return 0; + } + else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY ) + { + irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); + return 0; + } + */ + + if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 ) + st = set_reset( head, set_name ); + else + st = set_setstr( head, set_name, cmd[2] ); + + if( set_getstr( head, set_name ) == NULL ) + { + if( st ) + irc_usermsg( irc, "Setting changed successfully" ); + else + irc_usermsg( irc, "Failed to change setting" ); + } + else + { + cmd_showset( irc, head, set_name ); + } + } + else if( set_name ) + { + cmd_showset( irc, head, set_name ); + } + else + { + set_t *s = *head; + while( s ) + { + cmd_showset( irc, &s, s->key ); + s = s->next; + } + } + + return 1; +} + +static set_t **cmd_account_set_findhead( irc_t *irc, char *id ) +{ + account_t *a; + + if( ( a = account_get( irc, id ) ) ) + return &a->set; + else + return NULL; +} + static void cmd_account( irc_t *irc, char **cmd ) { account_t *a; @@ -419,88 +529,13 @@ static void cmd_account( irc_t *irc, char **cmd ) } else if( g_strcasecmp( cmd[1], "set" ) == 0 ) { - char *acc_handle, *set_name = NULL, *tmp; - if( !cmd[2] ) { irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); return; } - if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 ) - acc_handle = g_strdup( cmd[3] ); - else - acc_handle = g_strdup( cmd[2] ); - - if( !acc_handle ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 3 ); - return; - } - - if( ( tmp = strchr( acc_handle, '/' ) ) ) - { - *tmp = 0; - set_name = tmp + 1; - } - - if( ( a = account_get( irc, acc_handle ) ) == NULL ) - { - g_free( acc_handle ); - irc_usermsg( irc, "Invalid account" ); - return; - } - - if( cmd[3] && set_name ) - { - set_t *s = set_find( &a->set, set_name ); - int st; - - if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY ) - { - g_free( acc_handle ); - irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); - return; - } - else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY ) - { - g_free( acc_handle ); - irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); - return; - } - - if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 ) - st = set_reset( &a->set, set_name ); - else - st = set_setstr( &a->set, set_name, cmd[3] ); - - if( set_getstr( &a->set, set_name ) == NULL ) - { - if( st ) - irc_usermsg( irc, "Setting changed successfully" ); - else - irc_usermsg( irc, "Failed to change setting" ); - } - else - { - cmd_showset( irc, &a->set, set_name ); - } - } - else if( set_name ) - { - cmd_showset( irc, &a->set, set_name ); - } - else - { - set_t *s = a->set; - while( s ) - { - cmd_showset( irc, &s, s->key ); - s = s->next; - } - } - - g_free( acc_handle ); + cmd_set_real( irc, cmd + 1, cmd_account_set_findhead ); } else { @@ -834,54 +869,7 @@ static void cmd_yesno( irc_t *irc, char **cmd ) static void cmd_set( irc_t *irc, char **cmd ) { - char *set_name = cmd[1]; - - if( cmd[1] && cmd[2] ) - { - int st; - - if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 ) - { - st = set_reset( &irc->set, cmd[2] ); - set_name = cmd[2]; - } - else - { - st = set_setstr( &irc->set, cmd[1], cmd[2] ); - } - - /* Normally we just show the variable's new/unchanged - value as feedback to the user, but this has always - caused confusion when changing the password. Give - other feedback instead: */ - if( set_getstr( &irc->set, set_name ) == NULL ) - { - if( st ) - irc_usermsg( irc, "Setting changed successfully" ); - else - irc_usermsg( irc, "Failed to change setting" ); - } - else - { - cmd_showset( irc, &irc->set, set_name ); - } - } - else if( set_name ) - { - cmd_showset( irc, &irc->set, set_name ); - - if( strchr( set_name, '/' ) ) - irc_usermsg( irc, "Warning: / found in setting name, you're probably looking for the `account set' command." ); - } - else - { - set_t *s = irc->set; - while( s ) - { - cmd_showset( irc, &s, s->key ); - s = s->next; - } - } + cmd_set_real( irc, cmd, NULL ); } static void cmd_save( irc_t *irc, char **cmd ) @@ -1006,6 +994,16 @@ static void cmd_join_chat( irc_t *irc, char **cmd ) "Please try the `chat' command instead." ); } +static set_t **cmd_chat_set_findhead( irc_t *irc, char *id ) +{ + struct chat *c; + + if( ( c = chat_get( irc, id ) ) ) + return &c->set; + else + return NULL; +} + static void cmd_chat( irc_t *irc, char **cmd ) { account_t *acc; @@ -1046,6 +1044,10 @@ static void cmd_chat( irc_t *irc, char **cmd ) } irc_usermsg( irc, "End of chatroom list" ); } + else if( g_strcasecmp( cmd[1], "set" ) == 0 ) + { + cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead ); + } else { irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] ); -- cgit v1.2.3 From 0e639f5e5245aa807764162b7f1928b641947658 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 10:13:56 +0100 Subject: Added one TODO, and also dupe-check channel names against the control channel. --- chat.c | 3 +++ root_commands.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/chat.c b/chat.c index 41de1401..a786794e 100644 --- a/chat.c +++ b/chat.c @@ -33,6 +33,9 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) if( !chat_chanok( channel ) ) return NULL; + if( chat_chancmp( channel, irc->channel ) == 0 ) + return NULL; + for( c = irc->chatrooms; c; c = c->next ) { if( chat_chancmp( channel, c->channel ) == 0 ) diff --git a/root_commands.c b/root_commands.c index 89fc4776..83620173 100644 --- a/root_commands.c +++ b/root_commands.c @@ -301,6 +301,8 @@ static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) int st; /* + FIXME: Make these work again. Probably a gross hack. + if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY ) { irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); -- cgit v1.2.3 From 39f93f0ce1c0a179b51f5ff6474d57509e9e0d17 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 14:42:33 +0100 Subject: /join can now be used to join chatrooms, join_chat should not be used anymore. /join should not be used for unnamed groupchats anymore, use "chat with" instead. --- chat.c | 2 +- irc.c | 6 ++++-- irc.h | 2 +- irc_commands.c | 37 +++++++++++++++++++------------------ root_commands.c | 25 ++++++++++++++++++++++++- 5 files changed, 49 insertions(+), 23 deletions(-) diff --git a/chat.c b/chat.c index a786794e..234c1a23 100644 --- a/chat.c +++ b/chat.c @@ -138,7 +138,7 @@ int chat_chancmp( char *a, char *b ) int chat_chanok( char *a ) { - if( strchr( "&#", a[0] ) != NULL ) + if( strchr( CTYPES, a[0] ) != NULL ) return nick_ok( a + 1 ); else return 0; diff --git a/irc.c b/irc.c index 9b4e0020..d6b11dca 100644 --- a/irc.c +++ b/irc.c @@ -780,7 +780,9 @@ void irc_login( irc_t *irc ) irc_reply( irc, 2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost ); irc_reply( irc, 3, ":%s", IRCD_INFO ); irc_reply( irc, 4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES ); - irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 ); + irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee " + "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", + CTYPES, CMODES, MAX_NICK_LENGTH - 1 ); irc_motd( irc ); irc->umode[0] = '\0'; irc_umode_set( irc, "+" UMODE, 1 ); @@ -1021,7 +1023,7 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) struct groupchat *c = NULL; user_t *u = NULL; - if( *nick == '#' || *nick == '&' ) + if( strchr( CTYPES, *nick ) ) { if( !( c = irc_chat_by_channel( irc, nick ) ) ) { diff --git a/irc.h b/irc.h index e341b2da..f9b2a5b9 100644 --- a/irc.h +++ b/irc.h @@ -37,6 +37,7 @@ #define CMODES "nt" #define CMODE "t" #define UMODE "s" +#define CTYPES "&#" typedef enum { @@ -95,7 +96,6 @@ typedef struct irc } irc_t; #include "user.h" -// #include "nick.h" extern GSList *irc_connection_list; diff --git a/irc_commands.c b/irc_commands.c index fb2bc7cf..d083f714 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -124,7 +124,7 @@ static void irc_cmd_oper( irc_t *irc, char **cmd ) static void irc_cmd_mode( irc_t *irc, char **cmd ) { - if( *cmd[1] == '#' || *cmd[1] == '&' ) + if( strchr( CTYPES, *cmd[1] ) ) { if( cmd[2] ) { @@ -192,26 +192,27 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) RFC doesn't have any reply for that though? */ else if( cmd[1] ) { - if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] ) + struct groupchat *gc; + struct chat *c; + user_t *u; + + if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 ) + { + irc_reply( irc, 403, "%s :No such channel", cmd[1] ); + return; + } + + if( ( c = chat_bychannel( irc, cmd[1] ) ) ) { - user_t *u = user_find( irc, cmd[1] + 1 ); + char *nick = set_getstr( &c->set, "nick" ); - if( u && u->ic && u->ic->acc->prpl->chat_with ) - { - irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] ); - - if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) ) - { - irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick ); - } - } - else if( u ) - { - irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 ); - } - else + if( nick == NULL ) + nick = irc->nick; + + if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, NULL ) ) ) { - irc_reply( irc, 403, "%s :No such nick", cmd[1] ); + g_free( gc->channel ); + gc->channel = g_strdup( c->channel ); } } else diff --git a/root_commands.c b/root_commands.c index 83620173..97cadffe 100644 --- a/root_commands.c +++ b/root_commands.c @@ -1050,6 +1050,29 @@ static void cmd_chat( irc_t *irc, char **cmd ) { cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead ); } + else if( g_strcasecmp( cmd[1], "with" ) == 0 ) + { + user_t *u; + + if( !cmd[2] ) + { + irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); + return; + } + + if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with ) + { + if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) ) + { + irc_usermsg( irc, "(Possible) failure while trying to open " + "a groupchat with %s.", u->nick ); + } + } + else + { + irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] ); + } + } else { irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] ); @@ -1083,7 +1106,7 @@ static void cmd_chat( irc_t *irc, char **cmd ) chat = cmd[2]; if( cmd[3] ) { - if( cmd[3][0] != '#' && cmd[3][0] != '&' ) + if( strchr( CTYPES, cmd[3][0] ) == NULL ) channel = g_strdup_printf( "&%s", cmd[3] ); else channel = g_strdup( cmd[3] ); -- cgit v1.2.3 From d995c9b5de1bff5e3eb5de47b7ffbd3e92e2ac3d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 15:54:39 +0100 Subject: Added cleanup code. --- account.c | 8 ++++++++ chat.c | 25 +++++++++++++++++++++++++ chat.h | 1 + root_commands.c | 17 +++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/account.c b/account.c index f3e15d7e..f547d8f1 100644 --- a/account.c +++ b/account.c @@ -189,6 +189,7 @@ account_t *account_get( irc_t *irc, char *id ) void account_del( irc_t *irc, account_t *acc ) { account_t *a, *l = NULL; + struct chat *c, *nc; if( acc->ic ) /* Caller should have checked, accounts still in use can't be deleted. */ @@ -202,6 +203,13 @@ void account_del( irc_t *irc, account_t *acc ) else irc->accounts = a->next; + for( c = irc->chatrooms; c; c = nc ) + if( acc == c->acc ) + { + nc = c->next; + chat_del( irc, c ); + } + while( a->set ) set_del( &a->set, a->set->key ); diff --git a/chat.c b/chat.c index 234c1a23..a4c1cce9 100644 --- a/chat.c +++ b/chat.c @@ -125,6 +125,31 @@ struct chat *chat_get( irc_t *irc, char *id ) return ret; } +int chat_del( irc_t *irc, struct chat *chat ) +{ + struct chat *c, *l = NULL; + + for( c = irc->chatrooms; c; c = (l=c)->next ) + if( c == chat ) + break; + + if( c == NULL ) + return 0; + else if( l == NULL ) + irc->chatrooms = c->next; + else + l->next = c->next; + + while( c->set ) + set_del( &c->set, c->set->key ); + + g_free( c->handle ); + g_free( c->channel ); + g_free( c ); + + return 1; +} + int chat_chancmp( char *a, char *b ) { if( !chat_chanok( a ) || !chat_chanok( b ) ) diff --git a/chat.h b/chat.h index 6793b646..8c07d3d0 100644 --- a/chat.h +++ b/chat.h @@ -38,6 +38,7 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle ); struct chat *chat_bychannel( irc_t *irc, char *channel ); struct chat *chat_get( irc_t *irc, char *id ); +int chat_del( irc_t *irc, struct chat *chat ); int chat_chancmp( char *a, char *b ); int chat_chanok( char *a ); diff --git a/root_commands.c b/root_commands.c index 97cadffe..5b709b0e 100644 --- a/root_commands.c +++ b/root_commands.c @@ -1050,6 +1050,23 @@ static void cmd_chat( irc_t *irc, char **cmd ) { cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead ); } + else if( g_strcasecmp( cmd[1], "del" ) == 0 ) + { + if( !cmd[2] ) + { + irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); + return; + } + + if( ( c = chat_get( irc, cmd[2] ) ) ) + { + chat_del( irc, c ); + } + else + { + irc_usermsg( irc, "Could not remove chat." ); + } + } else if( g_strcasecmp( cmd[1], "with" ) == 0 ) { user_t *u; -- cgit v1.2.3 From 3611717156f4c9ebfdf829319840d49e59b827ce Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 16:00:35 +0100 Subject: Added auto_join code. --- chat.c | 20 +++++++++++++++++++- chat.h | 2 ++ irc_commands.c | 12 +----------- protocols/nogaim.c | 11 +++++++++++ 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/chat.c b/chat.c index a4c1cce9..d60655de 100644 --- a/chat.c +++ b/chat.c @@ -57,7 +57,7 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) c->channel = g_strdup( channel ); s = set_add( &c->set, "auto_join", "false", set_eval_bool, c ); - s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); + /* s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); */ s = set_add( &c->set, "nick", NULL, NULL, c ); s->flags |= SET_NULL_OK; @@ -168,3 +168,21 @@ int chat_chanok( char *a ) else return 0; } + +int chat_join( irc_t *irc, struct chat *c ) +{ + struct groupchat *gc; + char *nick = set_getstr( &c->set, "nick" ); + + if( nick == NULL ) + nick = irc->nick; + + if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, NULL ) ) ) + { + g_free( gc->channel ); + gc->channel = g_strdup( c->channel ); + return 1; + } + + return 0; +} diff --git a/chat.h b/chat.h index 8c07d3d0..78e54f24 100644 --- a/chat.h +++ b/chat.h @@ -42,3 +42,5 @@ int chat_del( irc_t *irc, struct chat *chat ); int chat_chancmp( char *a, char *b ); int chat_chanok( char *a ); + +int chat_join( irc_t *irc, struct chat *c ); diff --git a/irc_commands.c b/irc_commands.c index d083f714..8941b0e9 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -192,7 +192,6 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) RFC doesn't have any reply for that though? */ else if( cmd[1] ) { - struct groupchat *gc; struct chat *c; user_t *u; @@ -204,16 +203,7 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) if( ( c = chat_bychannel( irc, cmd[1] ) ) ) { - char *nick = set_getstr( &c->set, "nick" ); - - if( nick == NULL ) - nick = irc->nick; - - if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, NULL ) ) ) - { - g_free( gc->channel ); - gc->channel = g_strdup( c->channel ); - } + chat_join( irc, c ); } else { diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 6a267adf..20d2f3f1 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -248,6 +248,8 @@ static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond ) void imcb_connected( struct im_connection *ic ) { + irc_t *irc = ic->irc; + struct chat *c; user_t *u; /* MSN servers sometimes redirect you to a different server and do @@ -270,6 +272,15 @@ void imcb_connected( struct im_connection *ic ) /* Apparently we're connected successfully, so reset the exponential backoff timer. */ ic->acc->auto_reconnect_delay = 0; + + for( c = irc->chatrooms; c; c = c->next ) + { + if( c->acc != ic->acc ) + continue; + + if( set_getbool( &c->set, "auto_join" ) ) + chat_join( irc, c ); + } } gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ) -- cgit v1.2.3 From 3b99524d537183f74f34be8fef4e02324707f34e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 16:41:51 +0100 Subject: Added a MIN_ARGS() macro instead of stupidly copy-pasting the same if-statement ten times. --- root_commands.c | 66 +++++++++++++++++++++------------------------------------ 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/root_commands.c b/root_commands.c index 5b709b0e..b6ae5c7a 100644 --- a/root_commands.c +++ b/root_commands.c @@ -77,6 +77,18 @@ void root_command_string( irc_t *irc, user_t *u, char *command, int flags ) root_command( irc, cmd ); } +#define MIN_ARGS( x, y... ) \ + do \ + { \ + int i; \ + for( i = 1; i <= x; i ++ ) \ + if( cmd[i] == NULL ) \ + { \ + irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \ + return y; \ + } \ + } while( 0 ) + void root_command( irc_t *irc, char *cmd[] ) { int i; @@ -87,11 +99,8 @@ void root_command( irc_t *irc, char *cmd[] ) for( i = 0; commands[i].command; i++ ) if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 ) { - if( !cmd[commands[i].required_parameters] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters ); - return; - } + MIN_ARGS( commands[i].required_parameters ); + commands[i].execute( irc, cmd ); return; } @@ -269,12 +278,7 @@ static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) { char *id; - if( !set_full ) - { - /* FIXME: Broken # */ - irc_usermsg( irc, "Not enough parameters given (need %d)", 3 ); - return 0; - } + MIN_ARGS( 3, 0 ); if( ( tmp = strchr( set_full, '/' ) ) ) { @@ -373,11 +377,7 @@ static void cmd_account( irc_t *irc, char **cmd ) { struct prpl *prpl; - if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL ) - { - irc_usermsg( irc, "Not enough parameters" ); - return; - } + MIN_ARGS( 4 ); prpl = find_protocol( cmd[2] ); @@ -399,11 +399,9 @@ static void cmd_account( irc_t *irc, char **cmd ) } else if( g_strcasecmp( cmd[1], "del" ) == 0 ) { - if( !cmd[2] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); - } - else if( !( a = account_get( irc, cmd[2] ) ) ) + MIN_ARGS( 2 ); + + if( !( a = account_get( irc, cmd[2] ) ) ) { irc_usermsg( irc, "Invalid account" ); } @@ -531,11 +529,7 @@ static void cmd_account( irc_t *irc, char **cmd ) } else if( g_strcasecmp( cmd[1], "set" ) == 0 ) { - if( !cmd[2] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); - return; - } + MIN_ARGS( 2 ); cmd_set_real( irc, cmd + 1, cmd_account_set_findhead ); } @@ -1013,11 +1007,7 @@ static void cmd_chat( irc_t *irc, char **cmd ) if( g_strcasecmp( cmd[1], "add" ) == 0 ) { - if( !( cmd[2] && cmd[3] && cmd[4] ) ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 4 ); - return; - } + MIN_ARGS( 4 ); if( !( acc = account_get( irc, cmd[2] ) ) ) { @@ -1052,11 +1042,7 @@ static void cmd_chat( irc_t *irc, char **cmd ) } else if( g_strcasecmp( cmd[1], "del" ) == 0 ) { - if( !cmd[2] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); - return; - } + MIN_ARGS( 2 ); if( ( c = chat_get( irc, cmd[2] ) ) ) { @@ -1070,12 +1056,8 @@ static void cmd_chat( irc_t *irc, char **cmd ) else if( g_strcasecmp( cmd[1], "with" ) == 0 ) { user_t *u; - - if( !cmd[2] ) - { - irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); - return; - } + + MIN_ARGS( 2 ); if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with ) { -- cgit v1.2.3 From 07054a511479f070a274b4c8a488cc79b79abe1f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 31 Aug 2008 23:49:32 +0100 Subject: "chat add" can generate a channel name by itself if necessary. Also fixed MIN_ARGS, using a variable named i showed why precompiler macros really are evil. :-) --- root_commands.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/root_commands.c b/root_commands.c index b6ae5c7a..f65bdc65 100644 --- a/root_commands.c +++ b/root_commands.c @@ -80,9 +80,9 @@ void root_command_string( irc_t *irc, user_t *u, char *command, int flags ) #define MIN_ARGS( x, y... ) \ do \ { \ - int i; \ - for( i = 1; i <= x; i ++ ) \ - if( cmd[i] == NULL ) \ + int blaat; \ + for( blaat = 0; blaat <= x; blaat ++ ) \ + if( cmd[blaat] == NULL ) \ { \ irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \ return y; \ @@ -1007,7 +1007,9 @@ static void cmd_chat( irc_t *irc, char **cmd ) if( g_strcasecmp( cmd[1], "add" ) == 0 ) { - MIN_ARGS( 4 ); + char *channel, *s; + + MIN_ARGS( 3 ); if( !( acc = account_get( irc, cmd[2] ) ) ) { @@ -1015,10 +1017,30 @@ static void cmd_chat( irc_t *irc, char **cmd ) return; } - if( ( c = chat_add( irc, acc, cmd[3], cmd[4] ) ) ) + if( cmd[4] == NULL ) + { + channel = g_strdup( cmd[3] ); + if( ( s = strchr( channel, '@' ) ) ) + *s = 0; + } + else + { + channel = g_strdup( cmd[4] ); + } + + if( strchr( CTYPES, channel[0] ) == NULL ) + { + s = g_strdup_printf( "%c%s", CTYPES[0], channel ); + g_free( channel ); + channel = s; + } + + if( ( c = chat_add( irc, acc, cmd[3], channel ) ) ) irc_usermsg( irc, "Chatroom added successfully." ); else irc_usermsg( irc, "Could not add chatroom." ); + + g_free( channel ); } else if( g_strcasecmp( cmd[1], "list" ) == 0 ) { -- cgit v1.2.3 From c1333754810c20ff77324c9463ec3efba3c493d2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 1 Sep 2008 00:19:32 +0100 Subject: Added documentation on the "chat" command. --- doc/user-guide/commands.xml | 108 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 3 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index cd16808e..60b24113 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -124,7 +124,7 @@ - This command gives you a list of all the accounts known by BitlBee, including the numbers you'll need for most account commands. + This command gives you a list of all the accounts known by BitlBee. @@ -137,11 +137,11 @@ - This account can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing account set <account id>. + This command can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing account set <account id>. - For more infomation about a setting, see help set <setting>. For details about the syntax of this command, see help set. + For more infomation about a setting, see help set <setting>. @@ -151,6 +151,89 @@ + + Chatroom list maintenance + chat <action> [<arguments>] + + + + + Available actions: add, del, list, with and set. See help chat <action> for more information. + + + + + + chat add <account> <room> [<channel>] + + + + Add a chatroom to the list of chatrooms you're interested in. BitlBee needs this list to map room names to a proper IRC channel name. + + + + After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. (See chat set) + + + + + + + chat del <chat id> + + + + This commands deletes an chatroom from your list. + + + + The room ID can be a number (see chat list), or (part of) the name of the room/channel. + + + + + + chat list + + + + This command gives you a list of all the chatrooms known by BitlBee. + + + + + + chat with <nickname> + + + + While most chat subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what /join #nickname used to do in older BitlBee versions. + + + + + + chat set <chat id> + chat set <chat id>/<setting> + chat set <chat id>/<setting> <value> + chat set -del <chat id>/<setting> + + + + This command can be used to change various settings for chatrooms. + + + + For more infomation about a setting, see help set <setting>. + + + + The room ID can be a number (see chat list), or (part of) the name of the room/channel. + + + + + Add a buddy to your contact list add <connection> <handle> [<nick>] @@ -302,6 +385,16 @@ + + false + + + + With this option enabled, BitlBee will automatically join this chatroom when you log in. + + + + false @@ -485,6 +578,15 @@ + + + + + You can use this option to set your nickname in a chatroom. You won't see this nickname yourself, but other people in the room will. By default, BitlBee will use your username as the chatroom nickname. + + + + both both, root, user, none -- cgit v1.2.3 From 35529ae92ca468d7be6be60663c1f8d6a07b8373 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 1 Sep 2008 00:37:56 +0100 Subject: Updated "help groupchats" and removed help information on the join_chat command. --- doc/user-guide/commands.xml | 24 ------------------------ doc/user-guide/misc.xml | 6 +++--- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 60b24113..e50aed19 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -955,28 +955,4 @@ - - - Join a named groupchat/conference room - join_chat <connection> <room name> [<channel name>] [<room nickname>] [<password>] - - - - On most IM-networks groupchats can be started using the /join command. (/join #foo to start a chatroom with you and foo) This doesn't work with names groupchats though (which exist on Jabber networks and AIM, for example), instead you can use this command. - - - - The first two arguments are required. room name is the name of the chatroom on the IM-network. channel name is the IRC channel name BitlBee should map this to. room nickname is the nickname you want to have in this channel. If you don't give these options, BitlBee will do the right guesses. - - - - The following command will join you to the chatroom called bitlbee@conference.bitlbee.org. The channel will be called &bitlbee-help because &bitlbee will already be in use. Your nickname will be help-me. - - - - - join_chat jabber bitlbee@conference.bitlbee.org &bitlbee-help help-me - - - diff --git a/doc/user-guide/misc.xml b/doc/user-guide/misc.xml index b55a8915..3102b8b0 100644 --- a/doc/user-guide/misc.xml +++ b/doc/user-guide/misc.xml @@ -68,15 +68,15 @@ Of course you can also create your own groupchats. Type help groupchat Creating groupchats -If you want to start a groupchat with the person lisa_msn in it, just join the channel #lisa_msn. BitlBee will refuse to join you to the channel with that name, but it will create a new virtual channel with root, you and lisa_msn in it. +To open a groupchat, use the chat with command. For example, to start a groupchat with the person lisa_msn in it, just type chat with lisa_msn. BitlBee will create a new virtual channel with root, you and lisa_msn in it. -Of course a channel with only two people isn't really exciting yet. So the next step is to invite some other people to the channel. For this, you can use the /invite command of your IRC client. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat. +Then, just use the ordinary IRC /invite command to invite more people. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat. -Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the join_chat command to join them. See help join_chat for more information. +Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the chat add command to join them. See help chat_add for more information. -- cgit v1.2.3 From f86a3d558e1e69a3728c8f8fd014cbcd6271f98e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 1 Sep 2008 11:21:01 +0100 Subject: Fixed ugly looping bug in chatroom list cleanup code. --- account.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/account.c b/account.c index f547d8f1..cb54731f 100644 --- a/account.c +++ b/account.c @@ -204,11 +204,11 @@ void account_del( irc_t *irc, account_t *acc ) irc->accounts = a->next; for( c = irc->chatrooms; c; c = nc ) + { + nc = c->next; if( acc == c->acc ) - { - nc = c->next; chat_del( irc, c ); - } + } while( a->set ) set_del( &a->set, a->set->key ); -- cgit v1.2.3 From d4810dff26f128061d122cf120e1e0174d9df1f2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 2 Sep 2008 08:48:56 +0100 Subject: Fixed check for set -del arguments. --- root_commands.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/root_commands.c b/root_commands.c index f65bdc65..67847650 100644 --- a/root_commands.c +++ b/root_commands.c @@ -264,7 +264,10 @@ static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) set_t **head; if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 ) + { + MIN_ARGS( 2, 0 ); set_full = cmd[2]; + } else set_full = cmd[1]; @@ -278,8 +281,6 @@ static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) { char *id; - MIN_ARGS( 3, 0 ); - if( ( tmp = strchr( set_full, '/' ) ) ) { id = g_strndup( set_full, ( tmp - set_full ) ); -- cgit v1.2.3 From 2bebe15b447b84fd5705a021f73db609c336fd73 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 01:18:21 +0100 Subject: Fixed one crash bug in Yahoo! chatroom invitation handling. --- protocols/yahoo/yahoo.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 8d9e95d8..fa36de39 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -789,9 +789,22 @@ int ext_yahoo_connect(const char *host, int port) static void byahoo_accept_conf( void *data ) { struct byahoo_conf_invitation *inv = data; + struct groupchat *b; + + for( b = inv->ic->groupchats; b; b = b->next ) + if( b == inv->c ) + break; + + if( b != NULL ) + { + yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); + imcb_chat_add_buddy( inv->c, inv->ic->acc->user ); + } + else + { + imcb_log( inv->ic, "Duplicate/corrupted invitation to `%s'.", inv->name ); + } - yahoo_conference_logon( inv->yid, NULL, inv->members, inv->name ); - imcb_chat_add_buddy( inv->c, inv->ic->acc->user ); g_free( inv->name ); g_free( inv ); } -- cgit v1.2.3 From e180c59a7796bb651b96ffaa5757e4688f1d3cc6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 11:56:46 +0100 Subject: Fixed irc_cmd_join(). Giving a more proper response to invalid channel names, and checking if an account is on-line before attempting to join one of its chatrooms. --- irc_commands.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/irc_commands.c b/irc_commands.c index 8941b0e9..71a8fb3e 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -196,19 +196,11 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) user_t *u; if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 ) - { - irc_reply( irc, 403, "%s :No such channel", cmd[1] ); - return; - } - - if( ( c = chat_bychannel( irc, cmd[1] ) ) ) - { + irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] ); + else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic ) chat_join( irc, c ); - } else - { irc_reply( irc, 403, "%s :No such channel", cmd[1] ); - } } } -- cgit v1.2.3 From 94acdd0d7beaa659a5f6b26673c5dea5dbcc4496 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 12:18:19 +0100 Subject: Restored support for password-protected chatrooms (for now only by accepting a password in the IRC JOIN command). --- chat.c | 4 ++-- chat.h | 2 +- irc_commands.c | 3 +-- lib/xmltree.c | 2 +- lib/xmltree.h | 2 +- protocols/jabber/conference.c | 2 +- protocols/jabber/jabber.c | 2 +- protocols/jabber/jabber.h | 2 +- protocols/nogaim.c | 4 ++-- protocols/nogaim.h | 4 ++-- protocols/oscar/oscar.c | 2 +- 11 files changed, 14 insertions(+), 15 deletions(-) diff --git a/chat.c b/chat.c index d60655de..f7edf2e6 100644 --- a/chat.c +++ b/chat.c @@ -169,7 +169,7 @@ int chat_chanok( char *a ) return 0; } -int chat_join( irc_t *irc, struct chat *c ) +int chat_join( irc_t *irc, struct chat *c, const char *password ) { struct groupchat *gc; char *nick = set_getstr( &c->set, "nick" ); @@ -177,7 +177,7 @@ int chat_join( irc_t *irc, struct chat *c ) if( nick == NULL ) nick = irc->nick; - if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, NULL ) ) ) + if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) ) { g_free( gc->channel ); gc->channel = g_strdup( c->channel ); diff --git a/chat.h b/chat.h index 78e54f24..5aef745c 100644 --- a/chat.h +++ b/chat.h @@ -43,4 +43,4 @@ int chat_del( irc_t *irc, struct chat *chat ); int chat_chancmp( char *a, char *b ); int chat_chanok( char *a ); -int chat_join( irc_t *irc, struct chat *c ); +int chat_join( irc_t *irc, struct chat *c, const char *password ); diff --git a/irc_commands.c b/irc_commands.c index 71a8fb3e..bdca5b24 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -193,12 +193,11 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) else if( cmd[1] ) { struct chat *c; - user_t *u; if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 ) irc_reply( irc, 479, "%s :Invalid channel name", cmd[1] ); else if( ( c = chat_bychannel( irc, cmd[1] ) ) && c->acc && c->acc->ic ) - chat_join( irc, c ); + chat_join( irc, c, cmd[2] ); else irc_reply( irc, 403, "%s :No such channel", cmd[1] ); } diff --git a/lib/xmltree.c b/lib/xmltree.c index e65b4f41..67fe46e1 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -471,7 +471,7 @@ char *xt_find_attr( struct xt_node *node, const char *key ) return node->attr[i].value; } -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ) +struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children ) { struct xt_node *node, *c; diff --git a/lib/xmltree.h b/lib/xmltree.h index 10677412..34e3be68 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -89,7 +89,7 @@ void xt_free( struct xt_parser *xt ); struct xt_node *xt_find_node( struct xt_node *node, const char *name ); char *xt_find_attr( struct xt_node *node, const char *key ); -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ); +struct xt_node *xt_new_node( char *name, const char *text, struct xt_node *children ); void xt_add_child( struct xt_node *parent, struct xt_node *child ); void xt_add_attr( struct xt_node *node, const char *key, const char *value ); int xt_remove_attr( struct xt_node *node, const char *key ); diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 79fdd053..ce2c0b86 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -25,7 +25,7 @@ static xt_status jabber_chat_join_failed( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); -struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ) +struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password ) { struct jabber_chat *jc; struct xt_node *node; diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index ac8638cf..b8e88c26 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -424,7 +424,7 @@ static void jabber_remove_buddy( struct im_connection *ic, char *who, char *grou presence_send_request( ic, who, "unsubscribe" ); } -static struct groupchat *jabber_chat_join_( struct im_connection *ic, char *room, char *nick, char *password ) +static struct groupchat *jabber_chat_join_( struct im_connection *ic, const char *room, const char *nick, const char *password ) { if( strchr( room, '@' ) == NULL ) imcb_error( ic, "Invalid room name: %s", room ); diff --git a/protocols/jabber/jabber.h b/protocols/jabber/jabber.h index 904bf0c4..ee453144 100644 --- a/protocols/jabber/jabber.h +++ b/protocols/jabber/jabber.h @@ -239,7 +239,7 @@ xt_status sasl_pkt_result( struct xt_node *node, gpointer data ); gboolean sasl_supported( struct im_connection *ic ); /* conference.c */ -struct groupchat *jabber_chat_join( struct im_connection *ic, char *room, char *nick, char *password ); +struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, const char *nick, const char *password ); struct groupchat *jabber_chat_by_jid( struct im_connection *ic, const char *name ); void jabber_chat_free( struct groupchat *c ); int jabber_chat_msg( struct groupchat *ic, char *message, int flags ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 20d2f3f1..bec80c25 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -279,7 +279,7 @@ void imcb_connected( struct im_connection *ic ) continue; if( set_getbool( &c->set, "auto_join" ) ) - chat_join( irc, c ); + chat_join( irc, c, NULL ); } } @@ -709,7 +709,7 @@ void imcb_buddy_typing( struct im_connection *ic, char *handle, uint32_t flags ) } } -struct groupchat *imcb_chat_new( struct im_connection *ic, char *handle ) +struct groupchat *imcb_chat_new( struct im_connection *ic, const char *handle ) { struct groupchat *c; diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 9fe843b5..d828de4c 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -208,7 +208,7 @@ struct prpl { * your protocol does not support publicly named group chats, then do * not implement this. */ struct groupchat * - (* chat_join) (struct im_connection *, char *room, char *nick, char *password); + (* chat_join) (struct im_connection *, const char *room, const char *nick, const char *password); /* Change the topic, if supported. Note that BitlBee expects the IM server to confirm the topic change with a regular topic change event. If it doesn't do that, you have to fake it to make it @@ -289,7 +289,7 @@ G_MODULE_EXPORT void imcb_chat_invited( struct im_connection *ic, char *handle, * - After you have a groupchat pointer, you should add the handles, finally * 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, char *handle ); +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 ); /* 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 ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 36e03166..8be04259 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2580,7 +2580,7 @@ void oscar_chat_leave(struct groupchat *c) oscar_chat_kill(c->ic, c->data); } -struct groupchat *oscar_chat_join(struct im_connection * ic, char * room, char * nick, char * password ) +struct groupchat *oscar_chat_join(struct im_connection * ic, const char * room, const char * nick, const char * password ) { struct oscar_data * od = (struct oscar_data *)ic->proto_data; aim_conn_t * cur; -- cgit v1.2.3 From b2c062d609becdffc8c8542f68e260ab7b36dbcd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 12:21:55 +0100 Subject: Adding the password to the right part of the stanza so joining password-protected rooms *really* works. --- protocols/jabber/conference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index ce2c0b86..480006bd 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -35,9 +35,9 @@ struct groupchat *jabber_chat_join( struct im_connection *ic, const char *room, roomjid = g_strdup_printf( "%s/%s", room, nick ); node = xt_new_node( "x", NULL, NULL ); xt_add_attr( node, "xmlns", XMLNS_MUC ); - node = jabber_make_packet( "presence", NULL, roomjid, node ); if( password ) xt_add_child( node, xt_new_node( "password", password, NULL ) ); + node = jabber_make_packet( "presence", NULL, roomjid, node ); jabber_cache_add( ic, node, jabber_chat_join_failed ); if( !jabber_write_packet( ic, node ) ) -- cgit v1.2.3 From fb98634646e0560bc8f99b56502b6f050742a072 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 28 Sep 2008 14:09:36 +0100 Subject: Fixed crappy memory management in http_client. --- lib/http_client.c | 19 ++++++++++--------- lib/http_client.h | 2 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/http_client.c b/lib/http_client.c index b00fcf98..aae5645b 100644 --- a/lib/http_client.c +++ b/lib/http_client.c @@ -58,8 +58,8 @@ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_f if( error ) { - g_free( req ); - return( NULL ); + http_free( req ); + return NULL; } req->func = func; @@ -159,10 +159,7 @@ error: req->status_string = g_strdup( "Error while writing HTTP request" ); req->func( req ); - - g_free( req->request ); - g_free( req ); - + http_free( req ); return FALSE; } @@ -443,11 +440,15 @@ cleanup: closesocket( req->fd ); req->func( req ); - + http_free( req ); + return FALSE; +} + +void http_free( struct http_request *req ) +{ g_free( req->request ); g_free( req->reply_headers ); g_free( req->status_string ); g_free( req ); - - return FALSE; } + diff --git a/lib/http_client.h b/lib/http_client.h index 78d6dbd1..d73894a4 100644 --- a/lib/http_client.h +++ b/lib/http_client.h @@ -80,3 +80,5 @@ struct http_request are also supported (using ssl_client). */ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); + +void http_free( struct http_request *req ); -- cgit v1.2.3 From c05eb5b4711774c4274adafdf21558c3ea0492e4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 29 Sep 2008 22:53:05 +0100 Subject: Checking account setting's flags again before changing them. --- root_commands.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/root_commands.c b/root_commands.c index 8770e707..68561a17 100644 --- a/root_commands.c +++ b/root_commands.c @@ -259,8 +259,9 @@ static void cmd_showset( irc_t *irc, set_t **head, char *key ) } typedef set_t** (*cmd_set_findhead)( irc_t*, char* ); +typedef int (*cmd_set_checkflags)( irc_t*, set_t *set ); -static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) +static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead, cmd_set_checkflags checkflags ) { char *set_full = NULL, *set_name = NULL, *tmp; set_t **head; @@ -307,20 +308,8 @@ static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead ) set_t *s = set_find( head, set_name ); int st; - /* - FIXME: Make these work again. Probably a gross hack. - - if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY ) - { - irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); - return 0; - } - else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY ) - { - irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); + if( checkflags && checkflags( irc, s ) == 0 ) return 0; - } - */ if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 ) st = set_reset( head, set_name ); @@ -366,6 +355,24 @@ static set_t **cmd_account_set_findhead( irc_t *irc, char *id ) return NULL; } +static int cmd_account_set_checkflags( irc_t *irc, set_t *s ) +{ + account_t *a = s->data; + + if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY ) + { + irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); + return 0; + } + else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY ) + { + irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); + return 0; + } + + return 1; +} + static void cmd_account( irc_t *irc, char **cmd ) { account_t *a; @@ -534,7 +541,7 @@ static void cmd_account( irc_t *irc, char **cmd ) { MIN_ARGS( 2 ); - cmd_set_real( irc, cmd + 1, cmd_account_set_findhead ); + cmd_set_real( irc, cmd + 1, cmd_account_set_findhead, cmd_account_set_checkflags ); } else { @@ -868,7 +875,7 @@ static void cmd_yesno( irc_t *irc, char **cmd ) static void cmd_set( irc_t *irc, char **cmd ) { - cmd_set_real( irc, cmd, NULL ); + cmd_set_real( irc, cmd, NULL, NULL ); } static void cmd_save( irc_t *irc, char **cmd ) @@ -1065,7 +1072,7 @@ static void cmd_chat( irc_t *irc, char **cmd ) } else if( g_strcasecmp( cmd[1], "set" ) == 0 ) { - cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead ); + cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead, NULL ); } else if( g_strcasecmp( cmd[1], "del" ) == 0 ) { -- cgit v1.2.3 From de49316a14f16000968b2c12a61304afaf731072 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 13 Dec 2008 12:08:05 +0000 Subject: Killed the test for setting non-existing variables since I killed support for them as well. Thanks to cedk@gentoo.org for noticing (Bug #448). Also including chat.o when building the tests to fix linking issues. --- tests/Makefile | 2 +- tests/check_set.c | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/Makefile b/tests/Makefile index db145503..1bcf8f72 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,7 +10,7 @@ clean: distclean: clean -main_objs = account.o bitlbee.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o +main_objs = account.o bitlbee.o chat.o conf.o crypting.o help.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_xml.o storage_text.o user.o test_objs = check.o check_util.o check_nick.o check_md5.o check_arc.o check_irc.o check_help.o check_user.o check_crypting.o check_set.o check_jabber_sasl.o check_jabber_util.o diff --git a/tests/check_set.c b/tests/check_set.c index b1ea973d..29e3c8c8 100644 --- a/tests/check_set.c +++ b/tests/check_set.c @@ -95,13 +95,6 @@ START_TEST(test_setstr) fail_unless(strcmp(set_getstr(&s, "name"), "bloe") == 0); END_TEST -START_TEST(test_setstr_implicit) - void *data = "data"; - set_t *s = NULL, *t; - set_setstr(&s, "name", "bloe"); - fail_unless(set_find(&s, "name") != NULL); -END_TEST - START_TEST(test_set_get_int_unknown) set_t *s = NULL; fail_unless(set_getint(&s, "foo") == 0); @@ -125,6 +118,5 @@ Suite *set_suite (void) tcase_add_test (tc_core, test_set_get_int_unknown); tcase_add_test (tc_core, test_setint); tcase_add_test (tc_core, test_setstr); - tcase_add_test (tc_core, test_setstr_implicit); return s; } -- cgit v1.2.3 From 77fc000cf5248e3c82d21ee20c02db25191d0f0f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 13 Dec 2008 19:46:56 +0000 Subject: Added argument count check to "add -tmp" to prevent NULL dereference. --- root_commands.c | 1 + 1 file changed, 1 insertion(+) diff --git a/root_commands.c b/root_commands.c index 68561a17..d90531eb 100644 --- a/root_commands.c +++ b/root_commands.c @@ -556,6 +556,7 @@ static void cmd_add( irc_t *irc, char **cmd ) if( g_strcasecmp( cmd[1], "-tmp" ) == 0 ) { + MIN_ARGS( 3 ); add_on_server = 0; cmd ++; } -- cgit v1.2.3 From 549545b3c4c1f60eb977e1c16042aac6fe42736c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 13 Dec 2008 20:02:55 +0000 Subject: Checking if acc->prpl->chat_join actually exists before using it. :-/ --- chat.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/chat.c b/chat.c index f7edf2e6..9a880850 100644 --- a/chat.c +++ b/chat.c @@ -29,6 +29,9 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) { struct chat *c, *l; set_t *s; + + if( acc->prpl->chat_join == NULL ) + return NULL; if( !chat_chanok( channel ) ) return NULL; @@ -177,7 +180,8 @@ int chat_join( irc_t *irc, struct chat *c, const char *password ) if( nick == NULL ) nick = irc->nick; - if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) ) + if( c->acc->prpl->chat_join && + ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) ) { g_free( gc->channel ); gc->channel = g_strdup( c->channel ); -- cgit v1.2.3 From 6d5eb723d73cabcda196189d70bbebc2761eacc3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 01:14:55 +0000 Subject: Added more chat.c sanity checks that were (embarassingly) missing so far. --- chat.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/chat.c b/chat.c index 9a880850..87c262b8 100644 --- a/chat.c +++ b/chat.c @@ -30,14 +30,11 @@ struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel ) struct chat *c, *l; set_t *s; - if( acc->prpl->chat_join == NULL ) - return NULL; - - if( !chat_chanok( channel ) ) - return NULL; - - if( chat_chancmp( channel, irc->channel ) == 0 ) + if( acc->prpl->chat_join == NULL || !chat_chanok( channel ) || + chat_chancmp( channel, irc->channel ) == 0 ) + { return NULL; + } for( c = irc->chatrooms; c; c = c->next ) { @@ -176,12 +173,14 @@ int chat_join( irc_t *irc, struct chat *c, const char *password ) { struct groupchat *gc; char *nick = set_getstr( &c->set, "nick" ); + + if( c->acc->ic == NULL || c->acc->prpl->chat_join == NULL ) + return 0; if( nick == NULL ) nick = irc->nick; - if( c->acc->prpl->chat_join && - ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) ) + if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, password ) ) ) { g_free( gc->channel ); gc->channel = g_strdup( c->channel ); -- cgit v1.2.3 From e1720ce8958ae014ce38d03b7b9ab129d947921b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 01:38:59 +0000 Subject: Fixed a bug in the IRC parser where lines that start with a colon and don't contain any spaces could make BitlBee read uninitialized memory (and possibly even parse it as if it were a command). Also fixed a small memory leak around there. --- irc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/irc.c b/irc.c index 10b4fd83..2dcc625d 100644 --- a/irc.c +++ b/irc.c @@ -406,10 +406,8 @@ void irc_process( irc_t *irc ) lines[i] = conv; } - if( lines[i] ) + if( lines[i] && ( cmd = irc_parse_line( lines[i] ) ) ) { - if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) - continue; irc_exec( irc, cmd ); g_free( cmd ); } @@ -484,7 +482,7 @@ char **irc_parse_line( char *line ) /* Move the line pointer to the start of the command, skipping spaces and the optional prefix. */ if( line[0] == ':' ) { - for( i = 0; line[i] != ' '; i ++ ); + for( i = 0; line[i] && line[i] != ' '; i ++ ); line = line + i; } for( i = 0; line[i] == ' '; i ++ ); -- cgit v1.2.3 From 939370c674071a198e3115f9fa511fa51e8bea9e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 10:19:41 +0000 Subject: events_libevent now detects when the event currently being handled is removed. This could otherwise cause unpredictable behaviour, especially for timers. --- lib/events_libevent.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/events_libevent.c b/lib/events_libevent.c index d3403152..cf616576 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -36,9 +36,11 @@ #include "proxy.h" static void b_main_restart(); -static guint id_next = 1; +static guint id_next = 1; /* Next ID to be allocated to an event handler. */ +static guint id_cur = 0; /* Event ID that we're currently handling. */ +static guint id_dead; /* Set to 1 if b_event_remove removes id_cur. */ static GHashTable *id_hash; -static int quitting = 0; +static int quitting = 0; /* Prepare to quit, stop handling events. */ /* Since libevent doesn't handle two event handlers for one fd-condition very well (which happens sometimes when BitlBee changes event handlers @@ -118,7 +120,7 @@ static void b_event_passthrough( int fd, short event, void *data ) { struct b_event_data *b_ev = data; b_input_condition cond = 0; - int id; + gboolean st; if( fd >= 0 ) { @@ -132,21 +134,30 @@ static void b_event_passthrough( int fd, short event, void *data ) /* Since the called function might cancel this handler already (which free()s b_ev), we have to remember the ID here. */ - id = b_ev->id; + id_cur = b_ev->id; + id_dead = 0; if( quitting ) { - b_event_remove( id ); + b_event_remove( id_cur ); return; } - if( !b_ev->function( b_ev->data, fd, cond ) ) + st = b_ev->function( b_ev->data, fd, cond ); + if( id_dead ) + { + /* This event was killed already, don't touch it! */ + return; + } + else if( !st ) { event_debug( "Handler returned FALSE: " ); - b_event_remove( id ); + b_event_remove( id_cur ); } else if( fd == -1 ) { + /* fd == -1 means it was a timer. These can't be auto-repeated + so it has to be recreated every time. */ struct timeval tv; tv.tv_sec = b_ev->timeout / 1000; @@ -235,6 +246,9 @@ void b_event_remove( gint id ) event_debug( "b_event_remove( %d )\n", id ); if( b_ev ) { + if( id == id_cur ) + id_dead = TRUE; + g_hash_table_remove( id_hash, &b_ev->id ); if( b_ev->evinfo.ev_fd >= 0 ) { -- cgit v1.2.3 From c0c43fba49da3d14097f2c7cf3569a829b84125a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 10:31:49 +0000 Subject: Fixed ic->away leaking memory. This var is only used by OSCAR and should maybe be killed. Also fixed some completely broken indentation in those functions. --- protocols/nogaim.c | 3 +++ protocols/nogaim.h | 2 +- protocols/oscar/oscar.c | 37 +++++++++++++++++-------------------- protocols/yahoo/yahoo.c | 13 +++++++------ 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index bec80c25..fd445324 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -320,6 +320,9 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) ic->acc->prpl->logout( ic ); b_event_remove( ic->inpa ); + g_free( ic->away ); + ic->away = NULL; + u = irc->users; while( u ) { diff --git a/protocols/nogaim.h b/protocols/nogaim.h index d828de4c..ddfff07e 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -238,7 +238,7 @@ G_MODULE_EXPORT void register_protocol( struct prpl * ); /* You will need this function in prpl->login() to get an im_connection from * the account_t parameter. */ G_MODULE_EXPORT struct im_connection *imcb_new( account_t *acc ); -G_MODULE_EXPORT void imcb_free( struct im_connection *ic ); +G_MODULE_EXPORT void imc_free( struct im_connection *ic ); /* Once you're connected, you should call this function, so that the user will * see the success. */ G_MODULE_EXPORT void imcb_connected( struct im_connection *ic ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 8be04259..4142c046 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1938,8 +1938,7 @@ static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); - if (ic->away) - g_free(ic->away); + g_free(ic->away); ic->away = NULL; if (!message) { @@ -1959,55 +1958,53 @@ static void oscar_set_away_aim(struct im_connection *ic, struct oscar_data *od, static void oscar_set_away_icq(struct im_connection *ic, struct oscar_data *od, const char *state, const char *message) { - const char *msg = NULL; + const char *msg = NULL; gboolean no_message = FALSE; /* clean old states */ - if (ic->away) { - g_free(ic->away); - ic->away = NULL; - } + g_free(ic->away); + ic->away = NULL; od->sess->aim_icq_state = 0; /* if no message, then use an empty message */ - if (message) { - msg = message; - } else { - msg = ""; + if (message) { + msg = message; + } else { + msg = ""; no_message = TRUE; - } + } if (!g_strcasecmp(state, "Online")) { 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); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY; } else if (!g_strcasecmp(state, "Do Not Disturb")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTODND; } else if (!g_strcasecmp(state, "Not Available")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTONA; } else if (!g_strcasecmp(state, "Occupied")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOBUSY; } else if (!g_strcasecmp(state, "Free For Chat")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_CHAT); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOFFC; } else if (!g_strcasecmp(state, "Invisible")) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_INVISIBLE); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) { if (no_message) { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_NORMAL); } else { aim_setextstatus(od->sess, od->conn, AIM_ICQ_STATE_AWAY); - ic->away = g_strdup(msg); + ic->away = g_strdup(msg); od->sess->aim_icq_state = AIM_MTYPE_AUTOAWAY; } } @@ -2019,7 +2016,7 @@ static void oscar_set_away(struct im_connection *ic, char *state, char *message) { struct oscar_data *od = (struct oscar_data *)ic->proto_data; - oscar_set_away_aim(ic, od, state, message); + oscar_set_away_aim(ic, od, state, message); if (od->icq) oscar_set_away_icq(ic, od, state, message); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index fa36de39..3e844c55 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -196,13 +196,14 @@ 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; - ic->away = NULL; + away = NULL; if( state && msg && g_strcasecmp( state, msg ) != 0 ) { yd->current_status = YAHOO_STATUS_CUSTOM; - ic->away = ""; + away = ""; } else if( state ) { @@ -211,11 +212,11 @@ static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) away state. */ msg = NULL; - ic->away = ""; + away = ""; if( g_strcasecmp( state, "Available" ) == 0 ) { yd->current_status = YAHOO_STATUS_AVAILABLE; - ic->away = NULL; + away = NULL; } else if( g_strcasecmp( state, "Be Right Back" ) == 0 ) yd->current_status = YAHOO_STATUS_BRB; @@ -241,13 +242,13 @@ static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) { yd->current_status = YAHOO_STATUS_AVAILABLE; - ic->away = NULL; + away = NULL; } } else yd->current_status = YAHOO_STATUS_AVAILABLE; - yahoo_set_away( yd->y2_id, yd->current_status, msg, ic->away != NULL ? 2 : 0 ); + yahoo_set_away( yd->y2_id, yd->current_status, msg, away != NULL ? 2 : 0 ); } static GList *byahoo_away_states( struct im_connection *ic ) -- cgit v1.2.3 From ac46218e481891b0a1d02a0882a3bf964c4ed21c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 10:40:17 +0000 Subject: Removed a double g_free() in proxy.c (that couldn't actually ever be invoked but was stupid anyway). #409. --- lib/proxy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/proxy.c b/lib/proxy.c index 91493557..e52837fe 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -557,7 +557,6 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat else if (proxytype == PROXY_SOCKS5) return proxy_connect_socks5(host, port, phb); - if (phb->host) g_free(phb); g_free(phb); return -1; } -- cgit v1.2.3 From 71d45c298e0757b5f92f0302b987e368ee75891a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 13:39:02 +0000 Subject: Dropping warnings about unknown JIDs since they're spammy (mostly show up when the user logs in from mulitple locations) and the irc->debug setting shouldn't be read from inside the IM modules. --- protocols/jabber/presence.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/protocols/jabber/presence.c b/protocols/jabber/presence.c index 6fc360b7..939bc888 100644 --- a/protocols/jabber/presence.c +++ b/protocols/jabber/presence.c @@ -48,8 +48,9 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) { if( !( bud = jabber_buddy_by_jid( ic, from, GET_BUDDY_EXACT | GET_BUDDY_CREAT ) ) ) { - if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); + /* + imcb_log( ic, "Warning: Could not handle presence information from JID: %s", from ); + */ return XT_HANDLED; } @@ -105,8 +106,9 @@ xt_status jabber_pkt_presence( struct xt_node *node, gpointer data ) { if( ( bud = jabber_buddy_by_jid( ic, from, 0 ) ) == NULL ) { - if( set_getbool( &ic->irc->set, "debug" ) ) - imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); + /* + imcb_log( ic, "Warning: Received presence information from unknown JID: %s", from ); + */ return XT_HANDLED; } -- cgit v1.2.3 From 54699524eda49bb287d5998e443deefd81fce8fc Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 14 Dec 2008 15:04:48 +0000 Subject: Detect disconnects caused by concurrent logins or rate limiting, and disable auto-reconnect in those cases to prevent loops. --- protocols/oscar/oscar.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 4142c046..1118c26d 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -90,7 +90,7 @@ struct oscar_data { GSList *oscar_chats; - gboolean killme; + gboolean killme, no_reconnect; gboolean icq; GSList *evilhack; @@ -180,6 +180,7 @@ static struct chat_connection *find_oscar_chat_by_conn(struct im_connection *ic, static int gaim_parse_auth_resp (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_login (aim_session_t *, aim_frame_t *, ...); +static int gaim_parse_logout (aim_session_t *, aim_frame_t *, ...); static int gaim_handle_redirect (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_oncoming (aim_session_t *, aim_frame_t *, ...); static int gaim_parse_offgoing (aim_session_t *, aim_frame_t *, ...); @@ -293,7 +294,7 @@ static gboolean oscar_callback(gpointer data, gint source, if (aim_get_command(odata->sess, conn) >= 0) { aim_rxdispatch(odata->sess); if (odata->killme) - imc_logout(ic, TRUE); + imc_logout(ic, !odata->no_reconnect); } else { if ((conn->type == AIM_CONN_TYPE_BOS) || !(aim_getconn_type(odata->sess, AIM_CONN_TYPE_BOS))) { @@ -519,6 +520,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { break; case 0x18: /* connecting too frequently */ + od->no_reconnect = TRUE; imcb_error(ic, _("You have been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer.")); break; case 0x1c: @@ -571,6 +573,7 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SSI, AIM_CB_SSI_SRVACK, gaim_ssi_parseack, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_LOC, AIM_CB_LOC_USERINFO, gaim_parseaiminfo, 0); aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_MSG, AIM_CB_MSG_MTN, gaim_parsemtn, 0); + aim_conn_addhandler(sess, bosconn, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR, gaim_parse_logout, 0); ((struct oscar_data *)ic->proto_data)->conn = bosconn; for (i = 0; i < (int)strlen(info->bosip); i++) { @@ -750,6 +753,30 @@ static int gaim_parse_login(aim_session_t *sess, aim_frame_t *fr, ...) { return 1; } +static int gaim_parse_logout(aim_session_t *sess, aim_frame_t *fr, ...) { + struct im_connection *ic = sess->aux_data; + struct oscar_data *odata = ic->proto_data; + int code; + va_list ap; + + va_start(ap, fr); + code = va_arg(ap, int); + va_end(ap); + + imcb_error( ic, "Connection aborted by server: %s", code == 1 ? + "someone else logged in with your account" : + "unknown reason" ); + + /* Tell BitlBee to disable auto_reconnect if code == 1, since that + means a concurrent login somewhere else. */ + odata->no_reconnect = code == 1; + + /* DO NOT log out here! Just tell the callback to do it. */ + odata->killme = TRUE; + + return 1; +} + static int conninitdone_chat(aim_session_t *sess, aim_frame_t *fr, ...) { struct im_connection *ic = sess->aux_data; struct chat_connection *chatcon; -- cgit v1.2.3 From 72b6783ebf2af43a384364e62eab71b1c5e6f9c1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 24 Dec 2008 09:00:42 +0000 Subject: First version of new ini parser. Will just attempt to simplify code a bit. --- lib/ini.c | 128 ++++++++++++++++++++++++++++++++++++++++++++------------------ lib/ini.h | 12 +++--- 2 files changed, 98 insertions(+), 42 deletions(-) diff --git a/lib/ini.c b/lib/ini.c index c63a132e..b758ef81 100644 --- a/lib/ini.c +++ b/lib/ini.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2005 Wilmer van der Gaast and others * + * Copyright 2002-2008 Wilmer van der Gaast and others * \********************************************************************/ /* INI file reading code */ @@ -27,64 +27,118 @@ ini_t *ini_open( char *file ) { - ini_t *ini = g_new0( ini_t, 1 ); + int fd; + ini_t *ini = NULL; + struct stat fi; - if( ( ini->fp = fopen( file, "r" ) ) == NULL ) + if( ( fd = open( file, O_RDONLY ) ) != -1 && + fstat( fd, &fi ) == 0 && + fi.st_size <= 16384 && + ( ini = g_malloc( sizeof( ini_t ) + fi.st_size + 1 ) ) && + read( fd, ini->file, fi.st_size ) == fi.st_size ) { - g_free( ini ); - return( NULL ); + memset( ini, 0, sizeof( ini_t ) ); + ini->size = fi.st_size; + ini->file[ini->size] = 0; + ini->cur = ini->file; + ini->c_section = ""; + return ini; } - return( ini ); + g_free( ini ); + if( fd >= 0 ) + close( fd ); + + return NULL; } int ini_read( ini_t *file ) { - char key[MAX_STRING], s[MAX_STRING], *t; - int i; + char *s; - while( !feof( file->fp ) ) + while( file->cur && file->cur < file->file + file->size ) { - *s = 0; - fscanf( file->fp, "%127[^\n#]s", s ); - fscanf( file->fp, "%*[^\n]s" ); - fgetc( file->fp ); /* Skip newline */ - file->line ++; - if( strchr( s, '=' ) ) + char *e, *next; + + file->line++; + + /* Leading whitespace */ + while( *file->cur == ' ' || *file->cur == '\t' ) + file->cur++; + + /* Find the end of line */ + if( ( e = strchr( file->cur, '\n' ) ) != NULL ) + { + next = e + 1; + } + else + { + /* No more lines. */ + e = file->cur + strlen( file->cur ) - 1; + next = NULL; + } + + /* Comment? */ + if( ( s = strchr( file->cur, '#' ) ) != NULL ) + e = s - 1; + + /* And kill trailing whitespace. */ + while( isspace( *e ) && e > file->cur ) + e--; + e[1] = 0; + + printf( "Stripped line: '%s'\n", file->cur ); + + if( *file->cur == '[' ) + { + file->cur++; + if( ( s = strchr( file->cur, ']' ) ) != NULL ) + { + *s = 0; + file->c_section = file->cur; + + printf( "Section started: %s\n", file->c_section ); + } + } + else if( ( s = strchr( file->cur, '=' ) ) != NULL ) { - sscanf( s, "%[^ =]s", key ); - if( ( t = strchr( key, '.' ) ) ) + *s = 0; + file->value = s + 1; + while( isspace( *file->value ) ) + file->value++; + + s--; + while( isspace( *s ) && s > file->cur ) + s--; + s[1] = 0; + file->key = file->cur; + + if( ( s = strchr( file->key, '.' ) ) != NULL ) { - *t = 0; - strcpy( file->section, key ); - t ++; + *s = 0; + file->section = file->key; + file->key = s + 1; } else { - strcpy( file->section, file->c_section ); - t = key; + file->section = file->c_section; } - sscanf( t, "%s", file->key ); - t = strchr( s, '=' ) + 1; - for( i = 0; t[i] == ' '; i ++ ); - strcpy( file->value, &t[i] ); - for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- ) - file->value[i] = 0; - return( 1 ); - } - else if( ( t = strchr( s, '[' ) ) ) - { - strcpy( file->c_section, t + 1 ); - t = strchr( file->c_section, ']' ); - *t = 0; + file->cur = next; + + printf( "%s.%s = '%s'\n", file->section, file->key, file->value ); + + return 1; } + /* else: noise, but let's just ignore it. */ + + file->cur = next; } - return( 0 ); + + return 0; } void ini_close( ini_t *file ) { - fclose( file->fp ); g_free( file ); } diff --git a/lib/ini.h b/lib/ini.h index 5eab472b..6ae0bde5 100644 --- a/lib/ini.h +++ b/lib/ini.h @@ -28,12 +28,14 @@ typedef struct { - FILE *fp; int line; - char c_section[MAX_STRING]; - char section[MAX_STRING]; - char key[MAX_STRING]; - char value[MAX_STRING]; + char *c_section; + char *section; + char *key; + char *value; + int size; + char *cur, *tok; + char file[]; } ini_t; ini_t *ini_open( char *file ); -- cgit v1.2.3 From 489f996fe52c6969a9574d5ca562a4f5cb5c2585 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 25 Dec 2008 11:05:11 +0000 Subject: Simplified ini parser code a bit more. Not using strtok() after all since I can't find a guarantee that it's okay with me further mutilating the strings. :-) --- conf.c | 6 +++--- lib/ini.c | 51 ++++++++++++++++++++++++--------------------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/conf.c b/conf.c index 8e6b6c69..873aa0e7 100644 --- a/conf.c +++ b/conf.c @@ -307,15 +307,15 @@ static int conf_loadini( conf_t *conf, char *file ) } else { - fprintf( stderr, "Error: Unknown setting `%s` in configuration file.\n", ini->key ); + fprintf( stderr, "Error: Unknown setting `%s` in configuration file (line %d).\n", ini->key, ini->line ); return 0; /* For now just ignore unknown keys... */ } } else if( g_strcasecmp( ini->section, "defaults" ) != 0 ) { - fprintf( stderr, "Error: Unknown section [%s] in configuration file. " - "BitlBee configuration must be put in a [settings] section!\n", ini->section ); + fprintf( stderr, "Error: Unknown section [%s] in configuration file (line %d). " + "BitlBee configuration must be put in a [settings] section!\n", ini->section, ini->line ); return 0; } } diff --git a/lib/ini.c b/lib/ini.c index b758ef81..d9900aeb 100644 --- a/lib/ini.c +++ b/lib/ini.c @@ -52,6 +52,23 @@ ini_t *ini_open( char *file ) return NULL; } +/* Strips leading and trailing whitespace and returns a pointer to the first + non-ws character of the given string. */ +static char *ini_strip_whitespace( char *in ) +{ + char *e; + + while( isspace( *in ) ) + in++; + + e = in + strlen( in ) - 1; + while( e > in && isspace( *e ) ) + e--; + e[1] = 0; + + return in; +} + int ini_read( ini_t *file ) { char *s; @@ -61,33 +78,25 @@ int ini_read( ini_t *file ) char *e, *next; file->line++; - - /* Leading whitespace */ - while( *file->cur == ' ' || *file->cur == '\t' ) - file->cur++; /* Find the end of line */ if( ( e = strchr( file->cur, '\n' ) ) != NULL ) { + *e = 0; next = e + 1; } else { /* No more lines. */ - e = file->cur + strlen( file->cur ) - 1; + e = file->cur + strlen( file->cur ); next = NULL; } /* Comment? */ if( ( s = strchr( file->cur, '#' ) ) != NULL ) - e = s - 1; - - /* And kill trailing whitespace. */ - while( isspace( *e ) && e > file->cur ) - e--; - e[1] = 0; + *s = 0; - printf( "Stripped line: '%s'\n", file->cur ); + file->cur = ini_strip_whitespace( file->cur ); if( *file->cur == '[' ) { @@ -96,22 +105,13 @@ int ini_read( ini_t *file ) { *s = 0; file->c_section = file->cur; - - printf( "Section started: %s\n", file->c_section ); } } else if( ( s = strchr( file->cur, '=' ) ) != NULL ) { *s = 0; - file->value = s + 1; - while( isspace( *file->value ) ) - file->value++; - - s--; - while( isspace( *s ) && s > file->cur ) - s--; - s[1] = 0; - file->key = file->cur; + file->key = ini_strip_whitespace( file->cur ); + file->value = ini_strip_whitespace( s + 1 ); if( ( s = strchr( file->key, '.' ) ) != NULL ) { @@ -125,12 +125,9 @@ int ini_read( ini_t *file ) } file->cur = next; - - printf( "%s.%s = '%s'\n", file->section, file->key, file->value ); - return 1; } - /* else: noise, but let's just ignore it. */ + /* else: noise/comment/etc, let's just ignore it. */ file->cur = next; } -- cgit v1.2.3 From 9e768da723b4a770967efa0d4dcaf58ccef8917f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 13 Jan 2009 18:59:28 +0000 Subject: Fixed an embarassing typo that even fooled me into believing BitlBee is broken. :-( --- doc/user-guide/commands.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index e50aed19..fcb1c8be 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -681,7 +681,7 @@ priority - priority, time + priority, activity @@ -689,7 +689,7 @@ - Normally it's set to priority which means messages will always be delivered to the buddy's resource with the highest priority. If the setting is set to time, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected). + Normally it's set to priority which means messages will always be delivered to the buddy's resource with the highest priority. If the setting is set to activity, messages will be delivered to the resource that was last used to send you a message (or the resource that most recently connected). -- cgit v1.2.3 From 19176513584bf26fa69a8a946982d9c521038a17 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 3 Jun 2009 17:10:36 +0100 Subject: Fixed a bug that caused crashes when joining certain kinds of Google Talk chatrooms. Doesn't seem to be Google Talk specific, other than that this is the first time I see empty elements that cause this crash. A more proper/efficient fix may be to just move the break outside the inner if. --- protocols/jabber/conference.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 480006bd..08bef4f5 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -233,8 +233,10 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu if( ( s = xt_find_attr( c, "xmlns" ) ) && ( strcmp( s, XMLNS_MUC_USER ) == 0 ) ) { - c = xt_find_node( c->children, "item" ); - if( ( s = xt_find_attr( c, "jid" ) ) ) + struct xt_node *item; + + item = xt_find_node( c->children, "item" ); + if( ( s = xt_find_attr( item, "jid" ) ) ) { /* Yay, found what we need. :-) */ bud->ext_jid = jabber_normalize( s ); -- cgit v1.2.3 From b9369b55c99246a8feaee0ad24367044d92fa55d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 18 Jun 2009 00:17:15 +0100 Subject: Fixed compatibility with AIM mobile messages. Should work according to reports in bug #88 (where this patch comes from) and #bitlbee. Not sure about side effects, one way to find out... --- protocols/oscar/aim.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/protocols/oscar/aim.h b/protocols/oscar/aim.h index 9516996c..d1fc602a 100644 --- a/protocols/oscar/aim.h +++ b/protocols/oscar/aim.h @@ -143,6 +143,17 @@ struct client_info_s { "en", \ } +#define AIM_CLIENTINFO_KNOWNGOOD_5_1_3036 { \ + "AOL Instant Messenger, version 5.1.3036/WIN32", \ + 0x0109, \ + 0x0005, \ + 0x0001, \ + 0x0000, \ + 0x0bdc, \ + "us", \ + "en", \ +} + /* * I would make 4.1.2010 the default, but they seem to have found * an alternate way of breaking that one. @@ -151,7 +162,7 @@ struct client_info_s { * memory test, which may require you to have a WinAIM binary laying * around. (see login.c::memrequest()) */ -#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_3_5_1670 +#define AIM_CLIENTINFO_KNOWNGOOD AIM_CLIENTINFO_KNOWNGOOD_5_1_3036 #ifndef TRUE #define TRUE 1 -- cgit v1.2.3 From 8a08d92a092092b5d208616e03fb3fcee1fc3c86 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 24 Jun 2009 22:44:39 +0100 Subject: Fixed crash on setting an unknown setting. --- root_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/root_commands.c b/root_commands.c index d90531eb..b3a7109e 100644 --- a/root_commands.c +++ b/root_commands.c @@ -308,7 +308,7 @@ static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead, cmd_ set_t *s = set_find( head, set_name ); int st; - if( checkflags && checkflags( irc, s ) == 0 ) + if( s && checkflags && checkflags( irc, s ) == 0 ) return 0; if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 ) -- cgit v1.2.3 From 2ea8736c7f59db6c183752f1f2e47cd988c08b66 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 24 Jun 2009 22:48:44 +0100 Subject: Fixed another crash bug (this one was triggered by just typing "chat set"). --- root_commands.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/root_commands.c b/root_commands.c index b3a7109e..678ee143 100644 --- a/root_commands.c +++ b/root_commands.c @@ -1073,6 +1073,8 @@ static void cmd_chat( irc_t *irc, char **cmd ) } else if( g_strcasecmp( cmd[1], "set" ) == 0 ) { + MIN_ARGS( 2 ); + cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead, NULL ); } else if( g_strcasecmp( cmd[1], "del" ) == 0 ) -- cgit v1.2.3 From 01827732cb3d5289e8071d8317b95d5c4043857c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 20 Jul 2009 15:42:11 +0200 Subject: Fixed fd leak in ini.c. How could I miss this one.. :-( --- lib/ini.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/ini.c b/lib/ini.c index d9900aeb..aa291bb2 100644 --- a/lib/ini.c +++ b/lib/ini.c @@ -42,12 +42,16 @@ ini_t *ini_open( char *file ) ini->file[ini->size] = 0; ini->cur = ini->file; ini->c_section = ""; + + close( fd ); + return ini; } - - g_free( ini ); + if( fd >= 0 ) close( fd ); + + ini_close( ini ); return NULL; } -- cgit v1.2.3 From 4fefb772f530cd15ef3e92606532d3c6b193d96b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 3 Oct 2009 20:27:50 +0100 Subject: Yahoo! can log in again. This code still needs major cleanups, use it only if you're very desparate. --- protocols/yahoo/libyahoo2.c | 310 ++++++++++++++++++++++++++++++++++++++++- protocols/yahoo/yahoo2_types.h | 5 +- 2 files changed, 306 insertions(+), 9 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index a61955c4..52655240 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -88,6 +88,12 @@ char *strchr (), *strrchr (); #endif #include "base64.h" +#include "http_client.h" + +static void yahoo_process_auth_response(struct http_request *req); + +/* What's this used for actually? */ +static void _yahoo_http_connected(int id, int fd, int error, void *data); #ifdef USE_STRUCT_CALLBACKS struct yahoo_callbacks *yc=NULL; @@ -168,6 +174,7 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_PING, YAHOO_SERVICE_GOTGROUPRENAME, /* < 1, 36(old), 37(new) */ YAHOO_SERVICE_SYSMESSAGE = 0x14, + YAHOO_SERVICE_SKINNAME = 0x15, YAHOO_SERVICE_PASSTHROUGH2 = 0x16, YAHOO_SERVICE_CONFINVITE = 0x18, YAHOO_SERVICE_CONFLOGON, @@ -191,24 +198,49 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_AUTHRESP = 0x54, YAHOO_SERVICE_LIST, YAHOO_SERVICE_AUTH = 0x57, + YAHOO_SERVICE_AUTHBUDDY = 0x6d, YAHOO_SERVICE_ADDBUDDY = 0x83, YAHOO_SERVICE_REMBUDDY, YAHOO_SERVICE_IGNORECONTACT, /* > 1, 7, 13 < 1, 66, 13, 0*/ YAHOO_SERVICE_REJECTCONTACT, YAHOO_SERVICE_GROUPRENAME = 0x89, /* > 1, 65(new), 66(0), 67(old) */ + YAHOO_SERVICE_Y7_PING = 0x8A, /* 0 - id and that's it?? */ YAHOO_SERVICE_CHATONLINE = 0x96, /* > 109(id), 1, 6(abcde) < 0,1*/ YAHOO_SERVICE_CHATGOTO, YAHOO_SERVICE_CHATJOIN, /* > 1 104-room 129-1600326591 62-2 */ YAHOO_SERVICE_CHATLEAVE, YAHOO_SERVICE_CHATEXIT = 0x9b, + YAHOO_SERVICE_CHATADDINVITE = 0x9d, YAHOO_SERVICE_CHATLOGOUT = 0xa0, YAHOO_SERVICE_CHATPING, YAHOO_SERVICE_COMMENT = 0xa8, - YAHOO_SERVICE_STEALTH = 0xb9, + YAHOO_SERVICE_GAME_INVITE = 0xb7, + YAHOO_SERVICE_STEALTH_PERM = 0xb9, + YAHOO_SERVICE_STEALTH_SESSION = 0xba, + YAHOO_SERVICE_AVATAR = 0xbc, YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd, YAHOO_SERVICE_PICTURE = 0xbe, YAHOO_SERVICE_PICTURE_UPDATE = 0xc1, - YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2 + YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2, + YAHOO_SERVICE_YAB_UPDATE = 0xc4, + YAHOO_SERVICE_Y6_VISIBLE_TOGGLE = 0xc5, /* YMSG13, key 13: 2 = invisible, 1 = visible */ + YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6, /* YMSG13 */ + YAHOO_SERVICE_PICTURE_STATUS = 0xc7, /* YMSG13, key 213: 0 = none, 1 = avatar, 2 = picture */ + YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8, + YAHOO_SERVICE_AUDIBLE = 0xd0, + YAHOO_SERVICE_Y7_PHOTO_SHARING = 0xd2, + YAHOO_SERVICE_Y7_CONTACT_DETAILS = 0xd3,/* YMSG13 */ + YAHOO_SERVICE_Y7_CHAT_SESSION = 0xd4, + YAHOO_SERVICE_Y7_AUTHORIZATION = 0xd6, /* YMSG13 */ + YAHOO_SERVICE_Y7_FILETRANSFER = 0xdc, /* YMSG13 */ + YAHOO_SERVICE_Y7_FILETRANSFERINFO, /* YMSG13 */ + YAHOO_SERVICE_Y7_FILETRANSFERACCEPT, /* YMSG13 */ + YAHOO_SERVICE_Y7_MINGLE = 0xe1, /* YMSG13 */ + YAHOO_SERVICE_Y7_CHANGE_GROUP = 0xe7, /* YMSG13 */ + YAHOO_SERVICE_Y8_STATUS = 0xf0, /* YMSG15 */ + YAHOO_SERVICE_Y8_LIST = 0Xf1, /* YMSG15 */ + YAHOO_SERVICE_WEBLOGIN = 0x0226, + YAHOO_SERVICE_SMS_MSG = 0x02ea }; struct yahoo_pair { @@ -732,7 +764,7 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet data = y_new0(unsigned char, len + 1); memcpy(data + pos, "YMSG", 4); pos += 4; - pos += yahoo_put16(data + pos, 0x000c); + pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); pos += yahoo_put16(data + pos, 0x0000); pos += yahoo_put16(data + pos, pktlen + extra_pad); pos += yahoo_put16(data + pos, pkt->service); @@ -1479,6 +1511,62 @@ 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) +{ + struct yahoo_data *yd = yid->yd; + YList *l; + int last_packet = 0; + char *cur_group = NULL; + struct yahoo_buddy *newbud = 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 300: + case 301: + case 302: + case 303: + if ( 315 == atoi(pair->value) ) + last_packet = 1; + break; + case 65: + cur_group = strdup(pair->value); + break; + case 7: + newbud = y_new0(struct yahoo_buddy, 1); + newbud->id = strdup(pair->value); + 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; + newbud->group = strdup(lastbud->group); + } + + yd->buddies = y_list_append(yd->buddies, newbud); + + break; + } + } + + /* we could be getting multiple packets here */ + if (last_packet) + return; + + YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies); + + + /*** We login at the very end of the packet communication */ + 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); + } +} + static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { struct yahoo_data *yd = yid->yd; @@ -1548,7 +1636,8 @@ static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet yd->cookie_c = getcookie(pair->value); } - if(yd->cookie_y && yd->cookie_t && yd->cookie_c) + // if(yd->cookie_y && yd->cookie_t && yd->cookie_c) + if(yd->cookie_y && yd->cookie_t) YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id); break; @@ -2225,6 +2314,22 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se free(crypt_hash); } +static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn) +{ + char *url; + + yid->yd->login_cookie = strdup(seed); + + url = g_strdup_printf( + "https://login.yahoo.com/config/pwtoken_get?" + "src=ymsgr&ts=&login=%s&passwd=%s&chal=%s", + yid->yd->user, yid->yd->password, seed); + + http_dorequest_url(url, yahoo_process_auth_response, yid); + + g_free(url); +} + static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { char *seed = NULL; @@ -2253,6 +2358,10 @@ static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet case 1: yahoo_process_auth_0x0b(yid, seed, sn); break; + case 2: + /* HTTPS */ + yahoo_process_auth_0x10(yid, seed, sn); + break; default: /* call error */ WARNING(("unknown auth type %d", m)); @@ -2660,6 +2769,8 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_GAMELOGOFF: case YAHOO_SERVICE_IDACT: case YAHOO_SERVICE_IDDEACT: + case YAHOO_SERVICE_Y6_STATUS_UPDATE: + case YAHOO_SERVICE_Y8_STATUS: yahoo_process_status(yid, pkt); break; case YAHOO_SERVICE_NOTIFY: @@ -2755,6 +2866,8 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_PICTURE_UPLOAD: yahoo_process_picture_upload(yid, pkt); break; + case YAHOO_SERVICE_Y8_LIST: /* Buddy List */ + yahoo_process_buddy_list(yid, pkt); default: WARNING(("unknown service 0x%02x", pkt->service)); yahoo_dump_unhandled(pkt); @@ -3531,6 +3644,189 @@ static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int ov && yahoo_get_webcam_data(yid) == 1); } +//#define LOG(x...) printf x + +static void yahoo_process_auth_response(struct http_request *req) +{ + char *line_end; + char *token; + char *cookie; + + int error_code = 0; + int is_ymsgr = 0; + + struct yahoo_data *yd = NULL; + struct yahoo_input_data *yid = req->data; + + unsigned char crypt_hash[25]; + + md5_byte_t result[16]; + md5_state_t ctx; + + struct yahoo_packet *packet =NULL; + + token = req->reply_body; + line_end = strstr(token, "\r\n"); + + if (line_end) { + *line_end = '\0'; + + line_end+=2; + } + + error_code = atoi((char *)token); + + switch(error_code) { + case 0: + /* successful */ + LOG(("successful\n")); + break; + case 1212: + /* Incorrect ID or password */ + LOG(("Incorrect ID or password\n")); + + return; + case 1213: + /* Security lock from too many failed login attempts */ + LOG(("Security lock from too many failed login attempts\n")); + + return; + + case 1214: + /* Security lock */ + LOG(("Security lock\n")); + + return; + + case 1235: + /* User ID not taken yet */ + LOG(("User ID not taken yet\n")); + + return; + + case 1216: + /* Seems to be a lock, but shows the same generic User ID/Password failure */ + LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n")); + + return; + case 100: + /* Username and password cannot be blank */ + LOG(("Username and password cannot be blank\n")); + + return; + default: + /* Unknown error code */ + LOG(("Unknown Error\n")); + + return; + } + + if ( !strncmp(line_end, "ymsgr=", 6) ) { + is_ymsgr = 1; + } + else if ( strncmp(line_end, "crumb=", 6) ) { + LOG(("Oops! There was no ymsgr=. Where do I get my token from now :(")); + LOG(("I got this:\n\n%s\n",line_end)); + return; + /* Error */ + } + + token = line_end+6; + + line_end = strstr(token, "\r\n"); + + if(line_end) { + *line_end = '\0'; + line_end+=2; + } + + /* Go for the crumb */ + if(is_ymsgr) { + char *url; + + url = g_strdup_printf( + "https://login.yahoo.com/config/pwtoken_login?" + "src=ymsgr&ts=&token=%s", token); + + http_dorequest_url(url, yahoo_process_auth_response, yid); + g_free(url); + + return; + } + + /* token is actually crumb */ + + if(!line_end) { + /* We did not get our cookies. Cry. */ + } + + cookie = strstr(req->reply_headers, "Set-Cookie: Y="); + + if(!cookie) { + /* Cry. */ + LOG(("NO Y Cookie!")); + return; + } + + cookie+=14; + + line_end = strstr(cookie, "\r\n"); + *line_end = '\0'; + + LOG(("Cookie length: %d", strlen(cookie))); + + yid->yd->cookie_y = strdup(cookie); + *line_end = ';'; + + cookie = strstr(req->reply_headers, "Set-Cookie: T="); + if(!cookie) { + LOG(("NO T Cookie!")); + /* Cry. */ + return; + } + + cookie+=14; + + line_end = strstr(cookie, "\r\n"); + *line_end = '\0'; + + yid->yd->cookie_t = strdup(cookie); + + LOG(("My Cookies ::\n Y: %s\nT: %s\n\n", yid->yd->cookie_y, yid->yd->cookie_t)); + + md5_init(&ctx); + md5_append(&ctx, (md5_byte_t *)token, strlen(token)); + md5_append(&ctx, (md5_byte_t *)yid->yd->login_cookie, strlen(yid->yd->login_cookie)); + md5_finish(&ctx, result); + + to_y64(crypt_hash, result, 16); + + yd = yid->yd; + + //yid = find_input_by_id_and_type(yd->client_id, YAHOO_CONNECTION_PAGER); + + packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id); + yahoo_packet_hash(packet, 1, yd->user); + yahoo_packet_hash(packet, 0, yd->user); + yahoo_packet_hash(packet, 277, yd->cookie_y); + yahoo_packet_hash(packet, 278, yd->cookie_t); + yahoo_packet_hash(packet, 307, crypt_hash); + yahoo_packet_hash(packet, 244, "2097087"); /* Rekkanoryo says this is the build number */ + yahoo_packet_hash(packet, 2, yd->user); + yahoo_packet_hash(packet, 2, "1"); + yahoo_packet_hash(packet, 98, "us"); /* TODO Put country code */ + yahoo_packet_hash(packet, 135, "9.0.0.1389"); + + yahoo_send_packet(yid, packet, 0); + + yahoo_packet_free(packet); + + /* We don't need this anymore */ + free(yd->login_cookie); + yd->login_cookie = NULL; +} + + static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = { yahoo_process_pager_connection, yahoo_process_ft_connection, @@ -3538,7 +3834,7 @@ static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = yahoo_process_webcam_master_connection, yahoo_process_webcam_connection, yahoo_process_chatcat_connection, - yahoo_process_search_connection + yahoo_process_search_connection, }; int yahoo_read_ready(int id, int fd, void *data) @@ -3556,7 +3852,7 @@ int yahoo_read_ready(int id, int fd, void *data) len = read(fd, buf, sizeof(buf)); } while(len == -1 && errno == EINTR); - if(len == -1 && errno == EAGAIN) /* we'll try again later */ + if(len == -1 && (errno == EAGAIN||errno == EINTR)) /* we'll try again later */ return 1; if (len <= 0) { @@ -4145,7 +4441,7 @@ void yahoo_stealth_buddy(int id, const char *who, int unstealth) if (!yd->logged_in) return; - pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id); + pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH_PERM, YAHOO_STATUS_AVAILABLE, yd->session_id); yahoo_packet_hash(pkt, 1, yd->user); yahoo_packet_hash(pkt, 7, who); yahoo_packet_hash(pkt, 31, unstealth?"2":"1"); diff --git a/protocols/yahoo/yahoo2_types.h b/protocols/yahoo/yahoo2_types.h index df1756eb..7453e487 100644 --- a/protocols/yahoo/yahoo2_types.h +++ b/protocols/yahoo/yahoo2_types.h @@ -84,7 +84,7 @@ enum yahoo_log_level { YAHOO_LOG_DEBUG }; -#define YAHOO_PROTO_VER 0x000b +#define YAHOO_PROTO_VER 0x0010 /* Yahoo style/color directives */ #define YAHOO_COLOR_BLACK "\033[30m" @@ -114,7 +114,8 @@ enum yahoo_connection_type { YAHOO_CONNECTION_WEBCAM_MASTER, YAHOO_CONNECTION_WEBCAM, YAHOO_CONNECTION_CHATCAT, - YAHOO_CONNECTION_SEARCH + YAHOO_CONNECTION_SEARCH, + YAHOO_CONNECTION_AUTH, }; enum yahoo_webcam_direction_type { -- cgit v1.2.3 From c3e349e0847b5b936d1040c56ea427a7f2ce0d7c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 3 Oct 2009 23:25:36 +0100 Subject: Cleaned up Yahoo! fix: Error handling, and also not crashing when the connection disappears again before authentication finishes. --- protocols/yahoo/libyahoo2.c | 143 ++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 77 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 52655240..deaa46df 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -92,9 +92,6 @@ char *strchr (), *strrchr (); static void yahoo_process_auth_response(struct http_request *req); -/* What's this used for actually? */ -static void _yahoo_http_connected(int id, int fd, int error, void *data); - #ifdef USE_STRUCT_CALLBACKS struct yahoo_callbacks *yc=NULL; @@ -1532,6 +1529,7 @@ static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_ last_packet = 1; break; case 65: + g_free(cur_group); cur_group = strdup(pair->value); break; case 7: @@ -1550,6 +1548,8 @@ static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_ break; } } + + g_free(cur_group); /* we could be getting multiple packets here */ if (last_packet) @@ -1557,7 +1557,6 @@ static void yahoo_process_buddy_list(struct yahoo_input_data *yid, struct yahoo_ YAHOO_CALLBACK(ext_yahoo_got_buddies)(yd->client_id, yd->buddies); - /*** We login at the very end of the packet communication */ if (!yd->logged_in) { yd->logged_in = TRUE; @@ -1636,7 +1635,6 @@ static void yahoo_process_list(struct yahoo_input_data *yid, struct yahoo_packet yd->cookie_c = getcookie(pair->value); } - // if(yd->cookie_y && yd->cookie_t && yd->cookie_c) if(yd->cookie_y && yd->cookie_t) YAHOO_CALLBACK(ext_yahoo_got_cookies)(yd->client_id); @@ -3644,7 +3642,7 @@ static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int ov && yahoo_get_webcam_data(yid) == 1); } -//#define LOG(x...) printf x +/* #define LOG(x...) printf x */ static void yahoo_process_auth_response(struct http_request *req) { @@ -3655,15 +3653,22 @@ static void yahoo_process_auth_response(struct http_request *req) int error_code = 0; int is_ymsgr = 0; - struct yahoo_data *yd = NULL; struct yahoo_input_data *yid = req->data; - unsigned char crypt_hash[25]; + char crypt_hash[25]; md5_byte_t result[16]; md5_state_t ctx; - struct yahoo_packet *packet =NULL; + struct yahoo_packet *packet = NULL; + + if (y_list_find(inputs, yid) == NULL) + return; + + if (req->status_code != 200) { + error_code = 3000 + req->status_code; + goto FAIL; + } token = req->reply_body; line_end = strstr(token, "\r\n"); @@ -3671,54 +3676,46 @@ static void yahoo_process_auth_response(struct http_request *req) if (line_end) { *line_end = '\0'; - line_end+=2; + line_end += 2; + } + + if (sscanf(token, "%d", &error_code) != 1) { + error_code = 3000; + goto FAIL; } - - error_code = atoi((char *)token); switch(error_code) { case 0: /* successful */ - LOG(("successful\n")); break; + case 1212: - /* Incorrect ID or password */ LOG(("Incorrect ID or password\n")); + error_code = YAHOO_LOGIN_PASSWD; + goto FAIL; - return; case 1213: - /* Security lock from too many failed login attempts */ LOG(("Security lock from too many failed login attempts\n")); - - return; + error_code = YAHOO_LOGIN_LOCK; + goto FAIL; case 1214: - /* Security lock */ LOG(("Security lock\n")); - - return; + goto FAIL; case 1235: - /* User ID not taken yet */ LOG(("User ID not taken yet\n")); - - return; + error_code = YAHOO_LOGIN_UNAME; + goto FAIL; case 1216: - /* Seems to be a lock, but shows the same generic User ID/Password failure */ LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n")); + goto FAIL; - return; - case 100: - /* Username and password cannot be blank */ - LOG(("Username and password cannot be blank\n")); - - return; default: /* Unknown error code */ LOG(("Unknown Error\n")); - - return; + goto FAIL; } if ( !strncmp(line_end, "ymsgr=", 6) ) { @@ -3727,8 +3724,8 @@ static void yahoo_process_auth_response(struct http_request *req) else if ( strncmp(line_end, "crumb=", 6) ) { LOG(("Oops! There was no ymsgr=. Where do I get my token from now :(")); LOG(("I got this:\n\n%s\n",line_end)); - return; - /* Error */ + error_code = 2201; + goto FAIL; } token = line_end+6; @@ -3737,7 +3734,7 @@ static void yahoo_process_auth_response(struct http_request *req) if(line_end) { *line_end = '\0'; - line_end+=2; + line_end += 2; } /* Go for the crumb */ @@ -3747,8 +3744,9 @@ static void yahoo_process_auth_response(struct http_request *req) url = g_strdup_printf( "https://login.yahoo.com/config/pwtoken_login?" "src=ymsgr&ts=&token=%s", token); - + http_dorequest_url(url, yahoo_process_auth_response, yid); + g_free(url); return; @@ -3760,59 +3758,45 @@ static void yahoo_process_auth_response(struct http_request *req) /* We did not get our cookies. Cry. */ } - cookie = strstr(req->reply_headers, "Set-Cookie: Y="); - - if(!cookie) { + if((cookie = strstr(req->reply_headers, "Set-Cookie: Y=")) && + (line_end = strstr(cookie + 14, "\r\n"))) { + *line_end = '\0'; + yid->yd->cookie_y = strdup(cookie + 14); + *line_end = ';'; + } else { /* Cry. */ LOG(("NO Y Cookie!")); - return; + error_code = 2202; + goto FAIL; } - cookie+=14; - - line_end = strstr(cookie, "\r\n"); - *line_end = '\0'; - - LOG(("Cookie length: %d", strlen(cookie))); - - yid->yd->cookie_y = strdup(cookie); - *line_end = ';'; - - cookie = strstr(req->reply_headers, "Set-Cookie: T="); - if(!cookie) { - LOG(("NO T Cookie!")); + if((cookie = strstr(req->reply_headers, "Set-Cookie: T=")) && + (line_end = strstr(cookie + 14, "\r\n"))) { + *line_end = '\0'; + yid->yd->cookie_t = strdup(cookie + 14); + *line_end = ';'; + } else { /* Cry. */ - return; + LOG(("NO T Cookie!")); + error_code = 2203; + goto FAIL; } - cookie+=14; - - line_end = strstr(cookie, "\r\n"); - *line_end = '\0'; - - yid->yd->cookie_t = strdup(cookie); - - LOG(("My Cookies ::\n Y: %s\nT: %s\n\n", yid->yd->cookie_y, yid->yd->cookie_t)); - md5_init(&ctx); md5_append(&ctx, (md5_byte_t *)token, strlen(token)); md5_append(&ctx, (md5_byte_t *)yid->yd->login_cookie, strlen(yid->yd->login_cookie)); md5_finish(&ctx, result); - to_y64(crypt_hash, result, 16); - - yd = yid->yd; + to_y64((unsigned char*)crypt_hash, result, 16); - //yid = find_input_by_id_and_type(yd->client_id, YAHOO_CONNECTION_PAGER); - - packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id); - yahoo_packet_hash(packet, 1, yd->user); - yahoo_packet_hash(packet, 0, yd->user); - yahoo_packet_hash(packet, 277, yd->cookie_y); - yahoo_packet_hash(packet, 278, yd->cookie_t); + packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yid->yd->initial_status, yid->yd->session_id); + yahoo_packet_hash(packet, 1, yid->yd->user); + yahoo_packet_hash(packet, 0, yid->yd->user); + yahoo_packet_hash(packet, 277, yid->yd->cookie_y); + yahoo_packet_hash(packet, 278, yid->yd->cookie_t); yahoo_packet_hash(packet, 307, crypt_hash); yahoo_packet_hash(packet, 244, "2097087"); /* Rekkanoryo says this is the build number */ - yahoo_packet_hash(packet, 2, yd->user); + yahoo_packet_hash(packet, 2, yid->yd->user); yahoo_packet_hash(packet, 2, "1"); yahoo_packet_hash(packet, 98, "us"); /* TODO Put country code */ yahoo_packet_hash(packet, 135, "9.0.0.1389"); @@ -3822,8 +3806,13 @@ static void yahoo_process_auth_response(struct http_request *req) yahoo_packet_free(packet); /* We don't need this anymore */ - free(yd->login_cookie); - yd->login_cookie = NULL; + free(yid->yd->login_cookie); + yid->yd->login_cookie = NULL; + + return; + +FAIL: + YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, error_code, NULL); } -- cgit v1.2.3 From bdad4079b4bbc8209bf17c81cafbf699f8c6d90d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 4 Oct 2009 19:28:41 +0100 Subject: Fixing a crash bug that causes crashes only with buggy Jabber conference servers, sending a "you left this chat" without first acknowledging you entering it. --- protocols/jabber/conference.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/protocols/jabber/conference.c b/protocols/jabber/conference.c index 08bef4f5..f434c58a 100644 --- a/protocols/jabber/conference.c +++ b/protocols/jabber/conference.c @@ -284,12 +284,15 @@ void jabber_chat_pkt_presence( struct im_connection *ic, struct jabber_buddy *bu } else if( type ) /* type can only be NULL or "unavailable" in this function */ { - s = strchr( bud->ext_jid, '/' ); - if( s ) *s = 0; - imcb_chat_remove_buddy( chat, bud->ext_jid, NULL ); - if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) - imcb_remove_buddy( ic, bud->ext_jid, NULL ); - if( s ) *s = '/'; + if( ( bud->flags & JBFLAG_IS_CHATROOM ) && bud->ext_jid ) + { + s = strchr( bud->ext_jid, '/' ); + if( s ) *s = 0; + imcb_chat_remove_buddy( chat, bud->ext_jid, NULL ); + if( bud != jc->me && bud->flags & JBFLAG_IS_ANONYMOUS ) + imcb_remove_buddy( ic, bud->ext_jid, NULL ); + if( s ) *s = '/'; + } if( bud == jc->me ) jabber_chat_free( chat ); -- cgit v1.2.3 From e59b4f65183a7bee638312a0c96e3d0607cb181f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 4 Oct 2009 20:00:53 +0100 Subject: Fixed embarassing early free() bug that sat in the WATCH command handling for *years*. I guess it took a while for IRC clients to actually use that functionality... --- irc_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irc_commands.c b/irc_commands.c index bdca5b24..044ff62c 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -414,8 +414,8 @@ static void irc_cmd_watch( irc_t *irc, char **cmd ) if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) ) { - g_free( okey ); g_hash_table_remove( irc->watches, okey ); + g_free( okey ); irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" ); } -- cgit v1.2.3 From fa295e3620bdf928b6a853ec7e42b8c7fc5262be Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 10 Oct 2009 14:39:51 +0100 Subject: Added imcb_ask_auth() instead of reimplementing authorization requests in every protocol module. --- protocols/nogaim.c | 61 +++++++++++++++++++++++++++++++++++++++++++----------- protocols/nogaim.h | 13 +++++++++++- user.c | 2 +- user.h | 2 +- 4 files changed, 63 insertions(+), 15 deletions(-) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index fd445324..710b7645 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -505,33 +505,70 @@ void imcb_buddy_nick_hint( struct im_connection *ic, char *handle, char *nick ) } } -/* prpl.c */ -struct show_got_added_data +struct imcb_ask_cb_data { struct im_connection *ic; char *handle; }; -void show_got_added_no( void *data ) +static void imcb_ask_auth_cb_no( void *data ) { - g_free( ((struct show_got_added_data*)data)->handle ); + struct imcb_ask_cb_data *cbd = data; + + cbd->ic->acc->prpl->auth_deny( cbd->ic, cbd->handle ); + + g_free( cbd->handle ); + g_free( cbd ); +} + +static void imcb_ask_auth_cb_yes( void *data ) +{ + struct imcb_ask_cb_data *cbd = data; + + cbd->ic->acc->prpl->auth_allow( cbd->ic, cbd->handle ); + + g_free( cbd->handle ); + g_free( cbd ); +} + +void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname ) +{ + struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 ); + char *s, *realname_ = NULL; + + if( realname != NULL ) + realname_ = g_strdup_printf( " (%s)", realname ); + + s = g_strdup_printf( "The user %s%s wants to add you to his/her buddy list.", + handle, realname_ ?: "" ); + + g_free( realname_ ); + + data->ic = ic; + data->handle = g_strdup( handle ); + query_add( ic->irc, ic, s, imcb_ask_auth_cb_yes, imcb_ask_auth_cb_no, data ); +} + + +static void imcb_ask_add_cb_no( void *data ) +{ + g_free( ((struct imcb_ask_cb_data*)data)->handle ); g_free( data ); } -void show_got_added_yes( void *data ) +static void imcb_ask_add_cb_yes( void *data ) { - struct show_got_added_data *sga = data; + struct imcb_ask_cb_data *cbd = data; - sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL ); - /* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */ + cbd->ic->acc->prpl->add_buddy( cbd->ic, cbd->handle, NULL ); - return show_got_added_no( data ); + return imcb_ask_add_cb_no( data ); } -void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ) +void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname ) { - struct show_got_added_data *data = g_new0( struct show_got_added_data, 1 ); + struct imcb_ask_cb_data *data = g_new0( struct imcb_ask_cb_data, 1 ); char *s; /* TODO: Make a setting for this! */ @@ -542,7 +579,7 @@ void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname data->ic = ic; data->handle = g_strdup( handle ); - query_add( ic->irc, ic, s, show_got_added_yes, show_got_added_no, data ); + query_add( ic->irc, ic, s, imcb_ask_add_cb_yes, imcb_ask_add_cb_no, data ); } diff --git a/protocols/nogaim.h b/protocols/nogaim.h index ddfff07e..1e5df503 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -223,6 +223,10 @@ struct prpl { /* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* * - Most protocols will just want to set this to g_strcasecmp().*/ int (* handle_cmp) (const char *who1, const char *who2); + + /* Implement these callbacks if you want to use imcb_ask_auth() */ + void (* auth_allow) (struct im_connection *, const char *who); + void (* auth_deny) (struct im_connection *, const char *who); }; /* im_api core stuff. */ @@ -251,13 +255,20 @@ G_MODULE_EXPORT void imc_logout( struct im_connection *ic, int allow_reconnect ) G_MODULE_EXPORT void imcb_log( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); /* To tell the user an error, ie. before logging out when an error occurs. */ G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G_GNUC_PRINTF( 2, 3 ); + /* To ask a your about something. * - 'msg' is the question. * - 'data' can be your custom struct - it will be passed to the callbacks. * - 'doit' or 'dont' will be called depending of the answer of the user. */ G_MODULE_EXPORT void imcb_ask( struct im_connection *ic, char *msg, void *data, query_callback doit, query_callback dont ); -G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ); + +/* Two common questions you may want to ask: + * - X added you to his contact list, allow? + * - X is not in your contact list, want to add? + */ +G_MODULE_EXPORT void imcb_ask_auth( struct im_connection *ic, const char *handle, const char *realname ); +G_MODULE_EXPORT void imcb_ask_add( struct im_connection *ic, const char *handle, const char *realname ); /* Buddy management */ /* This function should be called for each handle which are visible to the diff --git a/user.c b/user.c index 26676dd4..4d58f56b 100644 --- a/user.c +++ b/user.c @@ -140,7 +140,7 @@ user_t *user_find( irc_t *irc, char *nick ) return( NULL ); } -user_t *user_findhandle( struct im_connection *ic, char *handle ) +user_t *user_findhandle( struct im_connection *ic, const char *handle ) { user_t *u; char *nick; diff --git a/user.h b/user.h index c6b933bc..9d8a41a0 100644 --- a/user.h +++ b/user.h @@ -55,7 +55,7 @@ typedef struct __USER user_t *user_add( struct irc *irc, char *nick ); int user_del( irc_t *irc, char *nick ); G_MODULE_EXPORT user_t *user_find( irc_t *irc, char *nick ); -G_MODULE_EXPORT user_t *user_findhandle( struct im_connection *ic, char *handle ); +G_MODULE_EXPORT user_t *user_findhandle( struct im_connection *ic, const char *handle ); void user_rename( irc_t *irc, char *oldnick, char *newnick ); #endif /* __USER_H__ */ -- cgit v1.2.3 From ba168953ffe832133cf236df73e574fa54f8d911 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 10 Oct 2009 14:48:44 +0100 Subject: More Yahoo! fixes: Adding and removing buddies works, and for the first time buddy add requests are actually handled; from what I can see this simply didn't exist in libyahoo2 yet so far. :-( I melded pieces of changes from http://geny.sf.net/ to make this stuff work. --- protocols/yahoo/libyahoo2.c | 147 ++++++++++++++++++++++++++++--------- protocols/yahoo/yahoo.c | 30 +++++++- protocols/yahoo/yahoo2.h | 3 + protocols/yahoo/yahoo2_callbacks.h | 12 +++ protocols/yahoo/yahoo2_types.h | 16 +++- 5 files changed, 167 insertions(+), 41 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index deaa46df..d6cab9e1 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -211,33 +211,23 @@ enum yahoo_service { /* these are easier to see in hex */ YAHOO_SERVICE_CHATLOGOUT = 0xa0, YAHOO_SERVICE_CHATPING, YAHOO_SERVICE_COMMENT = 0xa8, - YAHOO_SERVICE_GAME_INVITE = 0xb7, - YAHOO_SERVICE_STEALTH_PERM = 0xb9, - YAHOO_SERVICE_STEALTH_SESSION = 0xba, - YAHOO_SERVICE_AVATAR = 0xbc, + YAHOO_SERVICE_STEALTH = 0xb9, YAHOO_SERVICE_PICTURE_CHECKSUM = 0xbd, YAHOO_SERVICE_PICTURE = 0xbe, YAHOO_SERVICE_PICTURE_UPDATE = 0xc1, YAHOO_SERVICE_PICTURE_UPLOAD = 0xc2, - YAHOO_SERVICE_YAB_UPDATE = 0xc4, - YAHOO_SERVICE_Y6_VISIBLE_TOGGLE = 0xc5, /* YMSG13, key 13: 2 = invisible, 1 = visible */ - YAHOO_SERVICE_Y6_STATUS_UPDATE = 0xc6, /* YMSG13 */ - YAHOO_SERVICE_PICTURE_STATUS = 0xc7, /* YMSG13, key 213: 0 = none, 1 = avatar, 2 = picture */ - YAHOO_SERVICE_VERIFY_ID_EXISTS = 0xc8, - YAHOO_SERVICE_AUDIBLE = 0xd0, - YAHOO_SERVICE_Y7_PHOTO_SHARING = 0xd2, - YAHOO_SERVICE_Y7_CONTACT_DETAILS = 0xd3,/* YMSG13 */ - YAHOO_SERVICE_Y7_CHAT_SESSION = 0xd4, - YAHOO_SERVICE_Y7_AUTHORIZATION = 0xd6, /* YMSG13 */ - YAHOO_SERVICE_Y7_FILETRANSFER = 0xdc, /* YMSG13 */ - YAHOO_SERVICE_Y7_FILETRANSFERINFO, /* YMSG13 */ - YAHOO_SERVICE_Y7_FILETRANSFERACCEPT, /* YMSG13 */ - YAHOO_SERVICE_Y7_MINGLE = 0xe1, /* YMSG13 */ - YAHOO_SERVICE_Y7_CHANGE_GROUP = 0xe7, /* YMSG13 */ - YAHOO_SERVICE_Y8_STATUS = 0xf0, /* YMSG15 */ - YAHOO_SERVICE_Y8_LIST = 0Xf1, /* YMSG15 */ - YAHOO_SERVICE_WEBLOGIN = 0x0226, - YAHOO_SERVICE_SMS_MSG = 0x02ea + YAHOO_SERVICE_Y6_VISIBILITY=0xc5, + YAHOO_SERVICE_Y6_STATUS_UPDATE=0xc6, + YAHOO_PHOTOSHARE_INIT=0xd2, + YAHOO_SERVICE_CONTACT_YMSG13=0xd6, + YAHOO_PHOTOSHARE_PREV=0xd7, + YAHOO_PHOTOSHARE_KEY=0xd8, + YAHOO_PHOTOSHARE_TRANS=0xda, + YAHOO_FILE_TRANSFER_INIT_YMSG13=0xdc, + YAHOO_FILE_TRANSFER_GET_YMSG13=0xdd, + YAHOO_FILE_TRANSFER_PUT_YMSG13=0xde, + YAHOO_SERVICE_YMSG15_STATUS=0xf0, + YAHOO_SERVICE_YMSG15_BUDDY_LIST=0xf1, }; struct yahoo_pair { @@ -775,7 +765,7 @@ static void yahoo_send_packet(struct yahoo_input_data *yid, struct yahoo_packet if( yid->type == YAHOO_CONNECTION_FT ) yahoo_send_data(yid->fd, data, len); else - yahoo_add_to_send_queue(yid, data, len); + yahoo_add_to_send_queue(yid, data, len); FREE(data); } @@ -1495,9 +1485,15 @@ static void yahoo_process_status(struct yahoo_input_data *yid, struct yahoo_pack struct user *u = users->data; if (u->name != NULL) { - if (pkt->service == YAHOO_SERVICE_LOGOFF || u->flags == 0) { + 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); } else { + /* Key 47 always seems to be 1 for YMSG16 */ + 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); } } @@ -2514,7 +2510,7 @@ static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_pa bud->real_name = NULL; yd->buddies = y_list_append(yd->buddies, bud); - + /* Possibly called already, but at least the call above doesn't seem to happen every time (not anytime I tried). */ YAHOO_CALLBACK(ext_yahoo_contact_added)(yd->client_id, me, who, NULL); @@ -2523,6 +2519,26 @@ static void yahoo_process_buddyadd(struct yahoo_input_data *yid, struct yahoo_pa /* YAHOO_CALLBACK(ext_yahoo_status_changed)(yd->client_id, who, status, NULL, (status==YAHOO_STATUS_AVAILABLE?0:1)); */ } +static void yahoo_process_contact_ymsg13(struct yahoo_input_data *yid, struct yahoo_packet *pkt) +{ + char* who=NULL; + char* me=NULL; + char* msg=NULL; + YList *l; + for (l = pkt->hash; l; l = l->next) { + struct yahoo_pair *pair = l->data; + if (pair->key == 4) + who = pair->value; + else if (pair->key == 5) + me = pair->value; + else + DEBUG_MSG(("unknown key: %d = %s", pair->key, pair->value)); + } + + if(pkt->status==3) + YAHOO_CALLBACK(ext_yahoo_contact_auth_request)(yid->yd->client_id, me, who, msg); +} + static void yahoo_process_buddydel(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { struct yahoo_data *yd = yid->yd; @@ -2734,7 +2750,7 @@ static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_ char *who = NULL; YList *l; - yahoo_dump_unhandled(pkt); + // yahoo_dump_unhandled(pkt); for (l = pkt->hash; l; l = l->next) { struct yahoo_pair *pair = l->data; if (pair->key == 5) @@ -2756,6 +2772,7 @@ static void yahoo_process_webcam_key(struct yahoo_input_data *yid, struct yahoo_ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { DEBUG_MSG(("yahoo_packet_process: 0x%02x", pkt->service)); + yahoo_dump_unhandled(pkt); switch (pkt->service) { case YAHOO_SERVICE_USERSTAT: @@ -2768,7 +2785,7 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_IDACT: case YAHOO_SERVICE_IDDEACT: case YAHOO_SERVICE_Y6_STATUS_UPDATE: - case YAHOO_SERVICE_Y8_STATUS: + case YAHOO_SERVICE_YMSG15_STATUS: yahoo_process_status(yid, pkt); break; case YAHOO_SERVICE_NOTIFY: @@ -2782,6 +2799,7 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_NEWMAIL: yahoo_process_mail(yid, pkt); break; + case YAHOO_SERVICE_REJECTCONTACT: case YAHOO_SERVICE_NEWCONTACT: yahoo_process_contact(yid, pkt); break; @@ -2822,6 +2840,9 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_ADDBUDDY: yahoo_process_buddyadd(yid, pkt); break; + case YAHOO_SERVICE_CONTACT_YMSG13: + yahoo_process_contact_ymsg13(yid,pkt); + break; case YAHOO_SERVICE_REMBUDDY: yahoo_process_buddydel(yid, pkt); break; @@ -2850,7 +2871,6 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_CHATLOGON: case YAHOO_SERVICE_CHATLOGOFF: case YAHOO_SERVICE_CHATMSG: - case YAHOO_SERVICE_REJECTCONTACT: case YAHOO_SERVICE_PEERTOPEER: WARNING(("unhandled service 0x%02x", pkt->service)); yahoo_dump_unhandled(pkt); @@ -2864,7 +2884,7 @@ static void yahoo_packet_process(struct yahoo_input_data *yid, struct yahoo_pack case YAHOO_SERVICE_PICTURE_UPLOAD: yahoo_process_picture_upload(yid, pkt); break; - case YAHOO_SERVICE_Y8_LIST: /* Buddy List */ + case YAHOO_SERVICE_YMSG15_BUDDY_LIST: /* Buddy List */ yahoo_process_buddy_list(yid, pkt); default: WARNING(("unknown service 0x%02x", pkt->service)); @@ -4044,7 +4064,7 @@ void yahoo_send_typing(int id, const char *from, const char *who, int typ) pkt = yahoo_packet_new(YAHOO_SERVICE_NOTIFY, YAHOO_STATUS_NOTIFY, yd->session_id); yahoo_packet_hash(pkt, 5, who); - yahoo_packet_hash(pkt, 4, from?from:yd->user); + yahoo_packet_hash(pkt, 1, from?from:yd->user); yahoo_packet_hash(pkt, 14, " "); yahoo_packet_hash(pkt, 13, typ ? "1" : "0"); yahoo_packet_hash(pkt, 49, "TYPING"); @@ -4346,12 +4366,24 @@ void yahoo_add_buddy(int id, const char *who, const char *group, const char *msg if (!yd->logged_in) return; - pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YAHOO_STATUS_AVAILABLE, yd->session_id); - yahoo_packet_hash(pkt, 1, yd->user); - yahoo_packet_hash(pkt, 7, who); - yahoo_packet_hash(pkt, 65, group); + pkt = yahoo_packet_new(YAHOO_SERVICE_ADDBUDDY, YPACKET_STATUS_DEFAULT, yd->session_id); + if (msg != NULL) /* add message/request "it's me add me" */ yahoo_packet_hash(pkt, 14, msg); + else + yahoo_packet_hash(pkt,14,""); + + yahoo_packet_hash(pkt, 65, group); + yahoo_packet_hash(pkt, 97, "1"); + yahoo_packet_hash(pkt, 1, yd->user); + yahoo_packet_hash(pkt, 302, "319"); + yahoo_packet_hash(pkt, 300, "319"); + yahoo_packet_hash(pkt, 7, who); + yahoo_packet_hash(pkt, 334, "0"); + yahoo_packet_hash(pkt, 301, "319"); + yahoo_packet_hash(pkt, 303, "319"); + + yahoo_send_packet(yid, pkt, 0); yahoo_packet_free(pkt); } @@ -4375,6 +4407,49 @@ void yahoo_remove_buddy(int id, const char *who, const char *group) yahoo_packet_free(pkt); } +void yahoo_accept_buddy_ymsg13(int id,const char* me,const char* who){ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + + if(!yid) + return; + yd = yid->yd; + + struct yahoo_packet* pkt=NULL; + pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0); + + yahoo_packet_hash(pkt,1,me ?: yd->user); + yahoo_packet_hash(pkt,5,who); + yahoo_packet_hash(pkt,13,"1"); + yahoo_packet_hash(pkt,334,"0"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); +} + +void yahoo_reject_buddy_ymsg13(int id,const char* me,const char* who,const char* msg){ + struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); + struct yahoo_data *yd; + + if(!yid) + return; + yd = yid->yd; + + struct yahoo_packet* pkt=NULL; + pkt= yahoo_packet_new(YAHOO_SERVICE_CONTACT_YMSG13,YAHOO_STATUS_AVAILABLE,0); + + yahoo_packet_hash(pkt,1,me ?: yd->user); + yahoo_packet_hash(pkt,5,who); +// yahoo_packet_hash(pkt,241,YAHOO_PROTO_VER); + yahoo_packet_hash(pkt,13,"2"); + yahoo_packet_hash(pkt,334,"0"); + yahoo_packet_hash(pkt,97,"1"); + yahoo_packet_hash(pkt,14,msg?:""); + + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); + +} + void yahoo_reject_buddy(int id, const char *who, const char *msg) { struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); @@ -4430,7 +4505,7 @@ void yahoo_stealth_buddy(int id, const char *who, int unstealth) if (!yd->logged_in) return; - pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH_PERM, YAHOO_STATUS_AVAILABLE, yd->session_id); + pkt = yahoo_packet_new(YAHOO_SERVICE_STEALTH, YAHOO_STATUS_AVAILABLE, yd->session_id); yahoo_packet_hash(pkt, 1, yd->user); yahoo_packet_hash(pkt, 7, who); yahoo_packet_hash(pkt, 31, unstealth?"2":"1"); diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 3e844c55..ea1b4dec 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -347,6 +347,20 @@ static struct groupchat *byahoo_chat_with( struct im_connection *ic, char *who ) return c; } +static void byahoo_auth_allow( struct im_connection *ic, const char *who ) +{ + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; + + yahoo_accept_buddy_ymsg13( yd->y2_id, NULL, who ); +} + +static void byahoo_auth_deny( struct im_connection *ic, const char *who ) +{ + struct byahoo_data *yd = (struct byahoo_data *) ic->proto_data; + + yahoo_reject_buddy_ymsg13( yd->y2_id, NULL, who, NULL ); +} + void byahoo_initmodule( ) { struct prpl *ret = g_new0(struct prpl, 1); @@ -372,6 +386,9 @@ void byahoo_initmodule( ) ret->handle_cmp = g_strcasecmp; + ret->auth_allow = byahoo_auth_allow; + ret->auth_deny = byahoo_auth_deny; + register_protocol(ret); } @@ -921,11 +938,18 @@ void ext_yahoo_chat_yahooerror( int id, const char *me ) { } +void ext_yahoo_contact_auth_request( int id, const char *myid, const char *who, const char *msg ) +{ + struct im_connection *ic = byahoo_get_ic_by_id( id ); + + imcb_ask_auth( ic, who, NULL ); +} + void ext_yahoo_contact_added( int id, const char *myid, const char *who, const char *msg ) { - /* Groups schmoups. If I want to handle groups properly I can get the - buddy data from some internal libyahoo2 structure. */ - imcb_add_buddy( byahoo_get_ic_by_id( id ), (char*) who, NULL ); + struct im_connection *ic = byahoo_get_ic_by_id( id ); + + imcb_add_buddy( ic, (char*) who, NULL ); } void ext_yahoo_rejected( int id, const char *who, const char *msg ) diff --git a/protocols/yahoo/yahoo2.h b/protocols/yahoo/yahoo2.h index e54e09fb..2184a321 100644 --- a/protocols/yahoo/yahoo2.h +++ b/protocols/yahoo/yahoo2.h @@ -216,6 +216,9 @@ const char * yahoo_get_profile_url( void ); void yahoo_buddyicon_request(int id, const char *who); +void yahoo_accept_buddy_ymsg13(int,const char*,const char*); +void yahoo_reject_buddy_ymsg13(int,const char*,const char*,const char*); + #include "yahoo_httplib.h" #ifdef __cplusplus diff --git a/protocols/yahoo/yahoo2_callbacks.h b/protocols/yahoo/yahoo2_callbacks.h index b7f4e99b..e2c8ea42 100644 --- a/protocols/yahoo/yahoo2_callbacks.h +++ b/protocols/yahoo/yahoo2_callbacks.h @@ -359,6 +359,18 @@ void YAHOO_CALLBACK_TYPE(ext_yahoo_conf_message)(int id, const char *me, const c void YAHOO_CALLBACK_TYPE(ext_yahoo_got_file)(int id, const char *me, const char *who, const char *url, long expires, const char *msg, const char *fname, unsigned long fesize); +/* + * Name: ext_yahoo_contact_auth_request + * Called when a contact wants to add you to his/her contact list + * Params: + * id - the id that identifies the server connection + * myid - the identity s/he added + * who - who did it + * msg - any message sent + */ +void YAHOO_CALLBACK_TYPE(ext_yahoo_contact_auth_request)(int id, const char *myid, const char *who, const char *msg); + + /* * Name: ext_yahoo_contact_added * Called when a contact is added to your list diff --git a/protocols/yahoo/yahoo2_types.h b/protocols/yahoo/yahoo2_types.h index 7453e487..3507e13a 100644 --- a/protocols/yahoo/yahoo2_types.h +++ b/protocols/yahoo/yahoo2_types.h @@ -56,7 +56,20 @@ enum yahoo_login_status { YAHOO_LOGIN_PASSWD = 13, YAHOO_LOGIN_LOCK = 14, YAHOO_LOGIN_DUPL = 99, - YAHOO_LOGIN_SOCK = -1 + YAHOO_LOGIN_SOCK = -1, +}; + +enum ypacket_status { + YPACKET_STATUS_DISCONNECTED = -1, + YPACKET_STATUS_DEFAULT = 0, + YPACKET_STATUS_SERVERACK = 1, + YPACKET_STATUS_GAME = 0x2, + YPACKET_STATUS_AWAY = 0x4, + YPACKET_STATUS_CONTINUED = 0x5, + YPACKET_STATUS_INVISIBLE = 12, + YPACKET_STATUS_NOTIFY = 0x16, /* TYPING */ + YPACKET_STATUS_WEBLOGIN = 0x5a55aa55, + YPACKET_STATUS_OFFLINE = 0x5a55aa56 }; enum yahoo_error { @@ -132,7 +145,6 @@ enum yahoo_stealth_visibility_type { /* chat member attribs */ #define YAHOO_CHAT_MALE 0x8000 #define YAHOO_CHAT_FEMALE 0x10000 -#define YAHOO_CHAT_FEMALE 0x10000 #define YAHOO_CHAT_DUNNO 0x400 #define YAHOO_CHAT_WEBCAM 0x10 -- cgit v1.2.3 From 037b66a34beef59e7c591ee868516f2305cea906 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 10 Oct 2009 15:57:05 +0100 Subject: Fixed an ugly bug in the write handler that may have caused many weird bugs for a while already by only sending one packet even if more of them were generated during an event cycle. --- protocols/yahoo/yahoo.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index ea1b4dec..96f619ed 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -468,9 +468,7 @@ gboolean byahoo_write_ready_callback( gpointer data, gint source, b_input_condit { struct byahoo_write_ready_data *d = data; - yahoo_write_ready( d->id, d->fd, d->data ); - - return FALSE; + return yahoo_write_ready( d->id, d->fd, d->data ); } void ext_yahoo_login_response( int id, int succ, const char *url ) -- cgit v1.2.3 From 7ea8697c345d5d1e3f237a392b293abca948cdfa Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 10 Oct 2009 16:00:16 +0100 Subject: Setting Yahoo! away states works again. --- protocols/yahoo/libyahoo2.c | 53 +++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index d6cab9e1..e7005e38 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -4079,7 +4079,7 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away) struct yahoo_input_data *yid = find_input_by_id_and_type(id, YAHOO_CONNECTION_PAGER); struct yahoo_data *yd; struct yahoo_packet *pkt = NULL; - int service; + int old_status; char s[4]; if(!yid) @@ -4087,38 +4087,45 @@ void yahoo_set_away(int id, enum yahoo_status state, const char *msg, int away) yd = yid->yd; - if (msg) { + old_status = yd->current_status; + + if (msg && strncmp(msg,"Invisible",9)) { yd->current_status = YAHOO_STATUS_CUSTOM; } else { yd->current_status = state; } - if (yd->current_status == YAHOO_STATUS_AVAILABLE) - service = YAHOO_SERVICE_ISBACK; - else - service = YAHOO_SERVICE_ISAWAY; + /* Thank you libpurple :) */ + if (yd->current_status == YAHOO_STATUS_INVISIBLE) { + pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 13, "2"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); + + return; + } + + 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 ((away == 2) && (yd->current_status == YAHOO_STATUS_AVAILABLE)) { - pkt = yahoo_packet_new(YAHOO_SERVICE_ISAWAY, YAHOO_STATUS_BRB, yd->session_id); - yahoo_packet_hash(pkt, 10, "999"); - yahoo_packet_hash(pkt, 47, "2"); - }else { - pkt = yahoo_packet_new(service, YAHOO_STATUS_AVAILABLE, 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); - yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); - } else { - yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); - } - - - + if (yd->current_status == YAHOO_STATUS_CUSTOM) { + yahoo_packet_hash(pkt, 19, msg); + } else { + yahoo_packet_hash(pkt, 19, ""); } + + yahoo_packet_hash(pkt, 47, (away == 2)? "2": (away) ?"1":"0"); yahoo_send_packet(yid, pkt, 0); yahoo_packet_free(pkt); + + if(old_status == YAHOO_STATUS_INVISIBLE) { + pkt = yahoo_packet_new(YAHOO_SERVICE_Y6_VISIBILITY, YAHOO_STATUS_AVAILABLE, 0); + yahoo_packet_hash(pkt, 13, "1"); + yahoo_send_packet(yid, pkt, 0); + yahoo_packet_free(pkt); + } } void yahoo_logoff(int id) -- cgit v1.2.3 From e71cfbc35f3d2f3aa4da9e72776505d945429cbe Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 13 Oct 2009 23:33:12 +0100 Subject: Turns out I *did* implement HTTPS auth for Yahoo! myself already, but I kept it as a patch somewhere in my homedir because I thought I didn't need it. I like this code more so I'll use it instead. --- protocols/yahoo/libyahoo2.c | 362 ++++++++++++++++++++++---------------------- 1 file changed, 178 insertions(+), 184 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index e7005e38..1d943df7 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -90,8 +90,6 @@ char *strchr (), *strrchr (); #include "base64.h" #include "http_client.h" -static void yahoo_process_auth_response(struct http_request *req); - #ifdef USE_STRUCT_CALLBACKS struct yahoo_callbacks *yc=NULL; @@ -2308,22 +2306,193 @@ static void yahoo_process_auth_0x0b(struct yahoo_input_data *yid, const char *se free(crypt_hash); } +struct yahoo_https_auth_data +{ + struct yahoo_input_data *yid; + char *token; + char *chal; +}; + +static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had); +static void yahoo_https_auth_token_finish(struct http_request *req); +static void yahoo_https_auth_init(struct yahoo_https_auth_data *had); +static void yahoo_https_auth_finish(struct http_request *req); + +/* Extract a value from a login.yahoo.com response. Assume CRLF-linebreaks + and FAIL miserably if they're not there... */ +static char *yahoo_ha_find_key(char *response, char *key) +{ + char *s, *end; + int len = strlen(key); + + s = response; + do { + if (strncmp(s, key, len) == 0 && s[len] == '=') { + s += len + 1; + if ((end = strchr(s, '\r'))) + return g_strndup(s, end - s); + else + return g_strdup(s); + } + + if ((s = strchr(s, '\n'))) + s ++; + } while (s && *s); + + return NULL; +} + +static enum yahoo_status yahoo_https_status_parse(int code) +{ + switch (code) + { + case 1212: return YAHOO_LOGIN_PASSWD; + case 1213: return YAHOO_LOGIN_LOCK; + case 1235: return YAHOO_LOGIN_UNAME; + default: return (enum yahoo_status) code; + } +} + static void yahoo_process_auth_0x10(struct yahoo_input_data *yid, const char *seed, const char *sn) { - char *url; + struct yahoo_https_auth_data *had = g_new0(struct yahoo_https_auth_data, 1); + + had->yid = yid; + had->chal = g_strdup(seed); + + yahoo_https_auth_token_init(had); +} - yid->yd->login_cookie = strdup(seed); +static void yahoo_https_auth_token_init(struct yahoo_https_auth_data *had) +{ + struct yahoo_input_data *yid = had->yid; + struct yahoo_data *yd = yid->yd; + struct http_request *req; + char *login, *passwd, *chal; + char *url; + + login = g_strndup(yd->user, 3 * strlen(yd->user)); + http_encode(login); + passwd = g_strndup(yd->password, 3 * strlen(yd->password)); + http_encode(passwd); + chal = g_strndup(had->chal, 3 * strlen(had->chal)); + http_encode(chal); + + url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_get?src=ymsgr&ts=%d&login=%s&passwd=%s&chal=%s", + (int) time(NULL), login, passwd, chal); + + req = http_dorequest_url(url, yahoo_https_auth_token_finish, had); + + g_free(url); + g_free(chal); + g_free(passwd); + g_free(login); +} - url = g_strdup_printf( - "https://login.yahoo.com/config/pwtoken_get?" - "src=ymsgr&ts=&login=%s&passwd=%s&chal=%s", - yid->yd->user, yid->yd->password, seed); +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; + int st; + + if (req->status_code != 200) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL); + goto fail; + } + + if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL); + goto fail; + } + + if ((had->token = yahoo_ha_find_key(req->reply_body, "ymsgr")) == NULL) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3001, NULL); + goto fail; + } + + return yahoo_https_auth_init(had); + +fail: + g_free(had->token); + g_free(had->chal); + g_free(had); +} - http_dorequest_url(url, yahoo_process_auth_response, yid); +static void yahoo_https_auth_init(struct yahoo_https_auth_data *had) +{ + struct http_request *req; + char *url; + + url = g_strdup_printf("https://login.yahoo.com/config/pwtoken_login?src=ymsgr&ts=%d&token=%s", + (int) time(NULL), had->token); + + req = http_dorequest_url(url, yahoo_https_auth_finish, had); g_free(url); } +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_packet *pack; + char *crumb; + int st; + + md5_byte_t result[16]; + md5_state_t ctx; + + unsigned char yhash[32]; + + if (req->status_code != 200) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 2000 + req->status_code, NULL); + goto fail; + } + + if (sscanf(req->reply_body, "%d", &st) != 1 || st != 0) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, yahoo_https_status_parse(st), NULL); + goto fail; + } + + if ((yd->cookie_y = yahoo_ha_find_key(req->reply_body, "Y")) == NULL || + (yd->cookie_t = yahoo_ha_find_key(req->reply_body, "T")) == NULL || + (crumb = yahoo_ha_find_key(req->reply_body, "crumb")) == NULL) { + YAHOO_CALLBACK(ext_yahoo_login_response)(yd->client_id, 3002, NULL); + goto fail; + } + + md5_init(&ctx); + md5_append(&ctx, (unsigned char*) crumb, 11); + md5_append(&ctx, (unsigned char*) had->chal, strlen(had->chal)); + md5_finish(&ctx, result); + to_y64(yhash, result, 16); + + pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yd->initial_status, yd->session_id); + yahoo_packet_hash(pack, 1, yd->user); + yahoo_packet_hash(pack, 0, yd->user); + yahoo_packet_hash(pack, 277, yd->cookie_y); + yahoo_packet_hash(pack, 278, yd->cookie_t); + yahoo_packet_hash(pack, 307, (char*) yhash); + yahoo_packet_hash(pack, 244, "524223"); + yahoo_packet_hash(pack, 2, yd->user); + yahoo_packet_hash(pack, 2, "1"); + yahoo_packet_hash(pack, 98, "us"); + yahoo_packet_hash(pack, 135, "7.5.0.647"); + + yahoo_send_packet(yid, pack, 0); + + yahoo_packet_free(pack); + + return; + +fail: + g_free(had->token); + g_free(had->chal); + g_free(had); +} + static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet *pkt) { char *seed = NULL; @@ -2353,7 +2522,6 @@ static void yahoo_process_auth(struct yahoo_input_data *yid, struct yahoo_packet yahoo_process_auth_0x0b(yid, seed, sn); break; case 2: - /* HTTPS */ yahoo_process_auth_0x10(yid, seed, sn); break; default: @@ -3662,180 +3830,6 @@ static void yahoo_process_webcam_connection(struct yahoo_input_data *yid, int ov && yahoo_get_webcam_data(yid) == 1); } -/* #define LOG(x...) printf x */ - -static void yahoo_process_auth_response(struct http_request *req) -{ - char *line_end; - char *token; - char *cookie; - - int error_code = 0; - int is_ymsgr = 0; - - struct yahoo_input_data *yid = req->data; - - char crypt_hash[25]; - - md5_byte_t result[16]; - md5_state_t ctx; - - struct yahoo_packet *packet = NULL; - - if (y_list_find(inputs, yid) == NULL) - return; - - if (req->status_code != 200) { - error_code = 3000 + req->status_code; - goto FAIL; - } - - token = req->reply_body; - line_end = strstr(token, "\r\n"); - - if (line_end) { - *line_end = '\0'; - - line_end += 2; - } - - if (sscanf(token, "%d", &error_code) != 1) { - error_code = 3000; - goto FAIL; - } - - switch(error_code) { - case 0: - /* successful */ - break; - - case 1212: - LOG(("Incorrect ID or password\n")); - error_code = YAHOO_LOGIN_PASSWD; - goto FAIL; - - case 1213: - LOG(("Security lock from too many failed login attempts\n")); - error_code = YAHOO_LOGIN_LOCK; - goto FAIL; - - case 1214: - LOG(("Security lock\n")); - goto FAIL; - - case 1235: - LOG(("User ID not taken yet\n")); - error_code = YAHOO_LOGIN_UNAME; - goto FAIL; - - case 1216: - LOG(("Seems to be a lock, but shows the same generic User ID/Password failure\n")); - goto FAIL; - - default: - /* Unknown error code */ - LOG(("Unknown Error\n")); - goto FAIL; - } - - if ( !strncmp(line_end, "ymsgr=", 6) ) { - is_ymsgr = 1; - } - else if ( strncmp(line_end, "crumb=", 6) ) { - LOG(("Oops! There was no ymsgr=. Where do I get my token from now :(")); - LOG(("I got this:\n\n%s\n",line_end)); - error_code = 2201; - goto FAIL; - } - - token = line_end+6; - - line_end = strstr(token, "\r\n"); - - if(line_end) { - *line_end = '\0'; - line_end += 2; - } - - /* Go for the crumb */ - if(is_ymsgr) { - char *url; - - url = g_strdup_printf( - "https://login.yahoo.com/config/pwtoken_login?" - "src=ymsgr&ts=&token=%s", token); - - http_dorequest_url(url, yahoo_process_auth_response, yid); - - g_free(url); - - return; - } - - /* token is actually crumb */ - - if(!line_end) { - /* We did not get our cookies. Cry. */ - } - - if((cookie = strstr(req->reply_headers, "Set-Cookie: Y=")) && - (line_end = strstr(cookie + 14, "\r\n"))) { - *line_end = '\0'; - yid->yd->cookie_y = strdup(cookie + 14); - *line_end = ';'; - } else { - /* Cry. */ - LOG(("NO Y Cookie!")); - error_code = 2202; - goto FAIL; - } - - if((cookie = strstr(req->reply_headers, "Set-Cookie: T=")) && - (line_end = strstr(cookie + 14, "\r\n"))) { - *line_end = '\0'; - yid->yd->cookie_t = strdup(cookie + 14); - *line_end = ';'; - } else { - /* Cry. */ - LOG(("NO T Cookie!")); - error_code = 2203; - goto FAIL; - } - - md5_init(&ctx); - md5_append(&ctx, (md5_byte_t *)token, strlen(token)); - md5_append(&ctx, (md5_byte_t *)yid->yd->login_cookie, strlen(yid->yd->login_cookie)); - md5_finish(&ctx, result); - - to_y64((unsigned char*)crypt_hash, result, 16); - - packet = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, yid->yd->initial_status, yid->yd->session_id); - yahoo_packet_hash(packet, 1, yid->yd->user); - yahoo_packet_hash(packet, 0, yid->yd->user); - yahoo_packet_hash(packet, 277, yid->yd->cookie_y); - yahoo_packet_hash(packet, 278, yid->yd->cookie_t); - yahoo_packet_hash(packet, 307, crypt_hash); - yahoo_packet_hash(packet, 244, "2097087"); /* Rekkanoryo says this is the build number */ - yahoo_packet_hash(packet, 2, yid->yd->user); - yahoo_packet_hash(packet, 2, "1"); - yahoo_packet_hash(packet, 98, "us"); /* TODO Put country code */ - yahoo_packet_hash(packet, 135, "9.0.0.1389"); - - yahoo_send_packet(yid, packet, 0); - - yahoo_packet_free(packet); - - /* We don't need this anymore */ - free(yid->yd->login_cookie); - yid->yd->login_cookie = NULL; - - return; - -FAIL: - YAHOO_CALLBACK(ext_yahoo_login_response)(yid->yd->client_id, error_code, NULL); -} - - static void (*yahoo_process_connection[])(struct yahoo_input_data *, int over) = { yahoo_process_pager_connection, yahoo_process_ft_connection, -- cgit v1.2.3 From 99c8f1357f1ab85f3a98727cb8877403d965e3da Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 17 Oct 2009 15:48:21 +0100 Subject: Valgrind pointed me at some memory leaks in the Yahoo! codek, including one that existed for a while already. Fixed. --- protocols/yahoo/libyahoo2.c | 8 +++++--- protocols/yahoo/yahoo.c | 31 +++++++++++++++++-------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 1d943df7..a1755cc9 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -2485,9 +2485,8 @@ static void yahoo_https_auth_finish(struct http_request *req) yahoo_packet_free(pack); - return; - fail: + g_free(crumb); g_free(had->token); g_free(had->chal); g_free(had); @@ -4134,7 +4133,10 @@ void yahoo_logoff(int id) LOG(("yahoo_logoff: current status: %d", yd->current_status)); - if(yd->current_status != -1) { + if(yd->current_status != -1 && 0) { + /* Meh. Don't send this. The event handlers are not going to + get to do this so it'll just leak memory. And the TCP + connection reset will hopefully be clear enough. */ pkt = yahoo_packet_new(YAHOO_SERVICE_LOGOFF, YAHOO_STATUS_AVAILABLE, yd->session_id); yd->current_status = -1; diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 96f619ed..ac57d4b6 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -253,20 +253,23 @@ static void byahoo_set_away( struct im_connection *ic, char *state, char *msg ) static GList *byahoo_away_states( struct im_connection *ic ) { - GList *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" ); - m = g_list_append( m, "Not At Desk" ); - m = g_list_append( m, "Not In Office" ); - m = g_list_append( m, "On Phone" ); - m = g_list_append( m, "On Vacation" ); - 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 ); + static GList *m = NULL; + + 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" ); + m = g_list_append( m, "Not At Desk" ); + m = g_list_append( m, "Not In Office" ); + m = g_list_append( m, "On Phone" ); + m = g_list_append( m, "On Vacation" ); + 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; } -- cgit v1.2.3 From 57d842193767ddbb87531ce9865b23fbdb72eadb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 17 Oct 2009 16:04:30 +0100 Subject: Document password-protected rooms. --- doc/user-guide/commands.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index fcb1c8be..af566de4 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -174,6 +174,10 @@ After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. (See chat set) + + + Password-protected rooms work exactly like on IRC, by passing the password as an extra argument to /join. + -- cgit v1.2.3 From 74349eb5b77e2143289ef98201d03870e0d2366a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 17 Oct 2009 16:13:40 +0100 Subject: If you can't find what you expect in an IQ packet, it doesn't mean it's incorrect, so stop spamming. Ideally it should return a feature-not- implemented but I'll do that later. --- protocols/jabber/iq.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index 38c5a5a9..875b5c81 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -50,10 +50,11 @@ xt_status jabber_pkt_iq( struct xt_node *node, gpointer data ) else if( strcmp( type, "get" ) == 0 ) { if( !( ( c = xt_find_node( node->children, "query" ) ) || - ( c = xt_find_node( node->children, "ping" ) ) ) || /* O_o WHAT is wrong with just ????? */ + ( c = xt_find_node( node->children, "ping" ) ) ) || !( s = xt_find_attr( c, "xmlns" ) ) ) { - imcb_log( ic, "Warning: Received incomplete IQ-%s packet", type ); + /* Sigh. Who decided to suddenly invent new elements + instead of just sticking with ? */ return XT_HANDLED; } -- cgit v1.2.3 From 3650088f5bc4476b3508b11997ca1f2a620b8afa Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 17 Oct 2009 16:25:41 +0100 Subject: I call you BitlBee 1.2.4. I hope. :-) --- doc/CHANGES | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/CHANGES b/doc/CHANGES index 84dbe162..1bfd71d4 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -3,6 +3,23 @@ found in the bzr commit logs, for example you can try: http://bugs.bitlbee.org/bitlbee/timeline?daysback=90&changeset=on +Version 1.2.4: +- Most important change (and main reason for releasing now): Upgraded Yahoo! + module to a newer version to get it working again. +- join_chat command replaced with the much better chat command: + * Similar to how account replaced login/slist/logout. Add a chatroom once, + then just /join it like any other room. Also automatic joining at login + time is now possible. + * Note that the old way of starting groupchats (/join #nickname) is now + also deprecated, use "chat with" instead. + * See "help chat" and "help chat add" for more information. +- Rewrote bitlbee.conf parser to be less dumb. +- Fixed compatibility (hopefully) with AIM mobile messages, certain kinds + of Google Talk chatrooms. +- Fixed numerous stability/reliability bugs over the last year. + +Finished 17 Oct 2009 + Version 1.2.3: - Fixed one more flaw similar to the previous hijacking bug, caused by incon- sistent handling of the USTATUS_IDENTIFIED state. All code touching these -- cgit v1.2.3 From 2e44b1f12fb58a6969a8fbaf2946d6ecdace484a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 17 Oct 2009 16:43:12 +0100 Subject: Hah. Forgot to update the version number in bitlbee.h. I really haven't done this for a while. --- bitlbee.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bitlbee.h b/bitlbee.h index 2224b691..cbda42cd 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -32,7 +32,7 @@ #define _WIN32_WINNT 0x0501 #define PACKAGE "BitlBee" -#define BITLBEE_VERSION "1.2.3" +#define BITLBEE_VERSION "1.2.4" #define VERSION BITLBEE_VERSION #define MAX_STRING 511 -- cgit v1.2.3