From fc82be67d1f785218273e6269ed9d089a89b2bfd Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 6 Jan 2008 21:01:25 +0100 Subject: Add Debian watch file. --- debian/watch | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 debian/watch diff --git a/debian/watch b/debian/watch new file mode 100644 index 00000000..66ab4504 --- /dev/null +++ b/debian/watch @@ -0,0 +1,2 @@ +version=2 +http://get.bitlbee.org/src/bitlbee-(.*).tar.gz -- cgit v1.2.3 From 2799ff94059f496b59420d04ec4f41f67aab2b9d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 12:20:03 +0000 Subject: Fixed broken check in check_arc.c --- tests/check_arc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/check_arc.c b/tests/check_arc.c index 989a0a66..a430f899 100644 --- a/tests/check_arc.c +++ b/tests/check_arc.c @@ -61,14 +61,15 @@ struct 0xb6, 0x92, 0x59, 0xe4, 0xf9, 0xc1, 0x7a, 0xf6, 0xf3, 0x18, 0xea, 0x28, 0x73, 0x6d, 0xb3, 0x0a, 0x6f, 0x0a, 0x2b, 0x43, 0x57, 0xe9, 0x3e, 0x63 }, 24, "OSCAR is creepy..." - } + }, + { "", 0, NULL } }; static void check_decod(int l) { int i; - for( i = 0; clear_tests[i]; i++ ) + for( i = 0; decrypt_tests[i].len; i++ ) { tcase_fn_start (decrypt_tests[i].decrypted, __FILE__, __LINE__); char *decrypted; -- cgit v1.2.3 From af97b234ad86fb9d69aa744af426591e4b1eaf97 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 13:17:52 +0000 Subject: Improved sasl_get_part() to deal with whitespace in challenge strings, as described in RFC 2831 secion 7.1 (the #rule description). Closes bug #362. --- protocols/jabber/sasl.c | 27 ++++++++--- tests/Makefile | 4 +- tests/check.c | 4 ++ tests/check_jabber_sasl.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 143 insertions(+), 9 deletions(-) create mode 100644 tests/check_jabber_sasl.c diff --git a/protocols/jabber/sasl.c b/protocols/jabber/sasl.c index 87059051..53248ef3 100644 --- a/protocols/jabber/sasl.c +++ b/protocols/jabber/sasl.c @@ -21,6 +21,8 @@ * * \***************************************************************************/ +#include + #include "jabber.h" #include "base64.h" @@ -106,12 +108,17 @@ xt_status sasl_pkt_mechanisms( struct xt_node *node, gpointer data ) return XT_HANDLED; } -static char *sasl_get_part( char *data, char *field ) +/* Non-static function, but not mentioned in jabber.h because it's for internal + use, just that the unittest should be able to reach it... */ +char *sasl_get_part( char *data, char *field ) { int i, len; len = strlen( field ); + while( isspace( *data ) || *data == ',' ) + data ++; + if( g_strncasecmp( data, field, len ) == 0 && data[len] == '=' ) { i = strlen( field ) + 1; @@ -128,13 +135,19 @@ static char *sasl_get_part( char *data, char *field ) i ++; } - /* If we got a comma, we got a new field. Check it. */ - if( data[i] == ',' && - g_strncasecmp( data + i + 1, field, len ) == 0 && - data[i+len+1] == '=' ) + /* If we got a comma, we got a new field. Check it, + find the next key after it. */ + if( data[i] == ',' ) { - i += len + 2; - break; + while( isspace( data[i] ) || data[i] == ',' ) + i ++; + + if( g_strncasecmp( data + i, field, len ) == 0 && + data[i+len] == '=' ) + { + i += len + 1; + break; + } } } } diff --git a/tests/Makefile b/tests/Makefile index 5bc3fbde..ae76fef5 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,9 +10,9 @@ 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 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 +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: $(test_objs) $(addprefix ../, $(main_objs)) ../protocols/protocols.o ../lib/lib.o @echo '*' Linking $@ diff --git a/tests/check.c b/tests/check.c index 043889d6..b3ffb957 100644 --- a/tests/check.c +++ b/tests/check.c @@ -65,6 +65,9 @@ Suite *crypting_suite(void); /* From check_set.c */ Suite *set_suite(void); +/* From check_jabber_sasl.c */ +Suite *jabber_sasl_suite(void); + int main (int argc, char **argv) { int nf; @@ -110,6 +113,7 @@ int main (int argc, char **argv) srunner_add_suite(sr, user_suite()); srunner_add_suite(sr, crypting_suite()); srunner_add_suite(sr, set_suite()); + srunner_add_suite(sr, jabber_sasl_suite()); if (no_fork) srunner_set_fork_status(sr, CK_NOFORK); srunner_run_all (sr, verbose?CK_VERBOSE:CK_NORMAL); diff --git a/tests/check_jabber_sasl.c b/tests/check_jabber_sasl.c new file mode 100644 index 00000000..96c05837 --- /dev/null +++ b/tests/check_jabber_sasl.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include +#include +#include +#include "arc.h" + +char *sasl_get_part( char *data, char *field ); + +#define challenge1 "nonce=\"1669585310\",qop=\"auth\",charset=utf-8,algorithm=md5-sess," \ + "something=\"Not \\\"standardized\\\"\"" +#define challenge2 "realm=\"quadpoint.org\", nonce=\"NPotlQpQf9RNYodOwierkQ==\", " \ + "qop=\"auth, auth-int\", charset=utf-8, algorithm=md5-sess" +#define challenge3 ", realm=\"localhost\", nonce=\"LlBV2txnO8RbB5hgs3KgiQ==\", " \ + "qop=\"auth, auth-int, \", ,\n, charset=utf-8, algorithm=md5-sess," + +struct +{ + const char *challenge; + char *key; + char *value; +} get_part_tests[] = { + { + challenge1, + "nonce", + "1669585310" + }, + { + challenge1, + "charset", + "utf-8" + }, + { + challenge1, + "harset", + NULL + }, + { + challenge1, + "something", + "Not \"standardized\"" + }, + { + challenge1, + "something_else", + NULL + }, + { + challenge2, + "realm", + "quadpoint.org", + }, + { + challenge2, + "real", + NULL + }, + { + challenge2, + "qop", + "auth, auth-int" + }, + { + challenge3, + "realm", + "localhost" + }, + { + challenge3, + "qop", + "auth, auth-int, " + }, + { + challenge3, + "charset", + "utf-8" + }, + { NULL, NULL, NULL } +}; + +static void check_get_part(int l) +{ + int i; + + for( i = 0; get_part_tests[i].key; i++ ) + { + tcase_fn_start( get_part_tests[i].key, __FILE__, i ); + char *res; + int len; + + res = sasl_get_part( get_part_tests[i].challenge, + get_part_tests[i].key ); + + if( get_part_tests[i].value == NULL ) + fail_if( res != NULL, "Found key %s in %s while it shouldn't be there!", + get_part_tests[i].key, get_part_tests[i].challenge ); + else if( res ) + fail_unless( strcmp( res, get_part_tests[i].value ) == 0, + "Incorrect value for key %s in %s: %s", + get_part_tests[i].key, get_part_tests[i].challenge, res ); + else + fail( "Could not find key %s in %s", + get_part_tests[i].key, get_part_tests[i].challenge ); + + g_free( res ); + } +} + +Suite *jabber_sasl_suite (void) +{ + Suite *s = suite_create("jabber/sasl"); + TCase *tc_core = tcase_create("Core"); + suite_add_tcase (s, tc_core); + tcase_add_test (tc_core, check_get_part); + return s; +} -- cgit v1.2.3 From fc5cf88448d4337d1a5fde418df1c6206a9b0ea2 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 16 Feb 2008 16:45:12 +0100 Subject: Fix lcov dependencies. --- Makefile | 1 - lib/Makefile | 2 +- protocols/Makefile | 2 +- protocols/jabber/Makefile | 2 +- protocols/msn/Makefile | 2 +- protocols/oscar/Makefile | 2 +- protocols/yahoo/Makefile | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 0a988feb..49fc924a 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,6 @@ distclean: clean $(subdirs) check: all $(MAKE) -C tests -lcov: gcov: check gcov *.c diff --git a/lib/Makefile b/lib/Makefile index a79f7c4c..975deceb 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -17,7 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: lib.o check: all -lcov: +lcov: check gcov: gcov *.c diff --git a/protocols/Makefile b/protocols/Makefile index f7d76e0f..18d79e8d 100644 --- a/protocols/Makefile +++ b/protocols/Makefile @@ -26,7 +26,7 @@ LFLAGS += -r # [SH] Phony targets all: protocols.o check: all -lcov: +lcov: check gcov: gcov *.c diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index e042f812..3ce78127 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -17,7 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: jabber_mod.o check: all -lcov: +lcov: check gcov: gcov *.c diff --git a/protocols/msn/Makefile b/protocols/msn/Makefile index 3440658d..6a588613 100644 --- a/protocols/msn/Makefile +++ b/protocols/msn/Makefile @@ -17,7 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: msn_mod.o check: all -lcov: +lcov: check gcov: gcov *.c diff --git a/protocols/oscar/Makefile b/protocols/oscar/Makefile index 95e85ec2..2792f22a 100644 --- a/protocols/oscar/Makefile +++ b/protocols/oscar/Makefile @@ -17,7 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: oscar_mod.o check: all -lcov: +lcov: check gcov: gcov *.c diff --git a/protocols/yahoo/Makefile b/protocols/yahoo/Makefile index 2cfd147b..b4fe56e2 100644 --- a/protocols/yahoo/Makefile +++ b/protocols/yahoo/Makefile @@ -17,7 +17,7 @@ LFLAGS += -r # [SH] Phony targets all: yahoo_mod.o check: all -lcov: +lcov: check gcov: gcov *.c -- cgit v1.2.3 From a73e91a40ac1110e772214a3401105aeb86d35e4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 17:38:30 +0000 Subject: Added callback on Jabber add-to-roster requests so buddies get added to the internal buddy list a little bit earlier. This should deal better with Jabber servers that send presence information of a new buddy before the roster push. --- protocols/jabber/iq.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/protocols/jabber/iq.c b/protocols/jabber/iq.c index c88bc0b0..38c5a5a9 100644 --- a/protocols/jabber/iq.c +++ b/protocols/jabber/iq.c @@ -525,6 +525,8 @@ static xt_status jabber_iq_display_vcard( struct im_connection *ic, struct xt_no return XT_HANDLED; } +static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ); + int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ) { struct xt_node *node; @@ -540,13 +542,36 @@ int jabber_add_to_roster( struct im_connection *ic, char *handle, char *name ) node = xt_new_node( "query", NULL, node ); xt_add_attr( node, "xmlns", XMLNS_ROSTER ); node = jabber_make_packet( "iq", "set", NULL, node ); + jabber_cache_add( ic, node, jabber_add_to_roster_callback ); st = jabber_write_packet( ic, node ); - xt_free_node( node ); return st; } +static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig ) +{ + char *s, *jid = NULL; + struct xt_node *c; + + if( ( c = xt_find_node( orig->children, "query" ) ) && + ( c = xt_find_node( c->children, "item" ) ) && + ( jid = xt_find_attr( c, "jid" ) ) && + ( s = xt_find_attr( node, "type" ) ) && + strcmp( s, "result" ) == 0 ) + { + if( imcb_find_buddy( ic, jid ) == NULL ) + imcb_add_buddy( ic, jid, NULL ); + } + else + { + imcb_log( ic, "Error while adding `%s' to your contact list.", + jid ? jid : "(unknown handle)" ); + } + + return XT_HANDLED; +} + int jabber_remove_from_roster( struct im_connection *ic, char *handle ) { struct xt_node *node; -- cgit v1.2.3 From 2d88d25aeb62d90e4288f8b83979baaff96cb7f2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 19:38:17 +0000 Subject: Added help_free() test, and fixed compiler warning in SASL test. --- tests/check_help.c | 7 +++++-- tests/check_jabber_sasl.c | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/check_help.c b/tests/check_help.c index 7e5283e3..5a2f28d9 100644 --- a/tests/check_help.c +++ b/tests/check_help.c @@ -6,11 +6,14 @@ #include #include "help.h" -START_TEST(test_help_none) +START_TEST(test_help_initfree) help_t *h, *r; r = help_init(&h, "/dev/null"); fail_if(r == NULL); fail_if(r != h); + + help_free(&h); + fail_if(h != NULL); END_TEST START_TEST(test_help_nonexistent) @@ -24,7 +27,7 @@ Suite *help_suite (void) Suite *s = suite_create("Help"); TCase *tc_core = tcase_create("Core"); suite_add_tcase (s, tc_core); - tcase_add_test (tc_core, test_help_none); + tcase_add_test (tc_core, test_help_initfree); tcase_add_test (tc_core, test_help_nonexistent); return s; } diff --git a/tests/check_jabber_sasl.c b/tests/check_jabber_sasl.c index 96c05837..6bceeb88 100644 --- a/tests/check_jabber_sasl.c +++ b/tests/check_jabber_sasl.c @@ -17,7 +17,7 @@ char *sasl_get_part( char *data, char *field ); struct { - const char *challenge; + char *challenge; char *key; char *value; } get_part_tests[] = { -- cgit v1.2.3 From add23a26034a7368f4fdc0707488719048322e89 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 22:07:14 +0000 Subject: Moved xmltree to lib/ because I want to use it from more than just the Jabber module. --- lib/Makefile | 2 +- lib/xmltree.c | 589 +++++++++++++++++++++++++++++++++++++++++++++ lib/xmltree.h | 97 ++++++++ protocols/jabber/Makefile | 2 +- protocols/jabber/xmltree.c | 589 --------------------------------------------- protocols/jabber/xmltree.h | 97 -------- 6 files changed, 688 insertions(+), 688 deletions(-) create mode 100644 lib/xmltree.c create mode 100644 lib/xmltree.h delete mode 100644 protocols/jabber/xmltree.c delete mode 100644 protocols/jabber/xmltree.h diff --git a/lib/Makefile b/lib/Makefile index 975deceb..03fef1ab 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o +objects = arc.o base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o sha1.o $(SSL_CLIENT) url.o xmltree.o CFLAGS += -Wall LFLAGS += -r diff --git a/lib/xmltree.c b/lib/xmltree.c new file mode 100644 index 00000000..62549eb5 --- /dev/null +++ b/lib/xmltree.c @@ -0,0 +1,589 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * +* * +* Copyright 2006 Wilmer van der Gaast * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library 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 * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "xmltree.h" + +static void xt_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) +{ + struct xt_parser *xt = data; + struct xt_node *node = g_new0( struct xt_node, 1 ), *nt; + int i; + + node->parent = xt->cur; + node->name = g_strdup( element_name ); + + /* First count the number of attributes */ + for( i = 0; attr_names[i]; i ++ ); + + /* Then allocate a NULL-terminated array. */ + node->attr = g_new0( struct xt_attr, i + 1 ); + + /* And fill it, saving one variable by starting at the end. */ + for( i --; i >= 0; i -- ) + { + node->attr[i].key = g_strdup( attr_names[i] ); + node->attr[i].value = g_strdup( attr_values[i] ); + } + + /* Add it to the linked list of children nodes, if we have a current + node yet. */ + if( xt->cur ) + { + if( xt->cur->children ) + { + for( nt = xt->cur->children; nt->next; nt = nt->next ); + nt->next = node; + } + else + { + xt->cur->children = node; + } + } + else if( xt->root ) + { + /* ERROR situation: A second root-element??? */ + } + + /* Now this node will be the new current node. */ + xt->cur = node; + /* And maybe this is the root? */ + if( xt->root == NULL ) + xt->root = node; +} + +static void xt_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +{ + struct xt_parser *xt = data; + struct xt_node *node = xt->cur; + + if( node == NULL ) + return; + + /* FIXME: Does g_renew also OFFICIALLY accept NULL arguments? */ + node->text = g_renew( char, node->text, node->text_len + text_len + 1 ); + memcpy( node->text + node->text_len, text, text_len ); + node->text_len += text_len; + /* Zero termination is always nice to have. */ + node->text[node->text_len] = 0; +} + +static void xt_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) +{ + struct xt_parser *xt = data; + + xt->cur->flags |= XT_COMPLETE; + xt->cur = xt->cur->parent; +} + +GMarkupParser xt_parser_funcs = +{ + xt_start_element, + xt_end_element, + xt_text, + NULL, + NULL +}; + +struct xt_parser *xt_new( gpointer data ) +{ + struct xt_parser *xt = g_new0( struct xt_parser, 1 ); + + xt->data = data; + xt_reset( xt ); + + return xt; +} + +/* Reset the parser, flush everything we have so far. For example, we need + this for XMPP when doing TLS/SASL to restart the stream. */ +void xt_reset( struct xt_parser *xt ) +{ + if( xt->parser ) + g_markup_parse_context_free( xt->parser ); + + xt->parser = g_markup_parse_context_new( &xt_parser_funcs, 0, xt, NULL ); + + if( xt->root ) + { + xt_free_node( xt->root ); + xt->root = NULL; + xt->cur = NULL; + } +} + +/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on + end-of-stream and 1 otherwise. */ +int xt_feed( struct xt_parser *xt, char *text, int text_len ) +{ + if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) + { + return -1; + } + + return !( xt->root && xt->root->flags & XT_COMPLETE ); +} + +/* Find completed nodes and see if a handler has to be called. Passing + a node isn't necessary if you want to start at the root, just pass + NULL. This second argument is needed for recursive calls. */ +int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) +{ + struct xt_node *c; + xt_status st; + int i; + + /* Just in case someone likes infinite loops... */ + if( xt->root == NULL ) + return 0; + + if( node == NULL ) + return xt_handle( xt, xt->root, depth ); + + if( depth != 0 ) + for( c = node->children; c; c = c->next ) + if( !xt_handle( xt, c, depth > 0 ? depth - 1 : depth ) ) + return 0; + + if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) + { + for( i = 0; xt->handlers[i].func; i ++ ) + { + /* This one is fun! \o/ */ + + /* If handler.name == NULL it means it should always match. */ + if( ( xt->handlers[i].name == NULL || + /* If it's not, compare. There should always be a name. */ + g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && + /* If handler.parent == NULL, it's a match. */ + ( xt->handlers[i].parent == NULL || + /* If there's a parent node, see if the name matches. */ + ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : + /* If there's no parent, the handler should mention as a parent. */ + g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) + { + st = xt->handlers[i].func( node, xt->data ); + + if( st == XT_ABORT ) + return 0; + else if( st != XT_NEXT ) + break; + } + } + + node->flags |= XT_SEEN; + } + + return 1; +} + +/* Garbage collection: Cleans up all nodes that are handled. Useful for + streams because there's no reason to keep a complete packet history + in memory. */ +void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) +{ + struct xt_node *c, *prev; + + if( !xt || !xt->root ) + return; + + if( node == NULL ) + return xt_cleanup( xt, xt->root, depth ); + + if( node->flags & XT_SEEN && node == xt->root ) + { + xt_free_node( xt->root ); + xt->root = xt->cur = NULL; + /* xt->cur should be NULL already, BTW... */ + + return; + } + + /* c contains the current node, prev the previous node (or NULL). + I admit, this one's pretty horrible. */ + for( c = node->children, prev = NULL; c; prev = c, c = c ? c->next : node->children ) + { + if( c->flags & XT_SEEN ) + { + /* Remove the node from the linked list. */ + if( prev ) + prev->next = c->next; + else + node->children = c->next; + + xt_free_node( c ); + + /* Since the for loop wants to get c->next, make sure + c points at something that exists (and that c->next + will actually be the next item we should check). c + can be NULL now, if we just removed the first item. + That explains the ? thing in for(). */ + c = prev; + } + else + { + /* This node can't be cleaned up yet, but maybe a + subnode can. */ + if( depth != 0 ) + xt_cleanup( xt, c, depth > 0 ? depth - 1 : depth ); + } + } +} + +static void xt_to_string_real( struct xt_node *node, GString *str ) +{ + char *buf; + struct xt_node *c; + int i; + + g_string_append_printf( str, "<%s", node->name ); + + for( i = 0; node->attr[i].key; i ++ ) + { + buf = g_markup_printf_escaped( " %s=\"%s\"", node->attr[i].key, node->attr[i].value ); + g_string_append( str, buf ); + g_free( buf ); + } + + if( node->text == NULL && node->children == NULL ) + { + g_string_append( str, "/>" ); + return; + } + + g_string_append( str, ">" ); + if( node->text_len > 0 ) + { + buf = g_markup_escape_text( node->text, node->text_len ); + g_string_append( str, buf ); + g_free( buf ); + } + + for( c = node->children; c; c = c->next ) + xt_to_string_real( c, str ); + + g_string_append_printf( str, "", node->name ); +} + +char *xt_to_string( struct xt_node *node ) +{ + GString *ret; + char *real; + + ret = g_string_new( "" ); + xt_to_string_real( node, ret ); + + real = ret->str; + g_string_free( ret, FALSE ); + + return real; +} + +#ifdef DEBUG +void xt_print( struct xt_node *node ) +{ + int i; + struct xt_node *c; + + /* Indentation */ + for( c = node; c->parent; c = c->parent ) + printf( "\t" ); + + /* Start the tag */ + printf( "<%s", node->name ); + + /* Print the attributes */ + for( i = 0; node->attr[i].key; i ++ ) + printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); + + /* /> in case there's really *nothing* inside this tag, otherwise + just >. */ + /* If this tag doesn't have any content at all... */ + if( node->text == NULL && node->children == NULL ) + { + printf( "/>\n" ); + return; + /* Then we're finished! */ + } + + /* Otherwise... */ + printf( ">" ); + + /* Only print the text if it contains more than whitespace (TEST). */ + if( node->text_len > 0 ) + { + for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); + if( node->text[i] ) + printf( "%s", g_markup_escape_text( node->text, -1 ) ); + } + + if( node->children ) + printf( "\n" ); + + for( c = node->children; c; c = c->next ) + xt_print( c ); + + if( node->children ) + for( c = node; c->parent; c = c->parent ) + printf( "\t" ); + + /* Non-empty tag is now finished. */ + printf( "\n", node->name ); +} +#endif + +struct xt_node *xt_dup( struct xt_node *node ) +{ + struct xt_node *dup = g_new0( struct xt_node, 1 ); + struct xt_node *c, *dc = NULL; + int i; + + /* Let's NOT copy the parent element here BTW! Only do it for children. */ + + dup->name = g_strdup( node->name ); + dup->flags = node->flags; + if( node->text ) + { + dup->text = g_memdup( node->text, node->text_len + 1 ); + dup->text_len = node->text_len; + } + + /* Count the number of attributes and allocate the new array. */ + for( i = 0; node->attr[i].key; i ++ ); + dup->attr = g_new0( struct xt_attr, i + 1 ); + + /* Copy them all! */ + for( i --; i >= 0; i -- ) + { + dup->attr[i].key = g_strdup( node->attr[i].key ); + dup->attr[i].value = g_strdup( node->attr[i].value ); + } + + /* This nice mysterious loop takes care of the children. */ + for( c = node->children; c; c = c->next ) + { + if( dc == NULL ) + dc = dup->children = xt_dup( c ); + else + dc = ( dc->next = xt_dup( c ) ); + + dc->parent = dup; + } + + return dup; +} + +/* Frees a node. This doesn't clean up references to itself from parents! */ +void xt_free_node( struct xt_node *node ) +{ + int i; + + if( !node ) + return; + + g_free( node->name ); + g_free( node->text ); + + for( i = 0; node->attr[i].key; i ++ ) + { + g_free( node->attr[i].key ); + g_free( node->attr[i].value ); + } + g_free( node->attr ); + + while( node->children ) + { + struct xt_node *next = node->children->next; + + xt_free_node( node->children ); + node->children = next; + } + + g_free( node ); +} + +void xt_free( struct xt_parser *xt ) +{ + if( !xt ) + return; + + if( xt->root ) + xt_free_node( xt->root ); + + g_markup_parse_context_free( xt->parser ); + + g_free( xt ); +} + +/* To find a node's child with a specific name, pass the node's children + list, not the node itself! The reason you have to do this by hand: So + that you can also use this function as a find-next. */ +struct xt_node *xt_find_node( struct xt_node *node, const char *name ) +{ + while( node ) + { + if( g_strcasecmp( node->name, name ) == 0 ) + break; + + node = node->next; + } + + return node; +} + +char *xt_find_attr( struct xt_node *node, const char *key ) +{ + int i; + + if( !node ) + return NULL; + + for( i = 0; node->attr[i].key; i ++ ) + if( g_strcasecmp( node->attr[i].key, key ) == 0 ) + break; + + return node->attr[i].value; +} + +struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ) +{ + struct xt_node *node, *c; + + node = g_new0( struct xt_node, 1 ); + node->name = g_strdup( name ); + node->children = children; + node->attr = g_new0( struct xt_attr, 1 ); + + if( text ) + { + node->text_len = strlen( text ); + node->text = g_memdup( text, node->text_len + 1 ); + } + + for( c = children; c; c = c->next ) + { + if( c->parent != NULL ) + { + /* ERROR CONDITION: They seem to have a parent already??? */ + } + + c->parent = node; + } + + return node; +} + +void xt_add_child( struct xt_node *parent, struct xt_node *child ) +{ + struct xt_node *node; + + /* This function can actually be used to add more than one child, so + do handle this properly. */ + for( node = child; node; node = node->next ) + { + if( node->parent != NULL ) + { + /* ERROR CONDITION: They seem to have a parent already??? */ + } + + node->parent = parent; + } + + if( parent->children == NULL ) + { + parent->children = child; + } + else + { + for( node = parent->children; node->next; node = node->next ); + node->next = child; + } +} + +void xt_add_attr( struct xt_node *node, const char *key, const char *value ) +{ + int i; + + /* Now actually it'd be nice if we can also change existing attributes + (which actually means this function doesn't have the right name). + So let's find out if we have this attribute already... */ + for( i = 0; node->attr[i].key; i ++ ) + if( strcmp( node->attr[i].key, key ) == 0 ) + break; + + if( node->attr[i].key == NULL ) + { + /* If not, allocate space for a new attribute. */ + node->attr = g_renew( struct xt_attr, node->attr, i + 2 ); + node->attr[i].key = g_strdup( key ); + node->attr[i+1].key = NULL; + } + else + { + /* Otherwise, free the old value before setting the new one. */ + g_free( node->attr[i].value ); + } + + node->attr[i].value = g_strdup( value ); +} + +int xt_remove_attr( struct xt_node *node, const char *key ) +{ + int i, last; + + for( i = 0; node->attr[i].key; i ++ ) + if( strcmp( node->attr[i].key, key ) == 0 ) + break; + + /* If we didn't find the attribute... */ + if( node->attr[i].key == NULL ) + return 0; + + g_free( node->attr[i].key ); + g_free( node->attr[i].value ); + + /* If it's the last, this is easy: */ + if( node->attr[i+1].key == NULL ) + { + node->attr[i].key = node->attr[i].value = NULL; + } + else /* It's also pretty easy, actually. */ + { + /* Find the last item. */ + for( last = i + 1; node->attr[last+1].key; last ++ ); + + node->attr[i] = node->attr[last]; + node->attr[last].key = NULL; + node->attr[last].value = NULL; + } + + /* Let's not bother with reallocating memory here. It takes time and + most packets don't stay in memory for long anyway. */ + + return 1; +} diff --git a/lib/xmltree.h b/lib/xmltree.h new file mode 100644 index 00000000..b8b61641 --- /dev/null +++ b/lib/xmltree.h @@ -0,0 +1,97 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * +* * +* Copyright 2006 Wilmer van der Gaast * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Lesser General Public * +* License as published by the Free Software Foundation, version * +* 2.1. * +* * +* This library 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 * +* Lesser General Public License for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this library; if not, write to the Free Software Foundation, * +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * +* * +****************************************************************************/ + +#ifndef _XMLTREE_H +#define _XMLTREE_H + +typedef enum +{ + XT_COMPLETE = 1, /* reached */ + XT_SEEN = 2, /* Handler called (or not defined) */ +} xt_flags; + +typedef enum +{ + XT_ABORT, /* Abort, don't handle the rest anymore */ + XT_HANDLED, /* Handled this tag properly, go to the next one */ + XT_NEXT /* Try if there's another matching handler */ +} xt_status; + +struct xt_attr +{ + char *key, *value; +}; + +struct xt_node +{ + struct xt_node *parent; + struct xt_node *children; + + char *name; + struct xt_attr *attr; + char *text; + int text_len; + + struct xt_node *next; + xt_flags flags; +}; + +typedef xt_status (*xt_handler_func) ( struct xt_node *node, gpointer data ); + +struct xt_handler_entry +{ + char *name, *parent; + xt_handler_func func; +}; + +struct xt_parser +{ + GMarkupParseContext *parser; + struct xt_node *root; + struct xt_node *cur; + + struct xt_handler_entry *handlers; + gpointer data; + + GError *gerr; +}; + +struct xt_parser *xt_new( gpointer data ); +void xt_reset( struct xt_parser *xt ); +int xt_feed( struct xt_parser *xt, char *text, int text_len ); +int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); +void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); +char *xt_to_string( struct xt_node *node ); +void xt_print( struct xt_node *node ); +struct xt_node *xt_dup( struct xt_node *node ); +void xt_free_node( struct xt_node *node ); +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 ); +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 ); + +#endif diff --git a/protocols/jabber/Makefile b/protocols/jabber/Makefile index 3ce78127..e7a505ba 100644 --- a/protocols/jabber/Makefile +++ b/protocols/jabber/Makefile @@ -9,7 +9,7 @@ -include ../../Makefile.settings # [SH] Program variables -objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o xmltree.o +objects = conference.o io.o iq.o jabber.o jabber_util.o message.o presence.o sasl.o CFLAGS += -Wall LFLAGS += -r diff --git a/protocols/jabber/xmltree.c b/protocols/jabber/xmltree.c deleted file mode 100644 index 62549eb5..00000000 --- a/protocols/jabber/xmltree.c +++ /dev/null @@ -1,589 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * -* * -* Copyright 2006 Wilmer van der Gaast * -* * -* This library is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public * -* License as published by the Free Software Foundation, version * -* 2.1. * -* * -* This library 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 * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * -* * -****************************************************************************/ - -#include -#include -#include -#include -#include - -#include "xmltree.h" - -static void xt_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - struct xt_node *node = g_new0( struct xt_node, 1 ), *nt; - int i; - - node->parent = xt->cur; - node->name = g_strdup( element_name ); - - /* First count the number of attributes */ - for( i = 0; attr_names[i]; i ++ ); - - /* Then allocate a NULL-terminated array. */ - node->attr = g_new0( struct xt_attr, i + 1 ); - - /* And fill it, saving one variable by starting at the end. */ - for( i --; i >= 0; i -- ) - { - node->attr[i].key = g_strdup( attr_names[i] ); - node->attr[i].value = g_strdup( attr_values[i] ); - } - - /* Add it to the linked list of children nodes, if we have a current - node yet. */ - if( xt->cur ) - { - if( xt->cur->children ) - { - for( nt = xt->cur->children; nt->next; nt = nt->next ); - nt->next = node; - } - else - { - xt->cur->children = node; - } - } - else if( xt->root ) - { - /* ERROR situation: A second root-element??? */ - } - - /* Now this node will be the new current node. */ - xt->cur = node; - /* And maybe this is the root? */ - if( xt->root == NULL ) - xt->root = node; -} - -static void xt_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - struct xt_node *node = xt->cur; - - if( node == NULL ) - return; - - /* FIXME: Does g_renew also OFFICIALLY accept NULL arguments? */ - node->text = g_renew( char, node->text, node->text_len + text_len + 1 ); - memcpy( node->text + node->text_len, text, text_len ); - node->text_len += text_len; - /* Zero termination is always nice to have. */ - node->text[node->text_len] = 0; -} - -static void xt_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) -{ - struct xt_parser *xt = data; - - xt->cur->flags |= XT_COMPLETE; - xt->cur = xt->cur->parent; -} - -GMarkupParser xt_parser_funcs = -{ - xt_start_element, - xt_end_element, - xt_text, - NULL, - NULL -}; - -struct xt_parser *xt_new( gpointer data ) -{ - struct xt_parser *xt = g_new0( struct xt_parser, 1 ); - - xt->data = data; - xt_reset( xt ); - - return xt; -} - -/* Reset the parser, flush everything we have so far. For example, we need - this for XMPP when doing TLS/SASL to restart the stream. */ -void xt_reset( struct xt_parser *xt ) -{ - if( xt->parser ) - g_markup_parse_context_free( xt->parser ); - - xt->parser = g_markup_parse_context_new( &xt_parser_funcs, 0, xt, NULL ); - - if( xt->root ) - { - xt_free_node( xt->root ); - xt->root = NULL; - xt->cur = NULL; - } -} - -/* Feed the parser, don't execute any handler. Returns -1 on errors, 0 on - end-of-stream and 1 otherwise. */ -int xt_feed( struct xt_parser *xt, char *text, int text_len ) -{ - if( !g_markup_parse_context_parse( xt->parser, text, text_len, &xt->gerr ) ) - { - return -1; - } - - return !( xt->root && xt->root->flags & XT_COMPLETE ); -} - -/* Find completed nodes and see if a handler has to be called. Passing - a node isn't necessary if you want to start at the root, just pass - NULL. This second argument is needed for recursive calls. */ -int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ) -{ - struct xt_node *c; - xt_status st; - int i; - - /* Just in case someone likes infinite loops... */ - if( xt->root == NULL ) - return 0; - - if( node == NULL ) - return xt_handle( xt, xt->root, depth ); - - if( depth != 0 ) - for( c = node->children; c; c = c->next ) - if( !xt_handle( xt, c, depth > 0 ? depth - 1 : depth ) ) - return 0; - - if( node->flags & XT_COMPLETE && !( node->flags & XT_SEEN ) ) - { - for( i = 0; xt->handlers[i].func; i ++ ) - { - /* This one is fun! \o/ */ - - /* If handler.name == NULL it means it should always match. */ - if( ( xt->handlers[i].name == NULL || - /* If it's not, compare. There should always be a name. */ - g_strcasecmp( xt->handlers[i].name, node->name ) == 0 ) && - /* If handler.parent == NULL, it's a match. */ - ( xt->handlers[i].parent == NULL || - /* If there's a parent node, see if the name matches. */ - ( node->parent ? g_strcasecmp( xt->handlers[i].parent, node->parent->name ) == 0 : - /* If there's no parent, the handler should mention as a parent. */ - g_strcasecmp( xt->handlers[i].parent, "" ) == 0 ) ) ) - { - st = xt->handlers[i].func( node, xt->data ); - - if( st == XT_ABORT ) - return 0; - else if( st != XT_NEXT ) - break; - } - } - - node->flags |= XT_SEEN; - } - - return 1; -} - -/* Garbage collection: Cleans up all nodes that are handled. Useful for - streams because there's no reason to keep a complete packet history - in memory. */ -void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ) -{ - struct xt_node *c, *prev; - - if( !xt || !xt->root ) - return; - - if( node == NULL ) - return xt_cleanup( xt, xt->root, depth ); - - if( node->flags & XT_SEEN && node == xt->root ) - { - xt_free_node( xt->root ); - xt->root = xt->cur = NULL; - /* xt->cur should be NULL already, BTW... */ - - return; - } - - /* c contains the current node, prev the previous node (or NULL). - I admit, this one's pretty horrible. */ - for( c = node->children, prev = NULL; c; prev = c, c = c ? c->next : node->children ) - { - if( c->flags & XT_SEEN ) - { - /* Remove the node from the linked list. */ - if( prev ) - prev->next = c->next; - else - node->children = c->next; - - xt_free_node( c ); - - /* Since the for loop wants to get c->next, make sure - c points at something that exists (and that c->next - will actually be the next item we should check). c - can be NULL now, if we just removed the first item. - That explains the ? thing in for(). */ - c = prev; - } - else - { - /* This node can't be cleaned up yet, but maybe a - subnode can. */ - if( depth != 0 ) - xt_cleanup( xt, c, depth > 0 ? depth - 1 : depth ); - } - } -} - -static void xt_to_string_real( struct xt_node *node, GString *str ) -{ - char *buf; - struct xt_node *c; - int i; - - g_string_append_printf( str, "<%s", node->name ); - - for( i = 0; node->attr[i].key; i ++ ) - { - buf = g_markup_printf_escaped( " %s=\"%s\"", node->attr[i].key, node->attr[i].value ); - g_string_append( str, buf ); - g_free( buf ); - } - - if( node->text == NULL && node->children == NULL ) - { - g_string_append( str, "/>" ); - return; - } - - g_string_append( str, ">" ); - if( node->text_len > 0 ) - { - buf = g_markup_escape_text( node->text, node->text_len ); - g_string_append( str, buf ); - g_free( buf ); - } - - for( c = node->children; c; c = c->next ) - xt_to_string_real( c, str ); - - g_string_append_printf( str, "", node->name ); -} - -char *xt_to_string( struct xt_node *node ) -{ - GString *ret; - char *real; - - ret = g_string_new( "" ); - xt_to_string_real( node, ret ); - - real = ret->str; - g_string_free( ret, FALSE ); - - return real; -} - -#ifdef DEBUG -void xt_print( struct xt_node *node ) -{ - int i; - struct xt_node *c; - - /* Indentation */ - for( c = node; c->parent; c = c->parent ) - printf( "\t" ); - - /* Start the tag */ - printf( "<%s", node->name ); - - /* Print the attributes */ - for( i = 0; node->attr[i].key; i ++ ) - printf( " %s=\"%s\"", node->attr[i].key, g_markup_escape_text( node->attr[i].value, -1 ) ); - - /* /> in case there's really *nothing* inside this tag, otherwise - just >. */ - /* If this tag doesn't have any content at all... */ - if( node->text == NULL && node->children == NULL ) - { - printf( "/>\n" ); - return; - /* Then we're finished! */ - } - - /* Otherwise... */ - printf( ">" ); - - /* Only print the text if it contains more than whitespace (TEST). */ - if( node->text_len > 0 ) - { - for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ ); - if( node->text[i] ) - printf( "%s", g_markup_escape_text( node->text, -1 ) ); - } - - if( node->children ) - printf( "\n" ); - - for( c = node->children; c; c = c->next ) - xt_print( c ); - - if( node->children ) - for( c = node; c->parent; c = c->parent ) - printf( "\t" ); - - /* Non-empty tag is now finished. */ - printf( "\n", node->name ); -} -#endif - -struct xt_node *xt_dup( struct xt_node *node ) -{ - struct xt_node *dup = g_new0( struct xt_node, 1 ); - struct xt_node *c, *dc = NULL; - int i; - - /* Let's NOT copy the parent element here BTW! Only do it for children. */ - - dup->name = g_strdup( node->name ); - dup->flags = node->flags; - if( node->text ) - { - dup->text = g_memdup( node->text, node->text_len + 1 ); - dup->text_len = node->text_len; - } - - /* Count the number of attributes and allocate the new array. */ - for( i = 0; node->attr[i].key; i ++ ); - dup->attr = g_new0( struct xt_attr, i + 1 ); - - /* Copy them all! */ - for( i --; i >= 0; i -- ) - { - dup->attr[i].key = g_strdup( node->attr[i].key ); - dup->attr[i].value = g_strdup( node->attr[i].value ); - } - - /* This nice mysterious loop takes care of the children. */ - for( c = node->children; c; c = c->next ) - { - if( dc == NULL ) - dc = dup->children = xt_dup( c ); - else - dc = ( dc->next = xt_dup( c ) ); - - dc->parent = dup; - } - - return dup; -} - -/* Frees a node. This doesn't clean up references to itself from parents! */ -void xt_free_node( struct xt_node *node ) -{ - int i; - - if( !node ) - return; - - g_free( node->name ); - g_free( node->text ); - - for( i = 0; node->attr[i].key; i ++ ) - { - g_free( node->attr[i].key ); - g_free( node->attr[i].value ); - } - g_free( node->attr ); - - while( node->children ) - { - struct xt_node *next = node->children->next; - - xt_free_node( node->children ); - node->children = next; - } - - g_free( node ); -} - -void xt_free( struct xt_parser *xt ) -{ - if( !xt ) - return; - - if( xt->root ) - xt_free_node( xt->root ); - - g_markup_parse_context_free( xt->parser ); - - g_free( xt ); -} - -/* To find a node's child with a specific name, pass the node's children - list, not the node itself! The reason you have to do this by hand: So - that you can also use this function as a find-next. */ -struct xt_node *xt_find_node( struct xt_node *node, const char *name ) -{ - while( node ) - { - if( g_strcasecmp( node->name, name ) == 0 ) - break; - - node = node->next; - } - - return node; -} - -char *xt_find_attr( struct xt_node *node, const char *key ) -{ - int i; - - if( !node ) - return NULL; - - for( i = 0; node->attr[i].key; i ++ ) - if( g_strcasecmp( node->attr[i].key, key ) == 0 ) - break; - - return node->attr[i].value; -} - -struct xt_node *xt_new_node( char *name, char *text, struct xt_node *children ) -{ - struct xt_node *node, *c; - - node = g_new0( struct xt_node, 1 ); - node->name = g_strdup( name ); - node->children = children; - node->attr = g_new0( struct xt_attr, 1 ); - - if( text ) - { - node->text_len = strlen( text ); - node->text = g_memdup( text, node->text_len + 1 ); - } - - for( c = children; c; c = c->next ) - { - if( c->parent != NULL ) - { - /* ERROR CONDITION: They seem to have a parent already??? */ - } - - c->parent = node; - } - - return node; -} - -void xt_add_child( struct xt_node *parent, struct xt_node *child ) -{ - struct xt_node *node; - - /* This function can actually be used to add more than one child, so - do handle this properly. */ - for( node = child; node; node = node->next ) - { - if( node->parent != NULL ) - { - /* ERROR CONDITION: They seem to have a parent already??? */ - } - - node->parent = parent; - } - - if( parent->children == NULL ) - { - parent->children = child; - } - else - { - for( node = parent->children; node->next; node = node->next ); - node->next = child; - } -} - -void xt_add_attr( struct xt_node *node, const char *key, const char *value ) -{ - int i; - - /* Now actually it'd be nice if we can also change existing attributes - (which actually means this function doesn't have the right name). - So let's find out if we have this attribute already... */ - for( i = 0; node->attr[i].key; i ++ ) - if( strcmp( node->attr[i].key, key ) == 0 ) - break; - - if( node->attr[i].key == NULL ) - { - /* If not, allocate space for a new attribute. */ - node->attr = g_renew( struct xt_attr, node->attr, i + 2 ); - node->attr[i].key = g_strdup( key ); - node->attr[i+1].key = NULL; - } - else - { - /* Otherwise, free the old value before setting the new one. */ - g_free( node->attr[i].value ); - } - - node->attr[i].value = g_strdup( value ); -} - -int xt_remove_attr( struct xt_node *node, const char *key ) -{ - int i, last; - - for( i = 0; node->attr[i].key; i ++ ) - if( strcmp( node->attr[i].key, key ) == 0 ) - break; - - /* If we didn't find the attribute... */ - if( node->attr[i].key == NULL ) - return 0; - - g_free( node->attr[i].key ); - g_free( node->attr[i].value ); - - /* If it's the last, this is easy: */ - if( node->attr[i+1].key == NULL ) - { - node->attr[i].key = node->attr[i].value = NULL; - } - else /* It's also pretty easy, actually. */ - { - /* Find the last item. */ - for( last = i + 1; node->attr[last+1].key; last ++ ); - - node->attr[i] = node->attr[last]; - node->attr[last].key = NULL; - node->attr[last].value = NULL; - } - - /* Let's not bother with reallocating memory here. It takes time and - most packets don't stay in memory for long anyway. */ - - return 1; -} diff --git a/protocols/jabber/xmltree.h b/protocols/jabber/xmltree.h deleted file mode 100644 index b8b61641..00000000 --- a/protocols/jabber/xmltree.h +++ /dev/null @@ -1,97 +0,0 @@ -/***************************************************************************\ -* * -* BitlBee - An IRC to IM gateway * -* Simple XML (stream) parse tree handling code (Jabber/XMPP, mainly) * -* * -* Copyright 2006 Wilmer van der Gaast * -* * -* This library is free software; you can redistribute it and/or * -* modify it under the terms of the GNU Lesser General Public * -* License as published by the Free Software Foundation, version * -* 2.1. * -* * -* This library 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 * -* Lesser General Public License for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this library; if not, write to the Free Software Foundation, * -* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * -* * -****************************************************************************/ - -#ifndef _XMLTREE_H -#define _XMLTREE_H - -typedef enum -{ - XT_COMPLETE = 1, /* reached */ - XT_SEEN = 2, /* Handler called (or not defined) */ -} xt_flags; - -typedef enum -{ - XT_ABORT, /* Abort, don't handle the rest anymore */ - XT_HANDLED, /* Handled this tag properly, go to the next one */ - XT_NEXT /* Try if there's another matching handler */ -} xt_status; - -struct xt_attr -{ - char *key, *value; -}; - -struct xt_node -{ - struct xt_node *parent; - struct xt_node *children; - - char *name; - struct xt_attr *attr; - char *text; - int text_len; - - struct xt_node *next; - xt_flags flags; -}; - -typedef xt_status (*xt_handler_func) ( struct xt_node *node, gpointer data ); - -struct xt_handler_entry -{ - char *name, *parent; - xt_handler_func func; -}; - -struct xt_parser -{ - GMarkupParseContext *parser; - struct xt_node *root; - struct xt_node *cur; - - struct xt_handler_entry *handlers; - gpointer data; - - GError *gerr; -}; - -struct xt_parser *xt_new( gpointer data ); -void xt_reset( struct xt_parser *xt ); -int xt_feed( struct xt_parser *xt, char *text, int text_len ); -int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); -void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth ); -char *xt_to_string( struct xt_node *node ); -void xt_print( struct xt_node *node ); -struct xt_node *xt_dup( struct xt_node *node ); -void xt_free_node( struct xt_node *node ); -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 ); -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 ); - -#endif -- cgit v1.2.3 From 4bbcba32aca2948f66c484ab074264fdb67609ae Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 16 Feb 2008 22:40:38 +0000 Subject: Moved xmltree handlers initialization to xt_new(). --- lib/xmltree.c | 3 ++- lib/xmltree.h | 4 ++-- protocols/jabber/io.c | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/xmltree.c b/lib/xmltree.c index 62549eb5..e65b4f41 100644 --- a/lib/xmltree.c +++ b/lib/xmltree.c @@ -110,11 +110,12 @@ GMarkupParser xt_parser_funcs = NULL }; -struct xt_parser *xt_new( gpointer data ) +struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data ) { struct xt_parser *xt = g_new0( struct xt_parser, 1 ); xt->data = data; + xt->handlers = handlers; xt_reset( xt ); return xt; diff --git a/lib/xmltree.h b/lib/xmltree.h index b8b61641..10677412 100644 --- a/lib/xmltree.h +++ b/lib/xmltree.h @@ -70,13 +70,13 @@ struct xt_parser struct xt_node *root; struct xt_node *cur; - struct xt_handler_entry *handlers; + const struct xt_handler_entry *handlers; gpointer data; GError *gerr; }; -struct xt_parser *xt_new( gpointer data ); +struct xt_parser *xt_new( const struct xt_handler_entry *handlers, gpointer data ); void xt_reset( struct xt_parser *xt ); int xt_feed( struct xt_parser *xt, char *text, int text_len ); int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth ); diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 86c216ef..9980dc8e 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -520,8 +520,7 @@ gboolean jabber_start_stream( struct im_connection *ic ) /* We'll start our stream now, so prepare everything to receive one from the server too. */ xt_free( jd->xt ); /* In case we're RE-starting. */ - jd->xt = xt_new( ic ); - jd->xt->handlers = (struct xt_handler_entry*) jabber_handlers; + jd->xt = xt_new( jabber_handlers, ic ); if( jd->r_inpa <= 0 ) jd->r_inpa = b_input_add( jd->fd, GAIM_INPUT_READ, jabber_read_callback, ic ); -- cgit v1.2.3 From e6648bf3b821ae40c0640857aae069bc0f5d90c4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Feb 2008 11:16:01 +0000 Subject: Replaced old MSN Passport (v1.4) authentication code with what's described on http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener . This was an attempt to fix bug #360, but it didn't. However, this change may make BitlBee a little bit more future-proof. Plus, the code is tidier and sometimes faster than the old mechanism. --- protocols/msn/ns.c | 30 +++--- protocols/msn/passport.c | 275 ++++++++++++++++++----------------------------- protocols/msn/passport.h | 91 +++++++++++++--- 3 files changed, 200 insertions(+), 196 deletions(-) diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index 0bb84a74..ff7da6ed 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -33,7 +33,7 @@ static gboolean msn_ns_callback( gpointer data, gint source, b_input_condition c static int msn_ns_command( gpointer data, char **cmd, int num_parts ); static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int num_parts ); -static void msn_auth_got_passport_id( struct passport_reply *rep ); +static void msn_auth_got_passport_token( struct msn_auth_data *mad ); gboolean msn_ns_connected( gpointer data, gint source, b_input_condition cond ) { @@ -213,7 +213,7 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( num_parts == 5 && strcmp( cmd[2], "TWN" ) == 0 && strcmp( cmd[3], "S" ) == 0 ) { /* Time for some Passport black magic... */ - if( !passport_get_id( msn_auth_got_passport_id, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) + if( !passport_get_token( msn_auth_got_passport_token, ic, ic->acc->user, ic->acc->pass, cmd[4] ) ) { imcb_error( ic, "Error while contacting Passport server" ); imc_logout( ic, TRUE ); @@ -673,22 +673,26 @@ static int msn_ns_message( gpointer data, char *msg, int msglen, char **cmd, int return( 1 ); } -static void msn_auth_got_passport_id( struct passport_reply *rep ) +static void msn_auth_got_passport_token( struct msn_auth_data *mad ) { - struct im_connection *ic = rep->data; - struct msn_data *md = ic->proto_data; - char *key = rep->result; - char buf[1024]; + struct im_connection *ic = mad->data; + struct msn_data *md; - if( key == NULL ) + /* Dead connection? */ + if( g_slist_find( msn_connections, ic ) == NULL ) + return; + + md = ic->proto_data; + if( mad->token ) { - imcb_error( ic, "Error during Passport authentication (%s)", - rep->error_string ? rep->error_string : "Unknown error" ); - imc_logout( ic, TRUE ); + char buf[1024]; + + g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, mad->token ); + msn_write( ic, buf, strlen( buf ) ); } else { - g_snprintf( buf, sizeof( buf ), "USR %d TWN S %s\r\n", ++md->trId, key ); - msn_write( ic, buf, strlen( buf ) ); + imcb_error( ic, "Error during Passport authentication: %s", mad->error ); + imc_logout( ic, TRUE ); } } diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 9fe6a174..7a15c3fe 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -1,8 +1,7 @@ -/* passport.c +/** passport.c * - * Functions to login to microsoft passport service for Messenger - * Copyright (C) 2004 Wouter Paesen - * Copyright (C) 2004 Wilmer van der Gaast + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -23,208 +22,144 @@ #include "passport.h" #include "msn.h" #include "bitlbee.h" +#include "url.h" +#include "misc.h" +#include "xmltree.h" #include #include -#define MSN_BUF_LEN 8192 +static int passport_get_token_real( struct msn_auth_data *mad ); +static void passport_get_token_ready( struct http_request *req ); -static char *prd_cached = NULL; - -static int passport_get_id_real( gpointer func, gpointer data, char *header ); -static void passport_get_id_ready( struct http_request *req ); - -static int passport_retrieve_dalogin( gpointer data, gpointer func, char *header ); -static void passport_retrieve_dalogin_ready( struct http_request *req ); - -static char *passport_create_header( char *cookie, char *email, char *pwd ); -static void destroy_reply( struct passport_reply *rep ); - -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ) +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ) { - char *header = passport_create_header( cookie, username, password ); + struct msn_auth_data *mad = g_new0( struct msn_auth_data, 1 ); + int i; - if( prd_cached == NULL ) - return passport_retrieve_dalogin( func, data, header ); - else - return passport_get_id_real( func, data, header ); + mad->username = g_strdup( username ); + mad->password = g_strdup( password ); + mad->cookie = g_strdup( cookie ); + + mad->callback = func; + mad->data = data; + + mad->url = g_strdup( SOAP_AUTHENTICATION_URL ); + mad->ttl = 3; /* Max. # of redirects. */ + + /* HTTP-escape stuff and s/,/&/ */ + http_decode( mad->cookie ); + for( i = 0; mad->cookie[i]; i ++ ) + if( mad->cookie[i] == ',' ) + mad->cookie[i] = '&'; + + return passport_get_token_real( mad ); } -static int passport_get_id_real( gpointer func, gpointer data, char *header ) +static int passport_get_token_real( struct msn_auth_data *mad ) { - struct passport_reply *rep; - char *server, *dummy, *reqs; + char *post_payload, *post_request; struct http_request *req; + url_t url; - rep = g_new0( struct passport_reply, 1 ); - rep->data = data; - rep->func = func; - rep->header = header; - - server = g_strdup( prd_cached ); - dummy = strchr( server, '/' ); - - if( dummy == NULL ) - { - destroy_reply( rep ); - return( 0 ); - } - - reqs = g_strdup_printf( "GET %s HTTP/1.0\r\n%s\r\n\r\n", dummy, header ); + url_set( &url, mad->url ); - *dummy = 0; - req = http_dorequest( server, 443, 1, reqs, passport_get_id_ready, rep ); + post_payload = g_markup_printf_escaped( SOAP_AUTHENTICATION_PAYLOAD, + mad->username, + mad->password, + mad->cookie ); - g_free( server ); - g_free( reqs ); + post_request = g_strdup_printf( SOAP_AUTHENTICATION_REQUEST, + url.file, url.host, + (int) strlen( post_payload ), + post_payload ); + + req = http_dorequest( url.host, url.port, 1, post_request, + passport_get_token_ready, mad ); - if( req == NULL ) - destroy_reply( rep ); + g_free( post_request ); + g_free( post_payload ); - return( req != NULL ); + return req != NULL; } -static void passport_get_id_ready( struct http_request *req ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ); +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ); + +static const struct xt_handler_entry passport_xt_handlers[] = { + { "wsse:BinarySecurityToken", "wst:RequestedSecurityToken", passport_xt_extract_token }, + { "S:Fault", "S:Envelope", passport_xt_handle_fault }, + { NULL, NULL, NULL } +}; + +static void passport_get_token_ready( struct http_request *req ) { - struct passport_reply *rep = req->data; + struct msn_auth_data *mad = req->data; + struct xt_parser *parser; - if( !g_slist_find( msn_connections, rep->data ) ) - { - destroy_reply( rep ); - return; - } + g_free( mad->url ); + g_free( mad->error ); + mad->url = mad->error = NULL; - if( req->finished && req->reply_headers && req->status_code == 200 ) + if( req->status_code == 200 ) { - char *dummy; - - if( ( dummy = strstr( req->reply_headers, "from-PP='" ) ) ) - { - char *responseend; - - dummy += strlen( "from-PP='" ); - responseend = strchr( dummy, '\'' ); - if( responseend ) - *responseend = 0; - - rep->result = g_strdup( dummy ); - } - else - { - rep->error_string = g_strdup( "Could not parse Passport server response" ); - } + parser = xt_new( passport_xt_handlers, mad ); + xt_feed( parser, req->reply_body, req->body_size ); + xt_handle( parser, NULL, -1 ); + xt_free( parser ); } else { - rep->error_string = g_strdup_printf( "HTTP error: %s", - req->status_string ? req->status_string : "Unknown error" ); + mad->error = g_strdup_printf( "HTTP error %d (%s)", req->status_code, + req->status_string ? req->status_string : "unknown" ); } - rep->func( rep ); - destroy_reply( rep ); -} - -static char *passport_create_header( char *cookie, char *email, char *pwd ) -{ - char *buffer; - char *currenttoken; - char *email_enc, *pwd_enc; - - currenttoken = strstr( cookie, "lc=" ); - if( currenttoken == NULL ) - return NULL; - - email_enc = g_new0( char, strlen( email ) * 3 + 1 ); - strcpy( email_enc, email ); - http_encode( email_enc ); - - pwd_enc = g_new0( char, strlen( pwd ) * 3 + 1 ); - strcpy( pwd_enc, pwd ); - http_encode( pwd_enc ); - - buffer = g_strdup_printf( "Authorization: Passport1.4 OrgVerb=GET," - "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," - "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, - currenttoken ); - - g_free( email_enc ); - g_free( pwd_enc ); + if( mad->error == NULL && mad->token == NULL ) + mad->error = g_strdup( "Could not parse Passport server response" ); - return buffer; + if( mad->url && mad->token == NULL ) + { + passport_get_token_real( mad ); + } + else + { + mad->callback( mad ); + + g_free( mad->url ); + g_free( mad->username ); + g_free( mad->password ); + g_free( mad->cookie ); + g_free( mad->token ); + g_free( mad->error ); + g_free( mad ); + } } -static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) +static xt_status passport_xt_extract_token( struct xt_node *node, gpointer data ) { - struct passport_reply *rep = g_new0( struct passport_reply, 1 ); - struct http_request *req; + struct msn_auth_data *mad = data; + char *s; - rep->data = data; - rep->func = func; - rep->header = header; + if( ( s = xt_find_attr( node, "Id" ) ) && strcmp( s, "PPToken1" ) == 0 ) + mad->token = g_memdup( node->text, node->text_len + 1 ); - req = http_dorequest_url( "https://nexus.passport.com/rdr/pprdr.asp", passport_retrieve_dalogin_ready, rep ); - - if( !req ) - destroy_reply( rep ); - - return( req != NULL ); + return XT_HANDLED; } -static void passport_retrieve_dalogin_ready( struct http_request *req ) +static xt_status passport_xt_handle_fault( struct xt_node *node, gpointer data ) { - struct passport_reply *rep = req->data; - char *dalogin; - char *urlend; + struct msn_auth_data *mad = data; + struct xt_node *code = xt_find_node( node->children, "faultcode" ); + struct xt_node *string = xt_find_node( node->children, "faultstring" ); + struct xt_node *redirect = xt_find_node( node->children, "psf:redirectUrl" ); - if( !g_slist_find( msn_connections, rep->data ) ) - { - destroy_reply( rep ); - return; - } - - if( !req->finished || !req->reply_headers || req->status_code != 200 ) - { - rep->error_string = g_strdup_printf( "HTTP error while fetching DALogin: %s", - req->status_string ? req->status_string : "Unknown error" ); - goto failure; - } + if( redirect && redirect->text_len && mad->ttl-- > 0 ) + mad->url = g_memdup( redirect->text, redirect->text_len + 1 ); - dalogin = strstr( req->reply_headers, "DALogin=" ); - - if( !dalogin ) - { - rep->error_string = g_strdup( "Parse error while fetching DALogin" ); - goto failure; - } - - dalogin += strlen( "DALogin=" ); - urlend = strchr( dalogin, ',' ); - if( urlend ) - *urlend = 0; - - /* strip the http(s):// part from the url */ - urlend = strstr( urlend, "://" ); - if( urlend ) - dalogin = urlend + strlen( "://" ); - - if( prd_cached == NULL ) - prd_cached = g_strdup( dalogin ); - - if( passport_get_id_real( rep->func, rep->data, rep->header ) ) - { - rep->header = NULL; - destroy_reply( rep ); - return; - } + if( code == NULL || code->text_len == 0 ) + mad->error = g_strdup( "Unknown error" ); + else + mad->error = g_strdup_printf( "%s (%s)", code->text, string && string->text_len ? + string->text : "no description available" ); -failure: - rep->func( rep ); - destroy_reply( rep ); -} - -static void destroy_reply( struct passport_reply *rep ) -{ - g_free( rep->result ); - g_free( rep->header ); - g_free( rep->error_string ); - g_free( rep ); + return XT_HANDLED; } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 9fd81a82..1d0c6edc 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -1,10 +1,7 @@ -#ifndef __PASSPORT_H__ -#define __PASSPORT_H__ /* passport.h * - * Functions to login to Microsoft Passport Service for Messenger - * Copyright (C) 2004 Wouter Paesen , - * Wilmer van der Gaast + * Functions to login to Microsoft Passport service for Messenger + * Copyright (C) 2004-2008 Wilmer van der Gaast * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -17,9 +14,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Thanks to http://msnpiki.msnfanatic.com/index.php/MSNP13:SOAPTweener + for the specs! */ + +#ifndef __PASSPORT_H__ +#define __PASSPORT_H__ + #include #include #include @@ -32,15 +35,77 @@ #endif #include "nogaim.h" -struct passport_reply +struct msn_auth_data { - void (*func)( struct passport_reply * ); - void *data; - char *result; - char *header; - char *error_string; + char *url; + int ttl; + + char *username; + char *password; + char *cookie; + + /* The end result, the only thing we'll really be interested in + once finished. */ + char *token; + char *error; /* Yeah, or that... */ + + void (*callback)( struct msn_auth_data *mad ); + gpointer data; }; -int passport_get_id( gpointer func, gpointer data, char *username, char *password, char *cookie ); +#define SOAP_AUTHENTICATION_URL "https://loginnet.passport.com/RST.srf" + +#define SOAP_AUTHENTICATION_REQUEST \ +"POST %s HTTP/1.0\r\n" \ +"Accept: text/*\r\n" \ +"User-Agent: BitlBee " BITLBEE_VERSION "\r\n" \ +"Host: %s\r\n" \ +"Content-Length: %d\r\n" \ +"Cache-Control: no-cache\r\n" \ +"\r\n" \ +"%s" + +#define SOAP_AUTHENTICATION_PAYLOAD \ +"" \ +"" \ + "
" \ + "" \ + "{7108E71A-9926-4FCB-BCC9-9A9D3F32E423}" \ + "4" \ + "1" \ + "" \ + "AQAAAAIAAABsYwQAAAAzMDg0" \ + "" \ + "" \ + "" \ + "%s" \ + "%s" \ + "" \ + "" \ + "
" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "http://Passport.NET/tb" \ + "" \ + "" \ + "" \ + "" \ + "http://schemas.xmlsoap.org/ws/2004/04/security/trust/Issue" \ + "" \ + "" \ + "messenger.msn.com" \ + "" \ + "" \ + "" \ + "" \ + "" \ + "" \ +"
" + +int passport_get_token( gpointer func, gpointer data, char *username, char *password, char *cookie ); #endif /* __PASSPORT_H__ */ -- cgit v1.2.3 From 9186d15356a46576fb5b306f49a6acdb64fb7622 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Feb 2008 11:26:44 +0000 Subject: Automatically truncate MSN passports to 16 characters because that's the maximum supported by MSN and giving a longer password will make the authentication fail. --- protocols/msn/passport.c | 5 +++++ protocols/msn/passport.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 7a15c3fe..565d15f3 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -52,6 +52,11 @@ int passport_get_token( gpointer func, gpointer data, char *username, char *pass if( mad->cookie[i] == ',' ) mad->cookie[i] = '&'; + /* Microsoft doesn't allow password longer than 16 chars and silently + fails authentication if you give the "full version" of your passwd. */ + if( strlen( mad->password ) > MAX_PASSPORT_PWLEN ) + mad->password[MAX_PASSPORT_PWLEN] = 0; + return passport_get_token_real( mad ); } diff --git a/protocols/msn/passport.h b/protocols/msn/passport.h index 1d0c6edc..517d2e91 100644 --- a/protocols/msn/passport.h +++ b/protocols/msn/passport.h @@ -35,6 +35,8 @@ #endif #include "nogaim.h" +#define MAX_PASSPORT_PWLEN 16 + struct msn_auth_data { char *url; -- cgit v1.2.3 From d5bd9c078ae2fb4d2e9354e943e06e017e878776 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 28 Feb 2008 22:39:37 +0000 Subject: My fix for semi-PEBKAC bug #353: Add a warning if someone seems to be using the wrong command, and fixing "help nick" example to show how it should be done now. --- doc/user-guide/commands.xml | 4 ++-- root_commands.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 5a1e398c..3402cfd7 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -842,8 +842,8 @@ - nick 1 "Wouter Paesen" - Setting your name on connection 1 to `Wouter Paesen' + account set 1/display_name "The majestik møøse" + display_name = `The majestik møøse' diff --git a/root_commands.c b/root_commands.c index 8e315bd4..2f542826 100644 --- a/root_commands.c +++ b/root_commands.c @@ -768,6 +768,9 @@ static void cmd_set( irc_t *irc, char **cmd ) irc_usermsg( irc, "%s = `%s'", set_name, s ); else irc_usermsg( irc, "%s is empty", set_name ); + + if( strchr( set_name, '/' ) ) + irc_usermsg( irc, "Warning: / found in setting name, you're probably looking for the `account set' command." ); } else { -- cgit v1.2.3 From 7bb3afbf24aaae0df9cd2e0e0cc9ebaf8e19f228 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Mar 2008 17:13:32 +0000 Subject: Oops, even GMail got out of beta quicker than this. ;-) --- doc/user-guide/Support.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/user-guide/Support.xml b/doc/user-guide/Support.xml index 401a4295..c9f50a5f 100644 --- a/doc/user-guide/Support.xml +++ b/doc/user-guide/Support.xml @@ -3,12 +3,13 @@ Support -BitlBee is beta software +Disclaimer -Although BitlBee has quite some functionality it is still beta. That means it -can crash at any time, corrupt your data or whatever. Don't use it in -any production environment and don't rely on it. +BitlBee doesn't come with a warranty and is still (and will probably always +be) under development. That means it can crash at any time, corrupt your +data or whatever. Don't use it in any production environment and don't rely +on it, or at least don't blame us if things blow up. :-) -- cgit v1.2.3 From 064e47c5927e1711fc45263d971998a7afca547b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Mar 2008 17:58:21 +0000 Subject: Some very late quickstart updates: ICQ supports server-side contact lists for ages already and private is set to true by default for quite some time as well. --- doc/user-guide/quickstart.xml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/user-guide/quickstart.xml b/doc/user-guide/quickstart.xml index 7735a8d7..0539a7c7 100644 --- a/doc/user-guide/quickstart.xml +++ b/doc/user-guide/quickstart.xml @@ -60,11 +60,11 @@ When you are finished adding your account(s) use the account on -For most protocols (currently MSN, Jabber, Yahoo and AOL) BitlBee can download the contact list automatically from the IM server and all the on-line users should appear in the control channel when you log in. +Now BitlBee logs in and downloads the contact list from the IM server. In a few seconds, all your on-line buddies should show up in the control channel. -BitlBee will convert names into irc-friendly form (for instance: tux@example.com will be given the nickname tux). If you have more than one person who would have the same name by this logic (for instance: tux@example.com and tux@bitlbee.org) the second one to log on will be tux_. The same is true if you have a tux log on to AOL and a tux log on from Yahoo. +BitlBee will convert names into IRC-friendly form (for instance: tux@example.com will be given the nickname tux). If you have more than one person who would have the same name by this logic (for instance: tux@example.com and tux@bitlbee.org) the second one to log on will be tux_. The same is true if you have a tux log on to AOL and a tux log on from Yahoo. @@ -126,11 +126,15 @@ First of all, a person must be on your contact list for you to chat with them (u tux: hey, how's the weather down there? - you: a bit chilly! + you: a bit chilly! -If you'd rather chat with them in a separate window use the /msg or /query command, just like you would for a private message in IRC. If you want to have messages automatically come up in private messages rather than in the &bitlbee channel, use the set private command: set private true (set private false to change back). +Note that, although all contacts are in the &bitlbee channel, only tux will actually receive this message. The &bitlbee channel shouldn't be confused with a real IRC channel. + + + +If you prefer chatting in a separate window, use the /msg or /query command, just like on real IRC. BitlBee will remember how you talk to someone and show his/her responses the same way. If you want to change the default behaviour (for people you haven't talked to yet), see help set private. -- cgit v1.2.3 From b27557b2d23f3cbc0801bc628de24a2a6adcfca9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Mar 2008 22:12:06 +0000 Subject: More documentation fixes: Cleaned up dead links, removed more outdated information (like the "set charset" default, which is UTF-8 for ages already). --- doc/user-guide/commands.xml | 22 +++++++--------------- doc/user-guide/misc.xml | 28 ++++------------------------ 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 3402cfd7..c45727b9 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -162,11 +162,7 @@ - If you want, you can also tell BitlBee what nick to give the new contact. Of course you can also use the rename command for that, but sometimes this might be more convenient. - - - - Adding -tmp adds the buddy to the internal BitlBee structures only, not to the real contact list (like done by set handle_unknown add). This allows you to talk to people who are not in your contact list. + If you want, you can also tell BitlBee what nick to give the new contact. The -tmp option adds the buddy to the internal BitlBee structures only, not to the real contact list (like done by set handle_unknown add). This allows you to talk to people who are not in your contact list. This normally won't show you any presence notifications. @@ -382,16 +378,16 @@ - iso8859-1 + utf-8 you can get a list of all possible values by doing 'iconv -l' in a shell - The charset setting enables you to use different character sets in BitlBee. These get converted to UTF-8 before sending and from UTF-8 when receiving. + This setting tells BitlBee what your IRC client sends and expects. It should be equal to the charset setting of your IRC client if you want to be able to send and receive non-ASCII text properly. - If you don't know what's the best value for this, at least iso8859-1 is the best choice for most Western countries. You can try to find what works best for you on http://czyborra.com/charsets/iso8859.html + Most systems use UTF-8 these days. On older systems, an iso8859 charset may work better. For example, iso8859-1 is the best choice for most Western countries. You can try to find what works best for you on http://www.unicodecharacter.com/charsets/iso8859.html @@ -676,7 +672,7 @@ - Sends you a /notice when a user starts typing a message (if the protocol supports it, MSN for example). This is a bug, not a feature. (But please don't report it.. ;-) You don't want to use it. Really. In fact the typing-notification is just one of the least useful 'innovations' ever. It's just there because some guy will probably ask me about it anyway. ;-) + Sends you a /notice when a user starts typing a message (if supported by the IM protocol and the user's client). To use this, you most likely want to use a script in your IRC client to show this information in a more sensible way. @@ -829,15 +825,11 @@ Change friendly name, nick nick <connection> [<new nick>] - nick + nick <connection> - This command allows to set the friendly name of an im account. If no new name is specified the command will report the current name. When the name contains spaces, don't forget to quote the whole nick in double quotes. Currently this command is only supported by the MSN protocol. - - - - It is recommended to use the per-account display_name setting to read and change this information. The nick command is deprecated. + Deprecated: Use the per-account display_name setting to read and change this information. diff --git a/doc/user-guide/misc.xml b/doc/user-guide/misc.xml index d387d4b3..b55a8915 100644 --- a/doc/user-guide/misc.xml +++ b/doc/user-guide/misc.xml @@ -46,16 +46,12 @@ All MSN smileys (except one) are case insensitive and work without the nose too. (O)Clock - -This list was extracted from http://help.msn.com/!data/en_us/data/messengerv50.its51/$content$/EMOTICONS.HTM?H_APP=. - - Groupchats -Since version 0.8x, BitlBee supports groupchats on the MSN and Yahoo! networks. This text will try to explain you how they work. +BitlBee now supports groupchats on all IM networks. This text will try to explain you how they work. @@ -72,7 +68,7 @@ Of course you can also create your own groupchats. Type help groupchat Creating groupchats -If you want to start a groupchat with the person jim_msn in it, just join the channel #jim_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 jim_msn in it. +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. @@ -83,23 +79,6 @@ Of course a channel with only two people isn't really exciting yet. So the next 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. - -This is all you'll probably need to know. If you have any problems, please read help groupchats3. - - - - - -Groupchat channel names - - -Obviously the (numbered) channel names don't make a lot of sense. Problem is that groupchats usually don't have names at all in the IM-world, while IRC insists on a name. So BitlBee just generates something random, just don't pay attention to it. :-) - - - -Please also note that BitlBee doesn't support groupchats for all protocols yet. BitlBee will tell you so. Support for other protocols will hopefully come later. - - @@ -120,6 +99,7 @@ Not all away states are supported by all protocols, and some protocols have diff Be right back, BRB On the phone, Phone, On phone Out to lunch, Lunch, Food + Invisible, Hidden @@ -127,7 +107,7 @@ So /away Food will set your state to "Out to lunch" on your -You can also add more information to your away message. Setting it to "Busy - Fixing BitlBee bugs" will set your IM-away-states to Busy, but your away message will be more descriptive for people on IRC. Protocols like Yahoo! and Jabber will also show this complete away message to your buddies. +You can also add more information to your away message. Setting it to "Busy - Fixing BitlBee bugs" will set your IM-away-states to Busy, but your away message will be more descriptive for people on IRC. Most IM-protocols can also show this additional information to your buddies. -- cgit v1.2.3 From 171ef85781e08ccbd8a6a018e88b1ad3cb802f78 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Mar 2008 23:17:15 +0000 Subject: Some saner error handling in ipc.c. One of the things I wanted to do for 1.2. --- ipc.c | 60 +++++++++++++++++++++++++++++++++++++++--------------------- ipc.h | 3 +++ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/ipc.c b/ipc.c index 384a9c33..54f026ac 100644 --- a/ipc.c +++ b/ipc.c @@ -257,19 +257,7 @@ gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond ) } else { - GSList *l; - struct bitlbee_child *c; - - for( l = child_list; l; l = l->next ) - { - c = l->data; - if( c->ipc_fd == source ) - { - ipc_master_free_one( c ); - child_list = g_slist_remove( child_list, c ); - break; - } - } + ipc_master_free_fd( source ); } return TRUE; @@ -287,10 +275,7 @@ gboolean ipc_child_read( gpointer data, gint source, b_input_condition cond ) } else { - b_event_remove( global.listen_watch_source_id ); - close( global.listen_socket ); - - global.listen_socket = -1; + ipc_child_disable(); } return TRUE; @@ -325,7 +310,9 @@ void ipc_to_master_str( char *format, ... ) } else if( global.conf->runmode == RUNMODE_FORKDAEMON ) { - write( global.listen_socket, msg_buf, strlen( msg_buf ) ); + if( global.listen_socket >= 0 ) + if( write( global.listen_socket, msg_buf, strlen( msg_buf ) ) <= 0 ) + ipc_child_disable(); } else if( global.conf->runmode == RUNMODE_DAEMON ) { @@ -375,12 +362,18 @@ void ipc_to_children_str( char *format, ... ) else if( global.conf->runmode == RUNMODE_FORKDAEMON ) { int msg_len = strlen( msg_buf ); - GSList *l; + GSList *l, *next; - for( l = child_list; l; l = l->next ) + for( l = child_list; l; l = next ) { struct bitlbee_child *c = l->data; - write( c->ipc_fd, msg_buf, msg_len ); + + next = l->next; + if( write( c->ipc_fd, msg_buf, msg_len ) <= 0 ) + { + ipc_master_free_one( c ); + child_list = g_slist_remove( child_list, c ); + } } } else if( global.conf->runmode == RUNMODE_DAEMON ) @@ -409,6 +402,23 @@ void ipc_master_free_one( struct bitlbee_child *c ) g_free( c ); } +void ipc_master_free_fd( int fd ) +{ + GSList *l; + struct bitlbee_child *c; + + for( l = child_list; l; l = l->next ) + { + c = l->data; + if( c->ipc_fd == fd ) + { + ipc_master_free_one( c ); + child_list = g_slist_remove( child_list, c ); + break; + } + } +} + void ipc_master_free_all() { GSList *l; @@ -420,6 +430,14 @@ void ipc_master_free_all() child_list = NULL; } +void ipc_child_disable() +{ + b_event_remove( global.listen_watch_source_id ); + close( global.listen_socket ); + + global.listen_socket = -1; +} + char *ipc_master_save_state() { char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" ); diff --git a/ipc.h b/ipc.h index 68926dfd..f3d24614 100644 --- a/ipc.h +++ b/ipc.h @@ -43,8 +43,11 @@ gboolean ipc_master_read( gpointer data, gint source, b_input_condition cond ); gboolean ipc_child_read( gpointer data, gint source, b_input_condition cond ); void ipc_master_free_one( struct bitlbee_child *child ); +void ipc_master_free_fd( int fd ); void ipc_master_free_all(); +void ipc_child_disable(); + void ipc_to_master( char **cmd ); void ipc_to_master_str( char *format, ... ) G_GNUC_PRINTF( 1, 2 ); void ipc_to_children( char **cmd ); -- cgit v1.2.3 From ed3ae7e7d41f91917fc2ae92051c7c77c357fbab Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 3 Mar 2008 00:08:49 +0000 Subject: Added note about daemon mode to doc/README --- doc/README | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/README b/doc/README index bb6596ba..ca392573 100644 --- a/doc/README +++ b/doc/README @@ -41,6 +41,20 @@ Also, don't forget to create the configuration directory (/var/lib/bitlbee/ by default) and chown it to the UID BitlBee is running as. Make sure this directory is read-/writable by this user only. +--- (Fork)Daemon mode + +If you don't want to run any inetd daemon, you can run BitlBee in Daemon +mode. Right now, daemon mode may be a bad idea on servers with multiple +users, since possible fatal BitlBee bugs will crash the BitlBee process and +disconnect all connected users at once. Instead, you can use ForkDaemon +mode, which serves every user from a separate process, without depending on +an inetd daemon. + +To use BitlBee in daemon mode, just start it with the right flags or enable +it in bitlbee.conf. You probably want to write an init script to start +BitlBee automatically after a reboot. (This is where you realise using +a package from your distro would've been a better idea. :-P) + DEPENDENCIES ============ -- cgit v1.2.3 From 7f421d6b922837857d6aca342da314225023eb46 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 3 Mar 2008 23:18:36 +0000 Subject: BitlBee <= 1.0 didn't have "account set" and allowed one to delete an account and re-create it with new login settings if necessary, without losing custom nicknames. Now, nicknames are connected to an account instead of just the protocol, and they're flushed together with the account. So I added a warning to make sure nobody accidentally loses any settings while just changing the password. This will probably go after a few releases, since it's slightly annoying. --- query.c | 10 ++++++++-- root_commands.c | 31 +++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/query.c b/query.c index 99be2bee..6f9eb77f 100644 --- a/query.c +++ b/query.c @@ -139,12 +139,18 @@ void query_answer( irc_t *irc, query_t *q, int ans ) } if( ans ) { - imcb_log( q->ic, "Accepted: %s", q->question ); + if( q->ic ) + imcb_log( q->ic, "Accepted: %s", q->question ); + else + irc_usermsg( irc, "Accepted: %s", q->question ); q->yes( NULL, q->data ); } else { - imcb_log( q->ic, "Rejected: %s", q->question ); + if( q->ic ) + imcb_log( q->ic, "Rejected: %s", q->question ); + else + irc_usermsg( irc, "Rejected: %s", q->question ); q->no( NULL, q->data ); } q->data = NULL; diff --git a/root_commands.c b/root_commands.c index 2f542826..9a60b5af 100644 --- a/root_commands.c +++ b/root_commands.c @@ -203,6 +203,26 @@ static void cmd_drop( irc_t *irc, char **cmd ) } } +void cmd_account_del_yes( gpointer w, void *data ) +{ + account_t *a = data; + irc_t *irc = a->irc; + + if( a->ic ) + { + irc_usermsg( irc, "Account is still logged in, can't delete" ); + } + else + { + account_del( irc, a ); + irc_usermsg( irc, "Account deleted" ); + } +} + +void cmd_account_del_no( gpointer w, void *data ) +{ +} + static void cmd_account( irc_t *irc, char **cmd ) { account_t *a; @@ -257,8 +277,15 @@ static void cmd_account( irc_t *irc, char **cmd ) } else { - account_del( irc, a ); - irc_usermsg( irc, "Account deleted" ); + char *msg; + + msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will " + "also forget all your saved nicknames. If you want " + "to change your username/password, use the `account " + "set' command. Are you sure you want to delete this " + "account?", a->prpl->name, a->user ); + query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, a ); + g_free( msg ); } } else if( g_strcasecmp( cmd[1], "list" ) == 0 ) -- cgit v1.2.3 From 9ad86bb22e53a40b3ad5bbc57f33d819d2748b0c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 16:09:50 +0000 Subject: Fixed issues with "long" URLs in url.c. Reusing code from 2001 wasn't a good idea... --- bitlbee.h | 2 +- lib/url.c | 24 +++++++++++++----------- lib/url.h | 18 +++++++++--------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/bitlbee.h b/bitlbee.h index c118d7fc..4a1c8b6d 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -32,7 +32,7 @@ #define BITLBEE_VERSION "1.1.1dev" #define VERSION BITLBEE_VERSION -#define MAX_STRING 128 +#define MAX_STRING 511 #if HAVE_CONFIG_H #include "config.h" diff --git a/lib/url.c b/lib/url.c index c6fdc4c8..de9966b4 100644 --- a/lib/url.c +++ b/lib/url.c @@ -25,13 +25,16 @@ #include "url.h" -/* Convert an URL to a url_t structure */ +/* Convert an URL to a url_t structure */ int url_set( url_t *url, char *set_url ) { - char s[MAX_STRING]; + char s[MAX_STRING+1]; char *i; - /* protocol:// */ + memset( url, 0, sizeof( url_t ) ); + memset( s, 0, sizeof( s ) ); + + /* protocol:// */ if( ( i = strstr( set_url, "://" ) ) == NULL ) { url->proto = PROTO_DEFAULT; @@ -48,13 +51,12 @@ int url_set( url_t *url, char *set_url ) else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 ) url->proto = PROTO_SOCKS5; else - { - return( 0 ); - } + return 0; + strncpy( s, i + 3, MAX_STRING ); } - /* Split */ + /* Split */ if( ( i = strchr( s, '/' ) ) == NULL ) { strcpy( url->file, "/" ); @@ -66,7 +68,7 @@ int url_set( url_t *url, char *set_url ) } strncpy( url->host, s, MAX_STRING ); - /* Check for username in host field */ + /* Check for username in host field */ if( strrchr( url->host, '@' ) != NULL ) { strncpy( url->user, url->host, MAX_STRING ); @@ -75,19 +77,19 @@ int url_set( url_t *url, char *set_url ) strcpy( url->host, i + 1 ); *url->pass = 0; } - /* If not: Fill in defaults */ + /* If not: Fill in defaults */ else { *url->user = *url->pass = 0; } - /* Password? */ + /* Password? */ if( ( i = strchr( url->user, ':' ) ) != NULL ) { *i = 0; strcpy( url->pass, i + 1 ); } - /* Port number? */ + /* Port number? */ if( ( i = strchr( url->host, ':' ) ) != NULL ) { *i = 0; diff --git a/lib/url.h b/lib/url.h index e9e1ecfe..8c038c91 100644 --- a/lib/url.h +++ b/lib/url.h @@ -25,20 +25,20 @@ #include "bitlbee.h" -#define PROTO_HTTP 2 -#define PROTO_HTTPS 5 -#define PROTO_SOCKS4 3 -#define PROTO_SOCKS5 4 -#define PROTO_DEFAULT PROTO_HTTP +#define PROTO_HTTP 2 +#define PROTO_HTTPS 5 +#define PROTO_SOCKS4 3 +#define PROTO_SOCKS5 4 +#define PROTO_DEFAULT PROTO_HTTP typedef struct url { int proto; int port; - char host[MAX_STRING]; - char file[MAX_STRING]; - char user[MAX_STRING]; - char pass[MAX_STRING]; + char host[MAX_STRING+1]; + char file[MAX_STRING+1]; + char user[MAX_STRING+1]; + char pass[MAX_STRING+1]; } url_t; int url_set( url_t *url, char *set_url ); -- cgit v1.2.3 From a869d9147584de96a0ac341416e551953167800f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 17:44:21 +0000 Subject: Indicate that we support YMSG protocol version 12, this should hopefully keep BitlBee working after 2008-04-02 . --- protocols/yahoo/libyahoo2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index ce38bc73..4e93449e 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -736,7 +736,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, 0x0a00); + pos += yahoo_put16(data + pos, 0x000c); pos += yahoo_put16(data + pos, 0x0000); pos += yahoo_put16(data + pos, pktlen + extra_pad); pos += yahoo_put16(data + pos, pkt->service); -- cgit v1.2.3 From 79eae4a9edb343eaad30425289f7737467a535bb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 21:05:39 +0000 Subject: Inviting someone to a Yahoo! chatroom with msg=NULL is bad. I wonder if /invite ever worked in the Yahoo! module... --- protocols/yahoo/yahoo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 9f9ffcf7..36579d66 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -314,7 +314,7 @@ static void byahoo_chat_invite( struct groupchat *c, char *who, char *msg ) { struct byahoo_data *yd = (struct byahoo_data *) c->ic->proto_data; - yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ); + yahoo_conference_invite( yd->y2_id, NULL, c->data, c->title, msg ? msg : "" ); } static void byahoo_chat_leave( struct groupchat *c ) -- cgit v1.2.3 From 4bb50efd1015a04d44c301961710fa08e0eda162 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Mar 2008 23:53:54 +0000 Subject: Although I have no idea what the author meant with code like `if(cp != "\005")', I'm sure he feels homesick to QuickBasic. Since BitlBee doesn't use this function anyway, it doesn't really matter if my fix works. As long as it keeps the compiler quiet. --- protocols/yahoo/libyahoo2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index 4e93449e..80d88a85 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -3350,7 +3350,7 @@ static void yahoo_process_search_connection(struct yahoo_input_data *yid, int ov yct->age = atoi(cp); break; case 5: - if(cp != "\005") + if(strcmp(cp, "5") != 0) yct->location = cp; k = 0; break; -- cgit v1.2.3 From d07c3a8cde47096ad69db7139d410dfee29e509b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 00:40:20 +0000 Subject: No idea what's holding back 1.2 anymore so at least I'll make sure bitlbee.h is correct. Also updated the changelog. Just remembered 1 or 2 things left to do before 1.2, maybe do them tomorrow? --- bitlbee.h | 2 +- doc/CHANGES | 21 +++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/bitlbee.h b/bitlbee.h index 4a1c8b6d..420ab70a 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -29,7 +29,7 @@ #define _GNU_SOURCE /* Stupid GNU :-P */ #define PACKAGE "BitlBee" -#define BITLBEE_VERSION "1.1.1dev" +#define BITLBEE_VERSION "1.2" #define VERSION BITLBEE_VERSION #define MAX_STRING 511 diff --git a/doc/CHANGES b/doc/CHANGES index ee4cde69..959c11fd 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,7 +1,4 @@ Version 1.2: -- First BitlBee development/testing RELEASE. This should be quite stable - though (and for most people more stable than 1.0.x). It just has a couple - of rough edges and needs a bit more testing. - Added ForkDaemon mode next to the existing Daemon- and inetd modes. With ForkDaemon you can run BitlBee as a stand-alone daemon and every connection will run in its own process. No more need to configure inetd, and still you @@ -20,9 +17,16 @@ Version 1.2: This allows us to use more GLib features (like the XML parser). By now GLib 1.x is so old that supporting it really isn't necessary anymore. - Many, many, MANY little changes, improvements, fixes. Using non-blocking - I/O as much as possible, fixed lots of little bugs (including bugs that - affected daemon mode stability). See the bzr logs for more information. -- Added units tests, will have to add some more before the real release. + I/O as much as possible, replaced the Gaim (0.59, IOW heavily outdated) + API, fixed lots of little bugs (including bugs that affected daemon mode + stability). See the bzr logs for more information. +- One of the user-visible changes from the API change: You can finally see + all away states/messages properly. +- Added units tests. Test coverage is very minimal for now. +- Better charset handling: Everything is just converted from/to UTF-8 right + in the IRC core, and charset mismatches are detected (if possible) and the + user is asked to resolve this before continuing. Also, UTF-8 is the default + setting now, since that's how the world seems to work these days. - Most important change: New file format for user data (accounts, nicks and settings). Migration to the new format should happen transparently, BitlBee will read the old files and once you quit/save it will save in the @@ -68,6 +72,11 @@ Version 1.2: buddy is in your contact list.) * An XML console (add xmlconsole to your contact list or see "help set xmlconsole" if you want it permanently). +- The Yahoo! module now says it supports YMSG protocol version 12, which will + hopefully keep the Yahoo module working after 2008-04-02 (when Yahoo! is + dropping support for version 6.x of their client). +- MSN switchboard handling changes. Hopefully less messages will get lost now, + although things are still not perfect. Finished ??? -- cgit v1.2.3 From ddcf491fa460fea612c240589c50da864dad6668 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 14:18:22 +0000 Subject: Adding padding to encrypted IM-passwords so the exact password length can't be guessed from the encrypted data anymore. --- lib/arc.c | 27 +++++++++++++++++++++++++-- lib/arc.h | 4 ++-- storage_xml.c | 2 +- tests/check_arc.c | 35 ++++++++++++++++++++++------------- 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/lib/arc.c b/lib/arc.c index 617f6b96..fd498454 100644 --- a/lib/arc.c +++ b/lib/arc.c @@ -130,18 +130,40 @@ unsigned char arc_getbyte( struct arc_state *st ) don't need it anymore. Both functions return the number of bytes in the result string. + + Note that if you use the pad_to argument, you will need zero-termi- + nation to find back the original string length after decryption. So + it shouldn't be used if your string contains \0s by itself! */ -int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password ) +int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password, int pad_to ) { struct arc_state *st; unsigned char *key; - int key_len, i; + char *padded = NULL; + int key_len, i, padded_len; key_len = strlen( password ) + ARC_IV_LEN; if( clear_len <= 0 ) clear_len = strlen( clear ); + /* Pad the string to the closest multiple of pad_to. This makes it + impossible to see the exact length of the password. */ + if( pad_to > 0 && ( clear_len % pad_to ) > 0 ) + { + padded_len = clear_len + pad_to - ( clear_len % pad_to ); + padded = g_malloc( padded_len ); + memcpy( padded, clear, clear_len ); + + /* First a \0 and then random data, so we don't have to do + anything special when decrypting. */ + padded[clear_len] = 0; + random_bytes( (unsigned char*) padded + clear_len + 1, padded_len - clear_len - 1 ); + + clear = padded; + clear_len = padded_len; + } + /* Prepare buffers and the key + IV */ *crypt = g_malloc( clear_len + ARC_IV_LEN ); key = g_malloc( key_len ); @@ -160,6 +182,7 @@ int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *passwor crypt[0][i+ARC_IV_LEN] = clear[i] ^ arc_getbyte( st ); g_free( st ); + g_free( padded ); return clear_len + ARC_IV_LEN; } diff --git a/lib/arc.h b/lib/arc.h index 882372ed..58f30d3d 100644 --- a/lib/arc.h +++ b/lib/arc.h @@ -30,7 +30,7 @@ struct arc_state unsigned char i, j; }; -struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ); +G_GNUC_MALLOC struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ); unsigned char arc_getbyte( struct arc_state *st ); -int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password ); +int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password, int pad_to ); int arc_decode( unsigned char *crypt, int crypt_len, char **clear, char *password ); diff --git a/storage_xml.c b/storage_xml.c index 19070a74..6ea4d442 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -427,7 +427,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) char *pass_b64; int pass_len; - pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password ); + pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password, 12 ); pass_b64 = base64_encode( pass_cr, pass_len ); g_free( pass_cr ); diff --git a/tests/check_arc.c b/tests/check_arc.c index a430f899..9d913dcd 100644 --- a/tests/check_arc.c +++ b/tests/check_arc.c @@ -6,13 +6,14 @@ #include #include "arc.h" -char *password = "TotT"; +char *password = "ArcVier"; char *clear_tests[] = { "Wie dit leest is gek :-)", "ItllBeBitlBee", "One more boring password", + "Hoi hoi", NULL }; @@ -27,7 +28,7 @@ static void check_codec(int l) char *decrypted; int len; - len = arc_encode( clear_tests[i], 0, &crypted, password ); + len = arc_encode( clear_tests[i], 0, &crypted, password, 12 ); len = arc_decode( crypted, len, &decrypted, password ); fail_if( strcmp( clear_tests[i], decrypted ) != 0, @@ -40,27 +41,35 @@ static void check_codec(int l) struct { - unsigned char crypted[24]; + unsigned char crypted[30]; int len; char *decrypted; } decrypt_tests[] = { + /* One block with padding. */ { { - 0xc3, 0x0d, 0x43, 0xc3, 0xee, 0x80, 0xe2, 0x8c, 0x0b, 0x29, 0x32, 0x7e, - 0x38, 0x05, 0x82, 0x10, 0x21, 0x1c, 0x4a, 0x00, 0x2c - }, 21, "Debugging sucks" + 0x3f, 0x79, 0xb0, 0xf5, 0x91, 0x56, 0xd2, 0x1b, 0xd1, 0x4b, 0x67, 0xac, + 0xb1, 0x31, 0xc9, 0xdb, 0xf9, 0xaa + }, 18, "short pass" }, + + /* Two blocks with padding. */ { { - 0xb0, 0x00, 0x57, 0x0d, 0x0d, 0x0d, 0x70, 0xe1, 0xc0, 0x00, 0xa4, 0x25, - 0x7d, 0xbe, 0x03, 0xcc, 0x24, 0xd1, 0x0c - }, 19, "Testing rocks" + 0xf9, 0xa6, 0xec, 0x5d, 0xc7, 0x06, 0xb8, 0x6b, 0x63, 0x9f, 0x2d, 0xb5, + 0x7d, 0xaa, 0x32, 0xbb, 0xd8, 0x08, 0xfd, 0x81, 0x2e, 0xca, 0xb4, 0xd7, + 0x2f, 0x36, 0x9c, 0xac, 0xa0, 0xbc + }, 30, "longer password" }, + + /* This string is exactly two "blocks" long, to make sure unpadded strings also decrypt + properly. */ { { - 0xb6, 0x92, 0x59, 0xe4, 0xf9, 0xc1, 0x7a, 0xf6, 0xf3, 0x18, 0xea, 0x28, - 0x73, 0x6d, 0xb3, 0x0a, 0x6f, 0x0a, 0x2b, 0x43, 0x57, 0xe9, 0x3e, 0x63 - }, 24, "OSCAR is creepy..." + 0x95, 0x4d, 0xcf, 0x4d, 0x5e, 0x6c, 0xcf, 0xef, 0xb9, 0x80, 0x00, 0xef, + 0x25, 0xe9, 0x17, 0xf6, 0x29, 0x6a, 0x82, 0x79, 0x1c, 0xca, 0x68, 0xb5, + 0x4e, 0xd0, 0xc1, 0x41, 0x8e, 0xe6 + }, 30, "OSCAR is really creepy.." }, { "", 0, NULL } }; @@ -79,7 +88,7 @@ static void check_decod(int l) &decrypted, password ); fail_if( strcmp( decrypt_tests[i].decrypted, decrypted ) != 0, - "%s didn't decrypt properly", clear_tests[i] ); + "`%s' didn't decrypt properly", decrypt_tests[i].decrypted ); g_free( decrypted ); } -- cgit v1.2.3 From e960a523f587a83bd22d000b4451c5a21b2951e8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 14:39:34 +0000 Subject: Fixed cached_id_prefix memory leak. --- protocols/jabber/jabber.c | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 243ed7fd..0e23b4d4 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -266,6 +266,7 @@ static void jabber_logout( struct im_connection *ic ) xt_free( jd->xt ); + g_free( jd->cached_id_prefix ); g_free( jd->away_message ); g_free( jd->username ); g_free( jd ); -- cgit v1.2.3 From 50d26f33935aadc556dd3e79829b1ca01bbceab9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 15:28:37 +0000 Subject: Fixed base64_decode() to not barf on corrupted Base64 strings. --- lib/base64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/base64.c b/lib/base64.c index 64e9692a..ea0db6b9 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -117,7 +117,7 @@ int base64_decode_real(const unsigned char *in, unsigned char *out, char *b64rev { int i, outlen = 0; - for( i = 0; in[i]; i += 4 ) + for( i = 0; in[i] && in[i+1] && in[i+2] && in[i+3]; i += 4 ) { int sx; -- cgit v1.2.3 From 4e8db1c0141f74dc6156a57739613483344b358d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 16:03:52 +0000 Subject: Moved password hash verification to md5_verify_password() so this can be reused for IRC/OPER passwords (to have encrypted in bitlbee.conf). --- lib/misc.c | 41 +++++++++++++++++++++++++++++++++++++++++ lib/misc.h | 2 ++ storage_xml.c | 41 +++++++++++------------------------------ 3 files changed, 54 insertions(+), 30 deletions(-) diff --git a/lib/misc.c b/lib/misc.c index 18d98f9e..ccf208b5 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -32,6 +32,7 @@ #define BITLBEE_CORE #include "nogaim.h" +#include "base64.h" #include #include #include @@ -596,3 +597,43 @@ gboolean ssl_sockerr_again( void *ssl ) else return sockerr_again(); } + +/* Returns values: -1 == Failure (base64-decoded to something unexpected) + 0 == Okay + 1 == Password doesn't match the hash. */ +int md5_verify_password( char *password, char *hash ) +{ + md5_byte_t *pass_dec = NULL; + md5_byte_t pass_md5[16]; + md5_state_t md5_state; + int ret, i; + + if( base64_decode( hash, &pass_dec ) != 21 ) + { + ret = -1; + } + else + { + md5_init( &md5_state ); + md5_append( &md5_state, (md5_byte_t*) password, strlen( password ) ); + md5_append( &md5_state, (md5_byte_t*) pass_dec + 16, 5 ); /* Hmmm, salt! */ + md5_finish( &md5_state, pass_md5 ); + + for( i = 0; i < 16; i ++ ) + { + if( pass_dec[i] != pass_md5[i] ) + { + ret = 1; + break; + } + } + + /* If we reached the end of the loop, it was a match! */ + if( i == 16 ) + ret = 0; + } + + g_free( pass_dec ); + + return ret; +} diff --git a/lib/misc.h b/lib/misc.h index 7804bfb1..a2acada6 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -66,4 +66,6 @@ G_MODULE_EXPORT char *word_wrap( char *msg, int line_len ); G_MODULE_EXPORT gboolean ssl_sockerr_again( void *ssl ); +G_MODULE_EXPORT int md5_verify_password( char *password, char *hash ); + #endif diff --git a/storage_xml.c b/storage_xml.c index 6ea4d442..f37fce44 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -79,49 +79,30 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { char *nick = xml_attr( attr_names, attr_values, "nick" ); char *pass = xml_attr( attr_names, attr_values, "password" ); - md5_byte_t *pass_dec = NULL; + int st; if( !nick || !pass ) { g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Missing attributes for %s element", element_name ); } - else if( base64_decode( pass, &pass_dec ) != 21 ) + else if( ( st = md5_verify_password( xd->given_pass, pass ) ) == -1 ) { + xd->pass_st = XML_PASS_WRONG; g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Error while decoding password attribute" ); } + else if( st == 0 ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } else { - md5_byte_t pass_md5[16]; - md5_state_t md5_state; - int i; - - md5_init( &md5_state ); - md5_append( &md5_state, (md5_byte_t*) xd->given_pass, strlen( xd->given_pass ) ); - md5_append( &md5_state, (md5_byte_t*) pass_dec + 16, 5 ); /* Hmmm, salt! */ - md5_finish( &md5_state, pass_md5 ); - - for( i = 0; i < 16; i ++ ) - { - if( pass_dec[i] != pass_md5[i] ) - { - xd->pass_st = XML_PASS_WRONG; - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - "Password mismatch" ); - break; - } - } - - /* If we reached the end of the loop, it was a match! */ - if( i == 16 ) - { - if( xd->pass_st != XML_PASS_CHECK_ONLY ) - xd->pass_st = XML_PASS_OK; - } + xd->pass_st = XML_PASS_WRONG; + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Password mismatch" ); } - - g_free( pass_dec ); } else if( xd->pass_st < XML_PASS_OK ) { -- cgit v1.2.3 From ec0355f6998eb5dee254e4bc60a3207bb661c854 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 16:31:27 +0000 Subject: Passwords in bitlbee.conf can now be (properly salted) MD5 hashes, for just that little bit extra security. --- bitlbee.conf | 7 +++++++ doc/CHANGES | 2 ++ irc_commands.c | 10 ++++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/bitlbee.conf b/bitlbee.conf index d9f878c8..99e8106d 100644 --- a/bitlbee.conf +++ b/bitlbee.conf @@ -48,14 +48,21 @@ ## AuthPassword ## ## Password the user should enter when logging into a closed BitlBee server. +## You can also have an MD5-encrypted password here. Format: "md5:", followed +## by a hash as generated for the attribute in a BitlBee +## XML file (for now there's no easier way to generate the hash). ## # AuthPassword = ItllBeBitlBee ## Heh.. Our slogan. ;-) +## or +# AuthPassword = md5:gzkK0Ox/1xh+1XTsQjXxBJ571Vgl ## OperPassword ## ## Password that unlocks access to special operator commands. ## # OperPassword = ChangeMe! +## or +# OperPassword = md5:I0mnZbn1t4R731zzRdDN2/pK7lRX ## HostName ## diff --git a/doc/CHANGES b/doc/CHANGES index 959c11fd..b3c3b711 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -27,6 +27,8 @@ Version 1.2: in the IRC core, and charset mismatches are detected (if possible) and the user is asked to resolve this before continuing. Also, UTF-8 is the default setting now, since that's how the world seems to work these days. +- One can now keep hashed passwords in bitlbee.conf instead of the cleartext + version. - Most important change: New file format for user data (accounts, nicks and settings). Migration to the new format should happen transparently, BitlBee will read the old files and once you quit/save it will save in the diff --git a/irc_commands.c b/irc_commands.c index 68db4617..14209732 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -29,7 +29,10 @@ static void irc_cmd_pass( irc_t *irc, char **cmd ) { - if( global.conf->auth_pass && strcmp( cmd[1], global.conf->auth_pass ) == 0 ) + if( global.conf->auth_pass && + strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ? + md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 : + strcmp( cmd[1], global.conf->auth_pass ) == 0 ) { irc->status |= USTATUS_AUTHORIZED; irc_check_login( irc ); @@ -87,7 +90,10 @@ static void irc_cmd_ping( irc_t *irc, char **cmd ) static void irc_cmd_oper( irc_t *irc, char **cmd ) { - if( global.conf->oper_pass && strcmp( cmd[2], global.conf->oper_pass ) == 0 ) + if( global.conf->oper_pass && + strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ? + md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 : + strcmp( cmd[2], global.conf->oper_pass ) == 0 ) { irc_umode_set( irc, "+o", 1 ); irc_reply( irc, 381, ":Password accepted" ); -- cgit v1.2.3 From c029350d962d95c2d5e9854ca4d82e597addf76d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 16 Mar 2008 17:17:23 +0000 Subject: Added some brackets in irc_cmd_(pass|oper) to prevent crashes when no passwords were set. --- irc_commands.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/irc_commands.c b/irc_commands.c index 14209732..b8bae541 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -30,9 +30,9 @@ static void irc_cmd_pass( irc_t *irc, char **cmd ) { if( global.conf->auth_pass && - strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ? - md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 : - strcmp( cmd[1], global.conf->auth_pass ) == 0 ) + ( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ? + md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 : + strcmp( cmd[1], global.conf->auth_pass ) == 0 ) ) { irc->status |= USTATUS_AUTHORIZED; irc_check_login( irc ); @@ -91,9 +91,9 @@ static void irc_cmd_ping( irc_t *irc, char **cmd ) static void irc_cmd_oper( irc_t *irc, char **cmd ) { if( global.conf->oper_pass && - strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ? - md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 : - strcmp( cmd[2], global.conf->oper_pass ) == 0 ) + ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ? + md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 : + strcmp( cmd[2], global.conf->oper_pass ) == 0 ) ) { irc_umode_set( irc, "+o", 1 ); irc_reply( irc, 381, ":Password accepted" ); -- cgit v1.2.3 From 6612cc9dd32475569875030f5acc7cc4b0374ba6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 17 Mar 2008 22:35:24 +0000 Subject: Release 1.2 should now be ready. --- doc/CHANGES | 2 +- doc/RELEASE-SPEECH-1.2 | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 doc/RELEASE-SPEECH-1.2 diff --git a/doc/CHANGES b/doc/CHANGES index b3c3b711..65947617 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -80,7 +80,7 @@ Version 1.2: - MSN switchboard handling changes. Hopefully less messages will get lost now, although things are still not perfect. -Finished ??? +Finished 17 Mar 2008 Version 1.0.4: - Removed sethostent(), which causes problems for many people, especially on diff --git a/doc/RELEASE-SPEECH-1.2 b/doc/RELEASE-SPEECH-1.2 new file mode 100644 index 00000000..ec7c48b4 --- /dev/null +++ b/doc/RELEASE-SPEECH-1.2 @@ -0,0 +1,57 @@ +BitlBee ... is Bitl +------------------- + +"I CAN HAS SPEEECH?" This is how Wilmer announced to me that he was going to do +another BitlBee release. I was as surprised as you are. I thought he had given +up on this whole releasing business. + +There is some humor in using a LOLcats reference to announce a new Bee +release. The last major BitlBee release (1.0) was done a long time before the +hype even begun. Between then and now we've celebrated BitlBee's fifth birthday +and had a handful of releases, but nothing big happened. As a user this lax +release planning worries me. What if this means that later releases will take +even longer? I don't think we should fear this. Let us explore why this release +took so long. + +Personally, I blame Google. + +There, I've said it. Google. The guys who are so big on "Do No Evil" and all +that jazz. They caused this release to be so late. Let me explain why. + +They made Wilmer an offer. Wilmer, being the sillily naive guy he is, couldn't +refuse. There were no decapitated horses involved, but he couldn't refuse +nonetheless. That's not a big problem of course. Lots of guys (and gals, sure) +work for Google. It wouldn't have become a problem if they hadn't shipped him of +to Ireland. That's where the trouble starts. + +Ireland. Home of the leprechauns. These rascals joined forces with aliens and +LOLcats to abduct Wilmer. The aliens had been trying for years to kidnap him, +but they were on his turf and his trusty sidekicks Jelmer and Maurits were there +to help him. All that changed when he moved to Ireland. + +But it wasn't just that Wilmer was all alone in some strange place. It was also +that the aliens had created the LOLcats and made an alliance with the +leprechauns--the real rulers of Ireland. Wilmer is cool, but he's not that +cool. So they abducted him for a few years. When he finally came back, he +regathered his mad coding skills and hacked a new release together. + +By now you're thinking, what has happened to Jelmer and Maurits? Well, they're +still here and they worked on the Bee while Wilmer was absent. But, like open +source, they are very Bitl--they're cool, but they're ready when they're +ready. + +Well, whatever you may think of my little theory, they did take forever to +launch this release. We're not mad at them, because it shows. They have +added some cool new features and made plenty of changes under the hood. Let me +give you a sneak preview of some of the new features: Jabber groupchats are +supported. Configuration files are stored encrypted. You can now use +ForkDaemon mode, which gives better stability over normal daemon mode, but +doesn't require inetd. Also, server owners can now use the /OPER command to +spy on their users. And--as I was specifically asked to mention--this is the +first stable release that supports plugins. That's some Bitl changes for ya. + +BitlBee is cool, but ready when it's ready. Very Bitl. + +Sjoerd. LOL. + +(LOLBee by Erik Bosman.) -- cgit v1.2.3 From 379c08a27e637dbcbbe3f39a8723daa765ad0e48 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 21 Mar 2008 00:27:24 +0000 Subject: Updated/Fixed Debian package. --- debian/README.Debian | 4 ++-- debian/changelog | 25 +++++++++++++++++++++++-- debian/control | 2 +- debian/po/it.po | 36 ++++++++++++++++++++++++++++++++++++ debian/postinst | 9 ++++++++- debian/postrm | 3 ++- debian/rules | 9 ++++++--- 7 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 debian/po/it.po diff --git a/debian/README.Debian b/debian/README.Debian index e2102fc8..6056f488 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -1,6 +1,6 @@ - *** NEWS (Version 1.1 and later) *** + *** NEWS (Version 1.2 and later) *** -Starting from version 1.1, BitlBee has a forking daemon mode. The Debian +Starting from version 1.2, BitlBee has a forking daemon mode. The Debian package now uses this mode by default, instead of inetd mode. If you don't want to use this, you can disable the init scripts (best way to do this is by editing /etc/default/bitlbee) and restore the inetd.conf entry. This diff --git a/debian/changelog b/debian/changelog index ae524f73..2cf6510c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,33 @@ -bitlbee (1.1.1dev-0pre) unstable; urgency=low +bitlbee (1.2-1) unstable; urgency=low + * New upstream release. (Closes: #325017, #386914, #437515) + * With hopefully completely sane charset handling (Closes: #296145) * Switched to the new forking daemon mode. Added /etc/default/bitlbee file, an init script. People who want to stick with inetd can do so, see the defaults file. + (Closes: #460741, #466171, #294585, #345038, #306452, #392682) * Got rid of debconf Woody compatibility stuff. * No more MPL code in BitlBee, thanks to the Jabber module rewrite! + * Added Italian translation, sorry for taking so long! (Closes: #448238) + * Added libevent dependency (more reliable event handling). + * Removed GLib 1.x dependency because BitlBee really requires GLib >=2.4. - -- Wilmer van der Gaast Fri, 06 Jul 2007 09:09:36 +0100 + -- Wilmer van der Gaast Tue, 18 Mar 2008 23:44:19 +0000 + +bitlbee (1.0.4-2) unstable; urgency=low + + * Removed $DEB_BUILD_OPTIONS because apparently buildds fill it with crap. + (Closes: #458717) + + -- Wilmer van der Gaast Mon, 11 Feb 2008 19:15:33 +0000 + +bitlbee (1.0.4-1) unstable; urgency=low + + * New upstream release. + * Changed libnss-dev dependency. (Closes: #370442) + * Added build-indep rule to debian/rules. (Closes: #395673) + + -- Wilmer van der Gaast Wed, 29 Aug 2007 20:24:28 +0100 bitlbee (1.0.3-1.3) unstable; urgency=low diff --git a/debian/control b/debian/control index 139174a6..8383391b 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: net Priority: optional Maintainer: Wilmer van der Gaast Standards-Version: 3.5.9 -Build-Depends: libglib2.0-dev | libglib-dev, libgnutls-dev | libnss-dev (>= 1.6), debconf-2.0, po-debconf +Build-Depends: libglib2.0-dev (>= 2.4), libevent-dev, libgnutls-dev | libnss-dev (>= 1.6), debconf-2.0, po-debconf Package: bitlbee Architecture: any diff --git a/debian/po/it.po b/debian/po/it.po new file mode 100644 index 00000000..e149e61a --- /dev/null +++ b/debian/po/it.po @@ -0,0 +1,36 @@ +# Italian translation of the bitlbee debconf template +# This file is distributed under the same license as the bitlbee package +# Copyright (C) 2007 Free Software Foundation, Inc. +# Luca Monducci , 2007. +# +msgid "" +msgstr "" +"Project-Id-Version: bitlbee\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2007-08-30 04:31+0200\n" +"PO-Revision-Date: 2007-10-27 11:52+0200\n" +"Last-Translator: Luca Monducci \n" +"Language-Team: Italian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../bitlbee.templates.master:1001 +msgid "On what TCP port should BitlBee listen for connections?" +msgstr "Su quale porta TCP si deve mettere in ascolto BitlBee?" + +#. Type: string +#. Description +#: ../bitlbee.templates.master:1001 +msgid "" +"BitlBee normally listens on the regular IRC port, 6667. This might not be a " +"very good idea when you're running a real IRC daemon as well. 6668 might be " +"a good alternative. Leaving this value blank means that BitlBee will not be " +"run automatically." +msgstr "" +"Normalmente BitlBee si mette in ascolto sulla consueta porta IRC, la 6667. " +"Questa potrebbe non essere una buona idea se è in esecuzione anche un reale " +"demone IRC. La porta 6668 potrebbe essere una valida alternativa. Lasciando " +"vuoto questo valore BitlBee non viene avviato automaticamente." diff --git a/debian/postinst b/debian/postinst index 37608e47..c4edb8e8 100755 --- a/debian/postinst +++ b/debian/postinst @@ -15,9 +15,16 @@ BITLBEE_DISABLED=0 BITLBEE_UPGRADE_DONT_RESTART=0 [ -r /etc/default/bitlbee ] && source /etc/default/bitlbee -if [ "$BITLBEE_DISABLED" = "0" ]; then +if [ "$BITLBEE_DISABLED" = "0" ] && expr "$2" : '0\..*' > /dev/null || expr "$2" : '1\.0\..*' > /dev/null; then ## In case it's still there (if we're upgrading right now) update-inetd --remove '.*/usr/sbin/bitlbee' + if grep -q /usr/sbin/bitlbee /etc/inetd.conf 2> /dev/null; then + # Thanks for breaking update-inetd! (bugs.debian.org/311111) + # I hope that it works at least with xinetd, because this + # emergency hack doesn't: + perl -pi -e 's:^[^#].*/usr/sbin/bitlbee$:## Now using daemon mode\: # $&:' /etc/inetd.conf + killall -HUP inetd + fi fi cat</etc/default/bitlbee diff --git a/debian/postrm b/debian/postrm index cef99f13..f7686e7b 100755 --- a/debian/postrm +++ b/debian/postrm @@ -8,4 +8,5 @@ if [ -e /usr/share/debconf/confmodule ]; then fi update-rc.d bitlbee remove > /dev/null 2>&1 || true -deluser --remove-home bitlbee || true +deluser --system --remove-home bitlbee || true +rm -f /etc/default/bitlbee diff --git a/debian/rules b/debian/rules index 8d6bd4fa..0c757899 100755 --- a/debian/rules +++ b/debian/rules @@ -2,15 +2,18 @@ DEBUG ?= 0 +ifdef BITLBEE_VERSION +BITLBEE_FORCE_VERSION=1 +else # Want to use the full package version number instead of just the release. BITLBEE_VERSION ?= "$(shell dpkg-parsechangelog | grep ^Version: | awk '{print $$2}')" export BITLBEE_VERSION - +endif build-arch: build-arch-stamp build-arch-stamp: if [ ! -d debian ]; then exit 1; fi - ./configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee $(DEB_BUILD_OPTIONS) + ./configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent $(DEB_BUILD_OPTIONS) $(MAKE) # $(MAKE) -C doc/ all touch build-arch-stamp @@ -65,7 +68,7 @@ binary-arch: build-arch install-arch cd debian/bitlbee; \ find usr -type f -exec md5sum {} \; > DEBIAN/md5sums dpkg-shlibdeps -Tdebian/bitlbee.substvars -dDepends debian/bitlbee/usr/sbin/bitlbee -ifdef BITLBEE_VERSION +ifdef BITLBEE_FORCE_VERSION dpkg-gencontrol -ldebian/changelog -isp -pbitlbee -Tdebian/bitlbee.substvars -Pdebian/bitlbee -v1:$(BITLBEE_VERSION)-0 -V'debconf-depends=debconf (>= 1.2.0) | debconf-2.0' else dpkg-gencontrol -ldebian/changelog -isp -pbitlbee -Tdebian/bitlbee.substvars -Pdebian/bitlbee -V'debconf-depends=debconf (>= 1.2.0) | debconf-2.0' -- cgit v1.2.3 From a83442a7c4dbf99937e9e5397e5665c671694161 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 21 Mar 2008 00:39:16 +0000 Subject: Fixed handling of "set charset none". Fixes bug #373. --- irc.c | 7 ++++--- set.c | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/irc.c b/irc.c index 3a09f684..3589256e 100644 --- a/irc.c +++ b/irc.c @@ -308,7 +308,7 @@ void irc_process( irc_t *irc ) break; } - if( ( cs = set_getstr( &irc->set, "charset" ) ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) && g_strcasecmp( cs, "none" ) != 0 ) { conv[IRC_MAX_LINE] = 0; if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 ) @@ -329,7 +329,7 @@ void irc_process( irc_t *irc ) else { irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, - "Warning: invalid (non-UTF8) characters received at login time." ); + "Warning: invalid characters received at login time." ); strncpy( conv, lines[i], IRC_MAX_LINE ); for( temp = conv; *temp; temp ++ ) @@ -553,7 +553,8 @@ void irc_vawrite( irc_t *irc, char *format, va_list params ) g_vsnprintf( line, IRC_MAX_LINE - 2, format, params ); strip_newlines( line ); - if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) && + g_strcasecmp( cs, "none" ) != 0 && g_strcasecmp( cs, "utf-8" ) != 0 ) { char conv[IRC_MAX_LINE+1]; diff --git a/set.c b/set.c index 6f09843b..90b29f91 100644 --- a/set.c +++ b/set.c @@ -234,7 +234,7 @@ char *set_eval_charset( set_t *set, char *value ) { GIConv cd; - if ( g_strncasecmp( value, "none", 4 ) == 0 ) + if( g_strcasecmp( value, "none" ) == 0 ) return value; cd = g_iconv_open( "UTF-8", value ); -- cgit v1.2.3 From 851a8c29c681cdc3c9838ed99486822cba927f60 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 22 Mar 2008 12:02:50 +0000 Subject: Taught GLib-mode subprocesses how to die. (Closes: #374) --- lib/events_glib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/events_glib.c b/lib/events_glib.c index 1198dba6..3e194e98 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -50,11 +50,12 @@ typedef struct _GaimIOClosure { gpointer data; } GaimIOClosure; -static GMainLoop *loop; +static GMainLoop *loop = NULL; void b_main_init() { - loop = g_main_new( FALSE ); + if( loop == NULL ) + loop = g_main_new( FALSE ); } void b_main_run() -- cgit v1.2.3 From 8a2221a79b177a5c6d0b55dafebd39414d7fe10a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 23 Mar 2008 14:29:19 +0000 Subject: Fixed stalling issue with OpenSSL and Jabber (#368). --- lib/ssl_client.h | 3 +++ lib/ssl_gnutls.c | 6 ++++++ lib/ssl_nss.c | 6 ++++++ lib/ssl_openssl.c | 23 +++++++++++++++++++---- protocols/jabber/io.c | 9 +++++++-- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/ssl_client.h b/lib/ssl_client.h index dcbf9a01..f91d0d70 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -59,6 +59,9 @@ G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer da G_MODULE_EXPORT int ssl_read( void *conn, char *buf, int len ); G_MODULE_EXPORT int ssl_write( void *conn, const char *buf, int len ); +/* See ssl_openssl.c for an explanation. */ +G_MODULE_EXPORT int ssl_pending( void *conn ); + /* Abort the SSL connection and disconnect the socket. Do not use close() directly, both the SSL library and the peer will be unhappy! */ G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c index b964ab49..f5945442 100644 --- a/lib/ssl_gnutls.c +++ b/lib/ssl_gnutls.c @@ -210,6 +210,12 @@ int ssl_write( void *conn, const char *buf, int len ) return st; } +/* See ssl_openssl.c for an explanation. */ +int ssl_pending( void *conn ) +{ + return 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c index 218b3a80..eba3c441 100644 --- a/lib/ssl_nss.c +++ b/lib/ssl_nss.c @@ -168,6 +168,12 @@ int ssl_write( void *conn, const char *buf, int len ) return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); } +/* See ssl_openssl.c for an explanation. */ +int ssl_pending( void *conn ) +{ + return 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c index b1ba1db9..fc6d433e 100644 --- a/lib/ssl_openssl.c +++ b/lib/ssl_openssl.c @@ -61,16 +61,16 @@ void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data struct scd *conn = g_new0( struct scd, 1 ); conn->fd = proxy_connect( host, port, ssl_connected, conn ); - conn->func = func; - conn->data = data; - conn->inpa = -1; - if( conn->fd < 0 ) { g_free( conn ); return NULL; } + conn->func = func; + conn->data = data; + conn->inpa = -1; + return conn; } @@ -230,6 +230,21 @@ int ssl_write( void *conn, const char *buf, int len ) return st; } +/* Only OpenSSL *really* needs this (and well, maybe NSS). See for more info: + http://www.gnu.org/software/gnutls/manual/gnutls.html#index-gnutls_005frecord_005fcheck_005fpending-209 + http://www.openssl.org/docs/ssl/SSL_pending.html + + Required because OpenSSL empties the TCP buffer completely but doesn't + necessarily give us all the unencrypted data. + + Returns 0 if there's nothing left or if we don't have to care (GnuTLS), + 1 if there's more data. */ +int ssl_pending( void *conn ) +{ + return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ? + SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0; +} + void ssl_disconnect( void *conn_ ) { struct scd *conn = conn_; diff --git a/protocols/jabber/io.c b/protocols/jabber/io.c index 9980dc8e..10efad37 100644 --- a/protocols/jabber/io.c +++ b/protocols/jabber/io.c @@ -240,8 +240,13 @@ static gboolean jabber_read_callback( gpointer data, gint fd, b_input_condition return FALSE; } - /* EAGAIN/etc or a successful read. */ - return TRUE; + if( ssl_pending( jd->ssl ) ) + /* OpenSSL empties the TCP buffers completely but may keep some + data in its internap buffers. select() won't see that, but + ssl_pending() does. */ + return jabber_read_callback( data, fd, cond ); + else + return TRUE; } gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond ) -- cgit v1.2.3 From dd14ecc29b87b9aefa97b6838f5a8595557d46d1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 23 Mar 2008 15:02:42 +0000 Subject: s/g_strsplit/g_strsplit_set/, thanks to misc@mandriva.org (Bug #380). --- conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf.c b/conf.c index 57902826..339af618 100644 --- a/conf.c +++ b/conf.c @@ -251,7 +251,7 @@ static int conf_loadini( conf_t *conf, char *file ) else if( g_strcasecmp( ini->key, "account_storage_migrate" ) == 0 ) { g_strfreev( conf->migrate_storage ); - conf->migrate_storage = g_strsplit( ini->value, " \t,;", -1 ); + conf->migrate_storage = g_strsplit_set( ini->value, " \t,;", -1 ); } else if( g_strcasecmp( ini->key, "pinginterval" ) == 0 ) { -- cgit v1.2.3 From fcd5003bd6c10f176f63df459e8ca479c5292dc1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 23 Mar 2008 21:53:53 +0000 Subject: Some Debian package fixes. If nothing else comes up, this will be 1.2-2. (Not sure if I will roll back the non-Debian changes...) --- debian/README.Debian | 16 +++++++++++++++- debian/changelog | 7 +++++++ debian/conffiles | 1 + debian/postinst | 10 ++++++---- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/debian/README.Debian b/debian/README.Debian index 6056f488..b5a514c0 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -6,7 +6,21 @@ want to use this, you can disable the init scripts (best way to do this is by editing /etc/default/bitlbee) and restore the inetd.conf entry. This should be necessary only once, it won't be touched during upgrades. --------------------------------------------------------------------------- +Another important change in BitlBee 1.2 is the file format used for your +personal settings. Everything's now saved in a single .xml (per account, +of course) file instead of $nick.accounts and $nick.nicks. One advantage +of this new format is that the passwords are actually encrypted instead of +just vaguely obfuscated. BitlBee can still read the old files, and will +save things in the new format when you save/disconnect. After that, you +can safely remove the old-style files (this is recommended). + +I tried making this transition (the new file format but especially, in this +case, the inetd->forkdaemon mode change) as smooth as possible, but I'm +aware that many BitlBee users will have their own hacks already to run the +program. I hope the package won't break any of this for anyone. 1.2-2 +should fix at least some of the issues. + +--------------------------------------------------------------------------- Debconf should have asked you on what port you want BitlBee to run. If it did not, the port number should be 6667 or 6668. (6668 if you already got diff --git a/debian/changelog b/debian/changelog index 2cf6510c..0eb05525 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +bitlbee (1.2-2) unstable; urgency=low + + * Fixed some packaging issues reported by IRC and e-mail. (Closes: #472373) + * Not ready yet. + + -- Wilmer van der Gaast Sun, 23 Mar 2008 21:51:57 +0000 + bitlbee (1.2-1) unstable; urgency=low * New upstream release. (Closes: #325017, #386914, #437515) diff --git a/debian/conffiles b/debian/conffiles index 2ccc958d..dcb4078e 100644 --- a/debian/conffiles +++ b/debian/conffiles @@ -1,2 +1,3 @@ /etc/bitlbee/motd.txt /etc/bitlbee/bitlbee.conf +/etc/init.d/bitlbee diff --git a/debian/postinst b/debian/postinst index c4edb8e8..1a906474 100755 --- a/debian/postinst +++ b/debian/postinst @@ -13,17 +13,19 @@ update-rc.d bitlbee defaults > /dev/null 2>&1 BITLBEE_OPTS=-F BITLBEE_DISABLED=0 BITLBEE_UPGRADE_DONT_RESTART=0 -[ -r /etc/default/bitlbee ] && source /etc/default/bitlbee +[ -r /etc/default/bitlbee ] && . /etc/default/bitlbee -if [ "$BITLBEE_DISABLED" = "0" ] && expr "$2" : '0\..*' > /dev/null || expr "$2" : '1\.0\..*' > /dev/null; then - ## In case it's still there (if we're upgrading right now) +if [ "$BITLBEE_DISABLED" = "0" ] && type update-inetd > /dev/null 2> /dev/null && + ( expr "$2" : '0\..*' > /dev/null || expr "$2" : '1\.0\..*' > /dev/null ); then + ## Make sure the inetd entry is gone (can still be there from a + ## previous version. update-inetd --remove '.*/usr/sbin/bitlbee' if grep -q /usr/sbin/bitlbee /etc/inetd.conf 2> /dev/null; then # Thanks for breaking update-inetd! (bugs.debian.org/311111) # I hope that it works at least with xinetd, because this # emergency hack doesn't: perl -pi -e 's:^[^#].*/usr/sbin/bitlbee$:## Now using daemon mode\: # $&:' /etc/inetd.conf - killall -HUP inetd + killall -HUP inetd || true fi fi -- cgit v1.2.3 From 58a1449166ebc9c2913bf47a4bf05c4cf3e258b0 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 24 Mar 2008 11:01:02 +0000 Subject: Fixed a broken check in lib/proxy.c, this restores proxy support. Thanks to Miles Bader for reporting this in the Debian BTS. Apparently not many people use this functionality, it was broken in bzr for more than a year already... --- debian/changelog | 1 + lib/proxy.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0eb05525..6c725964 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ bitlbee (1.2-2) unstable; urgency=low * Fixed some packaging issues reported by IRC and e-mail. (Closes: #472373) + * Fixed proxy support. (Closes: #472395) * Not ready yet. -- Wilmer van der Gaast Sun, 23 Mar 2008 21:51:57 +0000 diff --git a/lib/proxy.c b/lib/proxy.c index 0e1c8f07..53b89d64 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -529,7 +529,7 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat { struct PHB *phb; - if (!host || !port || (port == -1) || !func || strlen(host) > 128) { + if (!host || port <= 0 || !func || strlen(host) > 128) { return -1; } @@ -537,7 +537,7 @@ int proxy_connect(const char *host, int port, b_event_handler func, gpointer dat phb->func = func; phb->data = data; - if ((proxytype == PROXY_NONE) || strlen(proxyhost) > 0 || !proxyport || (proxyport == -1)) + if (proxytype == PROXY_NONE || !proxyhost[0] || proxyport <= 0) return proxy_connect_none(host, port, phb); else if (proxytype == PROXY_HTTP) return proxy_connect_http(host, port, phb); -- cgit v1.2.3 From bfe7caaa8f7ec37506668b375bfa026b3349a6a6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 24 Mar 2008 13:55:25 +0000 Subject: Updated doc/CHANGES. --- doc/CHANGES | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/CHANGES b/doc/CHANGES index 65947617..4e9f72ab 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,3 +1,14 @@ +Version 1.2.1: +- Fixed proxy support. +- Fixed stalling issues while connecting to Jabber when using the OpenSSL + module. +- Fixed problem with GLib and ForkDaemon where processes didn't die when + the client disconnects. +- Fixed handling of "set charset none". (Which pretty much breaks the account + completely in 1.2.) + +Finished ... + Version 1.2: - Added ForkDaemon mode next to the existing Daemon- and inetd modes. With ForkDaemon you can run BitlBee as a stand-alone daemon and every connection -- cgit v1.2.3 From 66c51bbf19a599e3fffd2e3dbb5aae829e15af59 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 24 Mar 2008 19:11:29 +0000 Subject: Updated debian/changelog, I hope this will be a good 1.2-2 package. --- debian/changelog | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 6c725964..ba68e0e4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,9 +2,8 @@ bitlbee (1.2-2) unstable; urgency=low * Fixed some packaging issues reported by IRC and e-mail. (Closes: #472373) * Fixed proxy support. (Closes: #472395) - * Not ready yet. - -- Wilmer van der Gaast Sun, 23 Mar 2008 21:51:57 +0000 + -- Wilmer van der Gaast Mon, 24 Mar 2008 19:10:46 +0000 bitlbee (1.2-1) unstable; urgency=low -- cgit v1.2.3 From 628e6018a8387603e67f4ce1c8b3b67126408726 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 24 Mar 2008 19:48:36 +0000 Subject: Some more changes for 1.2-2: Adding a bitlbee group for extra security and small stuff. --- debian/bitlbee.init | 2 +- debian/changelog | 6 +++++- debian/postinst | 16 ++++++++++++---- debian/postrm | 4 +++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/debian/bitlbee.init b/debian/bitlbee.init index baf1a0c6..51b807f5 100755 --- a/debian/bitlbee.init +++ b/debian/bitlbee.init @@ -36,7 +36,7 @@ d_start() { chown bitlbee /var/run/bitlbee.pid start-stop-daemon --start --quiet --pidfile $PIDFILE \ - -c bitlbee -g nogroup \ + -c bitlbee: \ --exec $DAEMON -- -p $BITLBEE_PORT -P $PIDFILE $DAEMON_OPT } diff --git a/debian/changelog b/debian/changelog index ba68e0e4..b043c13a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,8 +2,12 @@ bitlbee (1.2-2) unstable; urgency=low * Fixed some packaging issues reported by IRC and e-mail. (Closes: #472373) * Fixed proxy support. (Closes: #472395) + * Added a BitlBee group so only root can edit the configs and BitlBee can + just *read* it. + * Manually deleting /var/lib/bitlbee/ when purging, deluser doesn't want to + do it. - -- Wilmer van der Gaast Mon, 24 Mar 2008 19:10:46 +0000 + -- Wilmer van der Gaast Mon, 24 Mar 2008 19:48:24 +0000 bitlbee (1.2-1) unstable; urgency=low diff --git a/debian/postinst b/debian/postinst index 1a906474..80249bfe 100755 --- a/debian/postinst +++ b/debian/postinst @@ -73,13 +73,21 @@ if [ -d $CONFDIR ] && chown -R bitlbee $CONFDIR; then exit 0 fi -adduser --system --home /var/lib/bitlbee/ --disabled-login --disabled-password bitlbee +adduser --system --group --disabled-login --disabled-password --home /var/lib/bitlbee/ bitlbee chmod 700 /var/lib/bitlbee/ ## Can't do this in packaging phase: Don't know the UID yet. Access to -## the file should be limited, now that it stores passwords. -chmod 600 /etc/bitlbee/bitlbee.conf -chown bitlbee /etc/bitlbee/bitlbee.conf +## the file should be limited, now that it stores passwords. Added +## --group later for a little more security, but have to see if I can +## apply this change to existing installations on upgrades. Will think +## about that later. +if getent group bitlbee > /dev/null; then + chmod 640 /etc/bitlbee/bitlbee.conf + chown root:bitlbee /etc/bitlbee/bitlbee.conf +else + chmod 600 /etc/bitlbee/bitlbee.conf + chown bitlbee /etc/bitlbee/bitlbee.conf +fi if [ -z "$2" ]; then /etc/init.d/bitlbee start diff --git a/debian/postrm b/debian/postrm index f7686e7b..5c3b4b2e 100755 --- a/debian/postrm +++ b/debian/postrm @@ -8,5 +8,7 @@ if [ -e /usr/share/debconf/confmodule ]; then fi update-rc.d bitlbee remove > /dev/null 2>&1 || true -deluser --system --remove-home bitlbee || true rm -f /etc/default/bitlbee + +deluser --system --remove-home bitlbee || true +rm -rf /var/lib/bitlbee ## deluser doesn't seem to do this for homedirs in /var -- cgit v1.2.3 From 483f8dd1042e89e02a0eb736f65885e9f74a344d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 24 Mar 2008 21:13:23 +0000 Subject: Removed DEB_BUILD_OPTIONS because it turns out this isn't just some string I can pass through to configure, there's an official policy on what can be in there exactly. (Or at least I found a suggested policy on the debian- policy mailing list.) 1.2-3, because I just uploaded -2 already. :-( --- debian/changelog | 8 ++++++++ debian/rules | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index b043c13a..1d266c0c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +bitlbee (1.2-3) unstable; urgency=low + + * Removed DEB_BUILD_OPTIONS again (forgot to apply that change to the 1.2 + branch when I finished 1.0.4-2, things diverged too much anyway.) + Closes: #472540. + + -- Wilmer van der Gaast Mon, 24 Mar 2008 21:10:14 +0000 + bitlbee (1.2-2) unstable; urgency=low * Fixed some packaging issues reported by IRC and e-mail. (Closes: #472373) diff --git a/debian/rules b/debian/rules index 0c757899..252fb742 100755 --- a/debian/rules +++ b/debian/rules @@ -13,7 +13,7 @@ endif build-arch: build-arch-stamp build-arch-stamp: if [ ! -d debian ]; then exit 1; fi - ./configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent $(DEB_BUILD_OPTIONS) + ./configure --debug=$(DEBUG) --prefix=/usr --etcdir=/etc/bitlbee --events=libevent $(MAKE) # $(MAKE) -C doc/ all touch build-arch-stamp -- cgit v1.2.3 From 0281c4598b396e837342c6fa6465bc709fc068a3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 29 Mar 2008 21:01:09 +0000 Subject: s/DAEMON_OPT/BITLBEE_OPTS/ so the init script will actually pick up flags from /etc/default/bitlbee. --- debian/bitlbee.init | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/bitlbee.init b/debian/bitlbee.init index 51b807f5..62b57b13 100755 --- a/debian/bitlbee.init +++ b/debian/bitlbee.init @@ -17,7 +17,7 @@ SCRIPTNAME=/etc/init.d/$NAME # Default value BITLBEE_PORT=6667 -DAEMON_OPT=-F +BITLBEE_OPTS=-F # Read config file if it is present. if [ -r /etc/default/$NAME ]; then @@ -37,7 +37,7 @@ d_start() { start-stop-daemon --start --quiet --pidfile $PIDFILE \ -c bitlbee: \ - --exec $DAEMON -- -p $BITLBEE_PORT -P $PIDFILE $DAEMON_OPT + --exec $DAEMON -- -p $BITLBEE_PORT -P $PIDFILE $BITLBEE_OPTS } # -- cgit v1.2.3 From e74c7fe11099e45da9a17b4d791162d57d2768f8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 29 Mar 2008 21:11:23 +0000 Subject: Added dependency information to the init script, and updated changelog. --- debian/bitlbee.init | 7 +++++++ debian/changelog | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/debian/bitlbee.init b/debian/bitlbee.init index 62b57b13..904ae5ea 100755 --- a/debian/bitlbee.init +++ b/debian/bitlbee.init @@ -1,4 +1,11 @@ #! /bin/sh +### BEGIN INIT INFO +# Provides: bitlbee +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 1 +### END INIT INFO # # Init script for BitlBee Debian package. Based on skeleton init script: # diff --git a/debian/changelog b/debian/changelog index 1d266c0c..b964ee0e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +bitlbee (1.2-4) unstable; urgency=low + + * Not a real release, just a placeholder for the changelog. + * Fixed init script to use the BITLBEE_OPTS variable, not an undefined + DAEMON_OPT. + * Added dependency information to the init script. (Closes: #472567) + + -- Wilmer van der Gaast Sat, 29 Mar 2008 21:10:33 +0000 + bitlbee (1.2-3) unstable; urgency=low * Removed DEB_BUILD_OPTIONS again (forgot to apply that change to the 1.2 -- cgit v1.2.3 From a199d33ed818820ffba328f718799bbd77392f6a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 29 Mar 2008 22:19:17 +0000 Subject: Closing bug #209: The PASS command can now be used to identify yourself to BitlBee. The advantage: No more messing with NickServ hooks. Just set a server password. --- irc.c | 17 ++++++++++++++++- irc.h | 4 +++- irc_commands.c | 24 +++++++++++++++++++++--- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/irc.c b/irc.c index 3589256e..fa0c03fe 100644 --- a/irc.c +++ b/irc.c @@ -735,12 +735,27 @@ void irc_login( irc_t *irc ) u->online = 1; irc_spawn( irc, u ); - irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQs are answered there." ); + irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n" + "If you've never used BitlBee before, please do read the help " + "information using the \x02help\x02 command. Lots of FAQs are " + "answered there.\n" + "If you already have an account on this server, just use the " + "\x02identify\x02 command to identify yourself." ); if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON ) ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname ); irc->status |= USTATUS_LOGGED_IN; + + /* This is for bug #209 (use PASS to identify to NickServ). */ + if( irc->password != NULL ) + { + char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL }; + + irc_setpass( irc, NULL ); + root_command( irc, send_cmd ); + g_free( send_cmd[1] ); + } } void irc_motd( irc_t *irc ) diff --git a/irc.h b/irc.h index eb70ad1c..eaf531b7 100644 --- a/irc.h +++ b/irc.h @@ -68,7 +68,9 @@ typedef struct irc char *user; char *host; char *realname; - char *password; + char *password; /* HACK: Used to save the user's password, but before + logging in, this may contain a password we should + send to identify after USER/NICK are received. */ char umode[8]; diff --git a/irc_commands.c b/irc_commands.c index b8bae541..61517614 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -29,7 +29,19 @@ static void irc_cmd_pass( irc_t *irc, char **cmd ) { - if( global.conf->auth_pass && + if( irc->status & USTATUS_LOGGED_IN ) + { + char *send_cmd[] = { "identify", cmd[1], NULL }; + + /* We're already logged in, this client seems to send the PASS + command last. (Possibly it won't send it at all if it turns + out we don't require it, which will break this feature.) + Try to identify using the given password. */ + return root_command( irc, send_cmd ); + } + /* Handling in pre-logged-in state, first see if this server is + password-protected: */ + else if( global.conf->auth_pass && ( strncmp( global.conf->auth_pass, "md5:", 4 ) == 0 ? md5_verify_password( cmd[1], global.conf->auth_pass + 4 ) == 0 : strcmp( cmd[1], global.conf->auth_pass ) == 0 ) ) @@ -37,10 +49,16 @@ static void irc_cmd_pass( irc_t *irc, char **cmd ) irc->status |= USTATUS_AUTHORIZED; irc_check_login( irc ); } - else + else if( global.conf->auth_pass ) { irc_reply( irc, 464, ":Incorrect password" ); } + else + { + /* Remember the password and try to identify after USER/NICK. */ + irc_setpass( irc, cmd[1] ); + irc_check_login( irc ); + } } static void irc_cmd_user( irc_t *irc, char **cmd ) @@ -580,7 +598,7 @@ static void irc_cmd_rehash( irc_t *irc, char **cmd ) } static const command_t irc_commands[] = { - { "pass", 1, irc_cmd_pass, IRC_CMD_PRE_LOGIN }, + { "pass", 1, irc_cmd_pass, 0 }, { "user", 4, irc_cmd_user, IRC_CMD_PRE_LOGIN }, { "nick", 1, irc_cmd_nick, 0 }, { "quit", 0, irc_cmd_quit, 0 }, -- cgit v1.2.3 From 18ff38fad0d6d47853fb43ec5a99b29ba031a8ca Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 29 Mar 2008 23:15:04 +0000 Subject: Be more liberal with accepted line endings. ERC on Windows likes to use "\r\r\n", for example, and until now BitlBee only chopped off the \r\n, leaving the first \r as part of the command, which means it couldn't log in to BitlBee at all. (Bad character in nickname.) --- irc.c | 54 ++++++++++++++++++++++++++---------------------------- tests/check_irc.c | 4 ++-- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/irc.c b/irc.c index fa0c03fe..99f0de9a 100644 --- a/irc.c +++ b/irc.c @@ -296,9 +296,8 @@ void irc_process( irc_t *irc ) { char conv[IRC_MAX_LINE+1]; - /* [WvG] Because irc_tokenize splits at every newline, the lines[] list - should end with an empty string. This is why this actually works. - Took me a while to figure out, Maurits. :-P */ + /* [WvG] If the last line isn't empty, it's an incomplete line and we + should wait for the rest to come in before processing it. */ if( lines[i+1] == NULL ) { temp = g_strdup( lines[i] ); @@ -368,42 +367,41 @@ void irc_process( irc_t *irc ) contains an incomplete line at the end, ends with an empty string. */ char **irc_tokenize( char *buffer ) { - int i, j; + int i, j, n = 3; char **lines; - /* Count the number of elements we're gonna need. */ - for( i = 0, j = 1; buffer[i] != '\0'; i ++ ) - { - if( buffer[i] == '\n' ) - if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) - j ++; - } - - /* Allocate j+1 elements. */ - lines = g_new( char *, j + 1 ); - - /* NULL terminate our list. */ - lines[j] = NULL; + /* Allocate n+1 elements. */ + lines = g_new( char *, n + 1 ); lines[0] = buffer; - /* Split the buffer in several strings, using \r\n as our seperator, where \r is optional. - * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too. - */ - for( i = 0, j = 0; buffer[i] != '\0'; i ++) + /* Split the buffer in several strings, and accept any kind of line endings, + * knowing that ERC on Windows may send something interesting like \r\r\n, + * and surely there must be clients that think just \n is enough... */ + for( i = 0, j = 0; buffer[i] != '\0'; i ++ ) { - if( buffer[i] == '\n' ) + if( buffer[i] == '\r' || buffer[i] == '\n' ) { - buffer[i] = '\0'; + while( buffer[i] == '\r' || buffer[i] == '\n' ) + buffer[i++] = '\0'; - if( i > 0 && buffer[i-1] == '\r' ) - buffer[i-1] = '\0'; - if( buffer[i+1] != '\r' && buffer[i+1] != '\n' ) - lines[++j] = buffer + i + 1; + lines[++j] = buffer + i; + + if( j >= n ) + { + n *= 2; + lines = g_renew( char *, lines, n + 1 ); + } + + if( buffer[i] == '\0' ) + break; } } - return( lines ); + /* NULL terminate our list. */ + lines[++j] = NULL; + + return lines; } /* Split an IRC-style line into little parts/arguments. */ diff --git a/tests/check_irc.c b/tests/check_irc.c index c1cf05a5..66fe0021 100644 --- a/tests/check_irc.c +++ b/tests/check_irc.c @@ -36,8 +36,8 @@ START_TEST(test_login) irc = irc_new(g_io_channel_unix_get_fd(ch1)); - fail_unless(g_io_channel_write_chars(ch2, "NICK bla\r\n" - "USER a a a a\r\n", -1, NULL, NULL) == G_IO_STATUS_NORMAL); + fail_unless(g_io_channel_write_chars(ch2, "NICK bla\r\r\n" + "USER a a a a\n", -1, NULL, NULL) == G_IO_STATUS_NORMAL); fail_unless(g_io_channel_flush(ch2, NULL) == G_IO_STATUS_NORMAL); g_main_iteration(FALSE); -- cgit v1.2.3 From 5ecf96b935c6f6c0fba00d84cf7616ee04b06aed Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 30 Mar 2008 17:15:15 +0100 Subject: Updated doc/CHANGES again. --- doc/CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/CHANGES b/doc/CHANGES index 4e9f72ab..93ad35e2 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -6,6 +6,9 @@ Version 1.2.1: the client disconnects. - Fixed handling of "set charset none". (Which pretty much breaks the account completely in 1.2.) +- You can now automatically identify yourself to BitlBee by setting a server + password in your IRC client. +- Compatible with all crazy kinds of line endings that clients can send. Finished ... -- cgit v1.2.3 From f9756bd2e2711d58e06ad2a33ad3292ff10fc6da Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 30 Mar 2008 22:26:16 +0100 Subject: Changed charset handling: irc_t keeps two iconv structures, which are just used for every line sent and received, so now there's no need to use g_iconv_open() every time a message comes in/out. Also, fixed a small memory leak that was there for a long time but somehow never caught my attention. --- irc.c | 102 ++++++++++++++++++++++++++++++++++++++++++++------------- irc.h | 1 + irc_commands.c | 3 +- set.c | 15 --------- set.h | 1 - 5 files changed, 81 insertions(+), 41 deletions(-) diff --git a/irc.c b/irc.c index 99f0de9a..2faa2bc1 100644 --- a/irc.c +++ b/irc.c @@ -41,6 +41,35 @@ static char *passchange( set_t *set, char *value ) return NULL; } +static char *set_eval_charset( set_t *set, char *value ) +{ + irc_t *irc = set->data; + GIConv ic, oc; + + if( g_strcasecmp( value, "none" ) == 0 ) + value = g_strdup( "utf-8" ); + + if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 ) + { + return NULL; + } + if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 ) + { + g_iconv_close( ic ); + return NULL; + } + + if( irc->iconv != (GIConv) -1 ) + g_iconv_close( irc->iconv ); + if( irc->oconv != (GIConv) -1 ) + g_iconv_close( irc->oconv ); + + irc->iconv = ic; + irc->oconv = oc; + + return value; +} + irc_t *irc_new( int fd ) { irc_t *irc; @@ -64,6 +93,9 @@ irc_t *irc_new( int fd ) irc->mynick = g_strdup( ROOT_NICK ); irc->channel = g_strdup( ROOT_CHAN ); + irc->iconv = (GIConv) -1; + irc->oconv = (GIConv) -1; + if( global.conf->hostname ) { irc->myhost = g_strdup( global.conf->hostname ); @@ -126,6 +158,9 @@ irc_t *irc_new( int fd ) conf_loaddefaults( irc ); + /* Evaluator sets the iconv/oconv structures. */ + set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) ); + return( irc ); } @@ -264,6 +299,13 @@ void irc_free(irc_t * irc) g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL); g_hash_table_destroy(irc->watches); + if( irc->iconv != (GIConv) -1 ) + g_iconv_close( irc->iconv ); + if( irc->oconv != (GIConv) -1 ) + g_iconv_close( irc->oconv ); + + g_free( irc->last_target ); + g_free(irc); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) @@ -285,7 +327,7 @@ void irc_setpass (irc_t *irc, const char *pass) void irc_process( irc_t *irc ) { - char **lines, *temp, **cmd, *cs; + char **lines, *temp, **cmd; int i; if( irc->readbuffer != NULL ) @@ -294,7 +336,7 @@ void irc_process( irc_t *irc ) for( i = 0; *lines[i] != '\0'; i ++ ) { - char conv[IRC_MAX_LINE+1]; + char *conv = NULL; /* [WvG] If the last line isn't empty, it's an incomplete line and we should wait for the rest to come in before processing it. */ @@ -307,10 +349,14 @@ void irc_process( irc_t *irc ) break; } - if( ( cs = set_getstr( &irc->set, "charset" ) ) && g_strcasecmp( cs, "none" ) != 0 ) + if( irc->iconv != (GIConv) -1 ) { - conv[IRC_MAX_LINE] = 0; - if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 ) + gsize bytes_read, bytes_written; + + conv = g_convert_with_iconv( lines[i], -1, irc->iconv, + &bytes_read, &bytes_written, NULL ); + + if( conv == NULL || bytes_read != strlen( lines[i] ) ) { /* GLib can do strange things if things are not in the expected charset, so let's be a little bit paranoid here: */ @@ -322,15 +368,18 @@ void irc_process( irc_t *irc ) "that charset, or tell BitlBee which charset to " "expect by changing the charset setting. See " "`help set charset' for more information. Your " - "message was ignored.", cs ); - *conv = 0; + "message was ignored.", + set_getstr( &irc->set, "charset" ) ); + + g_free( conv ); + conv = NULL; } else { irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost, "Warning: invalid characters received at login time." ); - strncpy( conv, lines[i], IRC_MAX_LINE ); + conv = g_strdup( lines[i] ); for( temp = conv; *temp; temp ++ ) if( *temp & 0x80 ) *temp = '?'; @@ -339,11 +388,15 @@ void irc_process( irc_t *irc ) lines[i] = conv; } - if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) - continue; - irc_exec( irc, cmd ); + if( lines[i] ) + { + if( ( cmd = irc_parse_line( lines[i] ) ) == NULL ) + continue; + irc_exec( irc, cmd ); + g_free( cmd ); + } - g_free( cmd ); + g_free( conv ); /* Shouldn't really happen, but just in case... */ if( !g_slist_find( irc_connection_list, irc ) ) @@ -535,32 +588,35 @@ void irc_write( irc_t *irc, char *format, ... ) va_end( params ); return; - } void irc_vawrite( irc_t *irc, char *format, va_list params ) { int size; - char line[IRC_MAX_LINE+1], *cs; + char line[IRC_MAX_LINE+1]; /* Don't try to write anything new anymore when shutting down. */ if( irc->status & USTATUS_SHUTDOWN ) return; - line[IRC_MAX_LINE] = 0; + memset( line, 0, sizeof( line ) ); g_vsnprintf( line, IRC_MAX_LINE - 2, format, params ); - strip_newlines( line ); - if( ( cs = set_getstr( &irc->set, "charset" ) ) && - g_strcasecmp( cs, "none" ) != 0 && g_strcasecmp( cs, "utf-8" ) != 0 ) + + if( irc->oconv != (GIConv) -1 ) { - char conv[IRC_MAX_LINE+1]; + gsize bytes_read, bytes_written; + char *conv; + + conv = g_convert_with_iconv( line, -1, irc->oconv, + &bytes_read, &bytes_written, NULL ); + + if( bytes_read == strlen( line ) ) + strncpy( line, conv, IRC_MAX_LINE - 2 ); - conv[IRC_MAX_LINE] = 0; - if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 ) - strcpy( line, conv ); + g_free( conv ); } - strcat( line, "\r\n" ); + g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 ); if( irc->sendbuffer != NULL ) { diff --git a/irc.h b/irc.h index eaf531b7..b8c52925 100644 --- a/irc.h +++ b/irc.h @@ -60,6 +60,7 @@ typedef struct irc int pinging; char *sendbuffer; char *readbuffer; + GIConv iconv, oconv; int sentbytes; time_t oldtime; diff --git a/irc_commands.c b/irc_commands.c index 61517614..6a47007a 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -277,8 +277,7 @@ static void irc_cmd_privmsg( irc_t *irc, char **cmd ) if( cmd[1] != irc->last_target ) { - if( irc->last_target ) - g_free( irc->last_target ); + g_free( irc->last_target ); irc->last_target = g_strdup( cmd[1] ); } } diff --git a/set.c b/set.c index 90b29f91..112e6937 100644 --- a/set.c +++ b/set.c @@ -229,18 +229,3 @@ char *set_eval_ops( set_t *set, char *value ) return value; } - -char *set_eval_charset( set_t *set, char *value ) -{ - GIConv cd; - - if( g_strcasecmp( value, "none" ) == 0 ) - return value; - - cd = g_iconv_open( "UTF-8", value ); - if( cd == (GIConv) -1 ) - return NULL; - - g_iconv_close( cd ); - return value; -} diff --git a/set.h b/set.h index 7dcbb869..8c722877 100644 --- a/set.h +++ b/set.h @@ -96,6 +96,5 @@ char *set_eval_bool( set_t *set, char *value ); /* Some not very generic evaluators that really shouldn't be here... */ char *set_eval_to_char( set_t *set, char *value ); char *set_eval_ops( set_t *set, char *value ); -char *set_eval_charset( set_t *set, char *value ); #endif /* __SET_H__ */ -- cgit v1.2.3 From ddba0aea68f90b06bb6278cada982eb88889c31c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 30 Mar 2008 22:28:39 +0100 Subject: Removing speech, in case I forget before 1.2.1. --- doc/RELEASE-SPEECH-1.2 | 57 -------------------------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 doc/RELEASE-SPEECH-1.2 diff --git a/doc/RELEASE-SPEECH-1.2 b/doc/RELEASE-SPEECH-1.2 deleted file mode 100644 index ec7c48b4..00000000 --- a/doc/RELEASE-SPEECH-1.2 +++ /dev/null @@ -1,57 +0,0 @@ -BitlBee ... is Bitl -------------------- - -"I CAN HAS SPEEECH?" This is how Wilmer announced to me that he was going to do -another BitlBee release. I was as surprised as you are. I thought he had given -up on this whole releasing business. - -There is some humor in using a LOLcats reference to announce a new Bee -release. The last major BitlBee release (1.0) was done a long time before the -hype even begun. Between then and now we've celebrated BitlBee's fifth birthday -and had a handful of releases, but nothing big happened. As a user this lax -release planning worries me. What if this means that later releases will take -even longer? I don't think we should fear this. Let us explore why this release -took so long. - -Personally, I blame Google. - -There, I've said it. Google. The guys who are so big on "Do No Evil" and all -that jazz. They caused this release to be so late. Let me explain why. - -They made Wilmer an offer. Wilmer, being the sillily naive guy he is, couldn't -refuse. There were no decapitated horses involved, but he couldn't refuse -nonetheless. That's not a big problem of course. Lots of guys (and gals, sure) -work for Google. It wouldn't have become a problem if they hadn't shipped him of -to Ireland. That's where the trouble starts. - -Ireland. Home of the leprechauns. These rascals joined forces with aliens and -LOLcats to abduct Wilmer. The aliens had been trying for years to kidnap him, -but they were on his turf and his trusty sidekicks Jelmer and Maurits were there -to help him. All that changed when he moved to Ireland. - -But it wasn't just that Wilmer was all alone in some strange place. It was also -that the aliens had created the LOLcats and made an alliance with the -leprechauns--the real rulers of Ireland. Wilmer is cool, but he's not that -cool. So they abducted him for a few years. When he finally came back, he -regathered his mad coding skills and hacked a new release together. - -By now you're thinking, what has happened to Jelmer and Maurits? Well, they're -still here and they worked on the Bee while Wilmer was absent. But, like open -source, they are very Bitl--they're cool, but they're ready when they're -ready. - -Well, whatever you may think of my little theory, they did take forever to -launch this release. We're not mad at them, because it shows. They have -added some cool new features and made plenty of changes under the hood. Let me -give you a sneak preview of some of the new features: Jabber groupchats are -supported. Configuration files are stored encrypted. You can now use -ForkDaemon mode, which gives better stability over normal daemon mode, but -doesn't require inetd. Also, server owners can now use the /OPER command to -spy on their users. And--as I was specifically asked to mention--this is the -first stable release that supports plugins. That's some Bitl changes for ya. - -BitlBee is cool, but ready when it's ready. Very Bitl. - -Sjoerd. LOL. - -(LOLBee by Erik Bosman.) -- cgit v1.2.3 From fa75134008bd9206ca02380927c27581feb65c3e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 2 Apr 2008 00:07:21 +0100 Subject: Reordered irc_free() a little bit, hoping that this will fix a crash-on-quit bug I can't figure out. The previous order wasn't optimal. --- account.c | 12 +++---- irc.c | 111 +++++++++++++++++++++++++++++++------------------------------- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/account.c b/account.c index 4eb78faa..2c6e1069 100644 --- a/account.c +++ b/account.c @@ -181,19 +181,17 @@ void account_del( irc_t *irc, account_t *acc ) { account_t *a, *l = NULL; + if( acc->ic ) + /* Caller should have checked, accounts still in use can't be deleted. */ + return; + for( a = irc->accounts; a; a = (l=a)->next ) if( a == acc ) { - if( a->ic ) return; /* Caller should have checked, accounts still in use can't be deleted. */ - if( l ) - { l->next = a->next; - } else - { irc->accounts = a->next; - } while( a->set ) set_del( &a->set, a->set->key ); @@ -202,7 +200,7 @@ void account_del( irc_t *irc, account_t *acc ) g_free( a->user ); g_free( a->pass ); - if( a->server ) g_free( a->server ); + g_free( a->server ); if( a->reconnect ) /* This prevents any reconnect still queued to happen */ cancel_auto_reconnect( a ); g_free( a ); diff --git a/irc.c b/irc.c index 2faa2bc1..585cf232 100644 --- a/irc.c +++ b/irc.c @@ -219,9 +219,8 @@ static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data ) } /* Because we have no garbage collection, this is quite annoying */ -void irc_free(irc_t * irc) +void irc_free( irc_t * irc ) { - account_t *account; user_t *user, *usertmp; log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); @@ -230,83 +229,85 @@ void irc_free(irc_t * irc) if( storage_save( irc, TRUE ) != STORAGE_OK ) irc_usermsg( irc, "Error while saving settings!" ); - closesocket( irc->fd ); - - if( irc->ping_source_id > 0 ) - b_event_remove( irc->ping_source_id ); - b_event_remove( irc->r_watch_source_id ); - if( irc->w_watch_source_id > 0 ) - b_event_remove( irc->w_watch_source_id ); - irc_connection_list = g_slist_remove( irc_connection_list, irc ); - for (account = irc->accounts; account; account = account->next) { - if (account->ic) { - imc_logout(account->ic, TRUE); - } else if (account->reconnect) { - cancel_auto_reconnect(account); - } - } - - g_free(irc->sendbuffer); - g_free(irc->readbuffer); - - g_free(irc->nick); - g_free(irc->user); - g_free(irc->host); - g_free(irc->realname); - g_free(irc->password); - - g_free(irc->myhost); - g_free(irc->mynick); - - g_free(irc->channel); - - while (irc->queries != NULL) - query_del(irc, irc->queries); - - while (irc->accounts) - if (irc->accounts->ic == NULL) - account_del(irc, irc->accounts); + while( irc->accounts ) + { + if( irc->accounts->ic ) + imc_logout( irc->accounts->ic, FALSE ); + else if( irc->accounts->reconnect ) + cancel_auto_reconnect( irc->accounts ); + + if( irc->accounts->ic == NULL ) + account_del( irc, irc->accounts ); else /* Nasty hack, but account_del() doesn't work in this case and we don't want infinite loops, do we? ;-) */ irc->accounts = irc->accounts->next; + } + + while( irc->queries != NULL ) + query_del( irc, irc->queries ); - while (irc->set) - set_del(&irc->set, irc->set->key); + while( irc->set ) + set_del( &irc->set, irc->set->key ); - if (irc->users != NULL) { + if (irc->users != NULL) + { user = irc->users; - while (user != NULL) { - g_free(user->nick); - g_free(user->away); - g_free(user->handle); - if(user->user!=user->nick) g_free(user->user); - if(user->host!=user->nick) g_free(user->host); - if(user->realname!=user->nick) g_free(user->realname); - b_event_remove(user->sendbuf_timer); + while( user != NULL ) + { + g_free( user->nick ); + g_free( user->away ); + g_free( user->handle ); + if( user->user != user->nick ) g_free( user->user ); + if( user->host != user->nick ) g_free( user->host ); + if( user->realname != user->nick ) g_free( user->realname ); + b_event_remove( user->sendbuf_timer ); usertmp = user; user = user->next; - g_free(usertmp); + g_free( usertmp ); } } - g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL); - g_hash_table_destroy(irc->userhash); + if( irc->ping_source_id > 0 ) + b_event_remove( irc->ping_source_id ); + b_event_remove( irc->r_watch_source_id ); + if( irc->w_watch_source_id > 0 ) + b_event_remove( irc->w_watch_source_id ); + + closesocket( irc->fd ); + irc->fd = -1; + + g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL ); + g_hash_table_destroy( irc->userhash ); - g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL); - g_hash_table_destroy(irc->watches); + g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL ); + g_hash_table_destroy( irc->watches ); if( irc->iconv != (GIConv) -1 ) g_iconv_close( irc->iconv ); if( irc->oconv != (GIConv) -1 ) g_iconv_close( irc->oconv ); + g_free( irc->sendbuffer ); + g_free( irc->readbuffer ); + + g_free( irc->nick ); + g_free( irc->user ); + g_free( irc->host ); + g_free( irc->realname ); + g_free( irc->password ); + + g_free( irc->myhost ); + g_free( irc->mynick ); + + g_free( irc->channel ); + g_free( irc->last_target ); - g_free(irc); + g_free( irc ); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) b_main_quit(); -- cgit v1.2.3 From 883a398f059f98cb31da77dd6e632e4152dcf87e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 2 Apr 2008 22:36:02 +0100 Subject: Rearranged some event handling code. --- bitlbee.c | 12 ++++++++---- irc.c | 13 ++++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index 59a417f0..230b8ce8 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -225,12 +225,16 @@ gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condit if( st == size ) { - g_free( irc->sendbuffer ); - irc->sendbuffer = NULL; - irc->w_watch_source_id = 0; - if( irc->status & USTATUS_SHUTDOWN ) + { irc_free( irc ); + } + else + { + g_free( irc->sendbuffer ); + irc->sendbuffer = NULL; + irc->w_watch_source_id = 0; + } return FALSE; } diff --git a/irc.c b/irc.c index 585cf232..c929d68b 100644 --- a/irc.c +++ b/irc.c @@ -198,12 +198,14 @@ void irc_abort( irc_t *irc, int immed, char *format, ... ) irc->status |= USTATUS_SHUTDOWN; if( irc->sendbuffer && !immed ) { - /* We won't read from this socket anymore. Instead, we'll connect a timer - to it that should shut down the connection in a second, just in case - bitlbee_.._write doesn't do it first. */ + /* Set up a timeout event that should shut down the connection + in a second, just in case ..._write doesn't do it first. */ b_event_remove( irc->r_watch_source_id ); - irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc ); + irc->r_watch_source_id = 0; + + b_event_remove( irc->ping_source_id ); + irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc ); } else { @@ -273,7 +275,8 @@ void irc_free( irc_t * irc ) if( irc->ping_source_id > 0 ) b_event_remove( irc->ping_source_id ); - b_event_remove( irc->r_watch_source_id ); + if( irc->r_watch_source_id > 0 ) + b_event_remove( irc->r_watch_source_id ); if( irc->w_watch_source_id > 0 ) b_event_remove( irc->w_watch_source_id ); -- cgit v1.2.3 From 8dbe021fab08902eb202da8da26d183cb0832fca Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Apr 2008 00:13:07 +0100 Subject: Don't pass an account_t pointer directly to query_add() since query_del() wants to free it! Passing an indirect pointer instead. --- root_commands.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/root_commands.c b/root_commands.c index 9a60b5af..2bccc465 100644 --- a/root_commands.c +++ b/root_commands.c @@ -205,22 +205,24 @@ static void cmd_drop( irc_t *irc, char **cmd ) void cmd_account_del_yes( gpointer w, void *data ) { - account_t *a = data; - irc_t *irc = a->irc; + account_t **aptr = data; + irc_t *irc = (*aptr)->irc; - if( a->ic ) + if( (*aptr)->ic ) { irc_usermsg( irc, "Account is still logged in, can't delete" ); } else { - account_del( irc, a ); + account_del( irc, (*aptr) ); irc_usermsg( irc, "Account deleted" ); } + g_free( aptr ); } void cmd_account_del_no( gpointer w, void *data ) { + g_free( data ); } static void cmd_account( irc_t *irc, char **cmd ) @@ -277,14 +279,18 @@ static void cmd_account( irc_t *irc, char **cmd ) } else { + account_t **aptr; char *msg; + aptr = g_malloc( sizeof( aptr ) ); + *aptr = a; + msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will " "also forget all your saved nicknames. If you want " "to change your username/password, use the `account " "set' command. Are you sure you want to delete this " "account?", a->prpl->name, a->user ); - query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, a ); + query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, aptr ); g_free( msg ); } } -- cgit v1.2.3 From f3351f0ae5c6014e36e529684b81e78cad9a66ce Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Apr 2008 12:54:31 +0100 Subject: Fixed GLib <2.6 compatibility issue in arc.h. (G_GNUC_MALLOC) --- lib/arc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/arc.h b/lib/arc.h index 58f30d3d..816fa612 100644 --- a/lib/arc.h +++ b/lib/arc.h @@ -30,6 +30,10 @@ struct arc_state unsigned char i, j; }; +#ifndef G_GNUC_MALLOC +#define G_GNUC_MALLOC +#endif + G_GNUC_MALLOC struct arc_state *arc_keymaker( unsigned char *key, int kl, int cycles ); unsigned char arc_getbyte( struct arc_state *st ); int arc_encode( char *clear, int clear_len, unsigned char **crypt, char *password, int pad_to ); -- cgit v1.2.3 From 9143aeb969697e05953b0f60a2fff2581fa0f18c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Apr 2008 13:26:04 +0100 Subject: query.h now defines a callback function type, not using void* for it anymore. Got rid of the bogus window handler pointer as the first argument to the callback. --- protocols/jabber/jabber_util.c | 8 ++++++-- protocols/msn/msn_util.c | 8 ++++++-- protocols/nogaim.c | 17 ++++++++++------- protocols/nogaim.h | 3 ++- protocols/oscar/oscar.c | 18 ++++++++++++------ protocols/yahoo/yahoo.c | 8 ++++++-- query.c | 7 ++++--- query.h | 8 +++++--- 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/protocols/jabber/jabber_util.c b/protocols/jabber/jabber_util.c index 6e872040..518624f6 100644 --- a/protocols/jabber/jabber_util.c +++ b/protocols/jabber/jabber_util.c @@ -245,8 +245,10 @@ struct jabber_buddy_ask_data char *realname; }; -static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla ) +static void jabber_buddy_ask_yes( void *data ) { + struct jabber_buddy_ask_data *bla = data; + presence_send_request( bla->ic, bla->handle, "subscribed" ); if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) @@ -256,8 +258,10 @@ static void jabber_buddy_ask_yes( gpointer w, struct jabber_buddy_ask_data *bla g_free( bla ); } -static void jabber_buddy_ask_no( gpointer w, struct jabber_buddy_ask_data *bla ) +static void jabber_buddy_ask_no( void *data ) { + struct jabber_buddy_ask_data *bla = data; + presence_send_request( bla->ic, bla->handle, "subscribed" ); g_free( bla->handle ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index fae2877d..58ad22f8 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -89,8 +89,10 @@ struct msn_buddy_ask_data char *realname; }; -static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) +static void msn_buddy_ask_yes( void *data ) { + struct msn_buddy_ask_data *bla = data; + msn_buddy_list_add( bla->ic, "AL", bla->handle, bla->realname ); if( imcb_find_buddy( bla->ic, bla->handle ) == NULL ) @@ -101,8 +103,10 @@ static void msn_buddy_ask_yes( gpointer w, struct msn_buddy_ask_data *bla ) g_free( bla ); } -static void msn_buddy_ask_no( gpointer w, struct msn_buddy_ask_data *bla ) +static void msn_buddy_ask_no( void *data ) { + struct msn_buddy_ask_data *bla = data; + msn_buddy_list_add( bla->ic, "BL", bla->handle, bla->realname ); g_free( bla->handle ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 3ce15166..7466e93a 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -342,7 +342,8 @@ void imc_logout( struct im_connection *ic, int allow_reconnect ) /* dialogs.c */ -void imcb_ask( struct im_connection *ic, char *msg, void *data, void *doit, void *dont ) +void imcb_ask( struct im_connection *ic, char *msg, void *data, + query_callback doit, query_callback dont ) { query_add( ic->irc, ic, msg, doit, dont, data ); } @@ -494,18 +495,20 @@ struct show_got_added_data char *handle; }; -void show_got_added_no( gpointer w, struct show_got_added_data *data ) +void show_got_added_no( void *data ) { - g_free( data->handle ); + g_free( ((struct show_got_added_data*)data)->handle ); g_free( data ); } -void show_got_added_yes( gpointer w, struct show_got_added_data *data ) +void show_got_added_yes( void *data ) { - data->ic->acc->prpl->add_buddy( data->ic, data->handle, NULL ); - /* imcb_add_buddy( data->ic, NULL, data->handle, data->handle ); */ + struct show_got_added_data *sga = data; - return show_got_added_no( w, data ); + sga->ic->acc->prpl->add_buddy( sga->ic, sga->handle, NULL ); + /* imcb_add_buddy( sga->ic, NULL, sga->handle, sga->handle ); */ + + return show_got_added_no( data ); } void imcb_ask_add( struct im_connection *ic, char *handle, const char *realname ) diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 7d391edd..bdd8bae2 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -41,6 +41,7 @@ #include "bitlbee.h" #include "account.h" #include "proxy.h" +#include "query.h" #include "md5.h" #define BUF_LEN MSG_LEN @@ -260,7 +261,7 @@ G_MODULE_EXPORT void imcb_error( struct im_connection *ic, char *format, ... ) G * - '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, void *doit, void *dont ); +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 ); /* Buddy management */ diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 9e5de70a..7738c31f 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1083,8 +1083,8 @@ static int incomingim_chan1(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ return 1; } -void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv); -void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv); +void oscar_accept_chat(void *data); +void oscar_reject_chat(void *data); static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_t *userinfo, struct aim_incomingim_ch2_args *args) { struct im_connection *ic = sess->aux_data; @@ -1118,7 +1118,8 @@ static int incomingim_chan2(aim_session_t *sess, aim_conn_t *conn, aim_userinfo_ return 1; } -static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { +static void gaim_icq_authgrant(void *data_) { + struct icq_auth *data = data_; char *uin, message; struct oscar_data *od = (struct oscar_data *)data->ic->proto_data; @@ -1133,7 +1134,8 @@ static void gaim_icq_authgrant(gpointer w, struct icq_auth *data) { g_free(data); } -static void gaim_icq_authdeny(gpointer w, struct icq_auth *data) { +static void gaim_icq_authdeny(void *data_) { + struct icq_auth *data = data_; char *uin, *message; struct oscar_data *od = (struct oscar_data *)data->ic->proto_data; @@ -2587,15 +2589,19 @@ struct groupchat *oscar_chat_with(struct im_connection * ic, char *who) return NULL; } -void oscar_accept_chat(gpointer w, struct aim_chat_invitation * inv) +void oscar_accept_chat(void *data) { + struct aim_chat_invitation * inv = data; + oscar_chat_join(inv->ic, inv->name, NULL, NULL); g_free(inv->name); g_free(inv); } -void oscar_reject_chat(gpointer w, struct aim_chat_invitation * inv) +void oscar_reject_chat(void *data) { + struct aim_chat_invitation * inv = data; + g_free(inv->name); g_free(inv); } diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 36579d66..ab30df4d 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -796,16 +796,20 @@ int ext_yahoo_connect(const char *host, int port) return -1; } -static void byahoo_accept_conf( gpointer w, struct byahoo_conf_invitation *inv ) +static void byahoo_accept_conf( void *data ) { + struct byahoo_conf_invitation *inv = data; + 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 ); } -static void byahoo_reject_conf( gpointer w, struct byahoo_conf_invitation *inv ) +static void byahoo_reject_conf( void *data ) { + struct byahoo_conf_invitation *inv = data; + yahoo_conference_decline( inv->yid, NULL, inv->members, inv->name, "User rejected groupchat" ); imcb_chat_free( inv->c ); g_free( inv->name ); diff --git a/query.c b/query.c index 6f9eb77f..e8f69572 100644 --- a/query.c +++ b/query.c @@ -29,7 +29,8 @@ static void query_display( irc_t *irc, query_t *q ); static query_t *query_default( irc_t *irc ); -query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data ) +query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, + query_callback yes, query_callback no, void *data ) { query_t *q = g_new0( query_t, 1 ); @@ -143,7 +144,7 @@ void query_answer( irc_t *irc, query_t *q, int ans ) imcb_log( q->ic, "Accepted: %s", q->question ); else irc_usermsg( irc, "Accepted: %s", q->question ); - q->yes( NULL, q->data ); + q->yes( q->data ); } else { @@ -151,7 +152,7 @@ void query_answer( irc_t *irc, query_t *q, int ans ) imcb_log( q->ic, "Rejected: %s", q->question ); else irc_usermsg( irc, "Rejected: %s", q->question ); - q->no( NULL, q->data ); + q->no( q->data ); } q->data = NULL; diff --git a/query.h b/query.h index b64642c2..e0ca32ec 100644 --- a/query.h +++ b/query.h @@ -26,17 +26,19 @@ #ifndef _QUERY_H #define _QUERY_H +typedef void (*query_callback) ( void *data ); + typedef struct query { struct im_connection *ic; char *question; - void (* yes) ( gpointer w, void *data ); - void (* no) ( gpointer w, void *data ); + query_callback yes, no; void *data; struct query *next; } query_t; -query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, void *yes, void *no, void *data ); +query_t *query_add( irc_t *irc, struct im_connection *ic, char *question, + query_callback yes, query_callback no, void *data ); void query_del( irc_t *irc, query_t *q ); void query_del_by_conn( irc_t *irc, struct im_connection *ic ); void query_answer( irc_t *irc, query_t *q, int ans ); -- cgit v1.2.3 From f35aee7fdfc66138d0525a0a7b9e02ccb1aaaec7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Apr 2008 13:36:13 +0100 Subject: Fixed #386. --- root_commands.c | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/root_commands.c b/root_commands.c index 2bccc465..aec91455 100644 --- a/root_commands.c +++ b/root_commands.c @@ -203,24 +203,36 @@ static void cmd_drop( irc_t *irc, char **cmd ) } } -void cmd_account_del_yes( gpointer w, void *data ) +struct cmd_account_del_data { - account_t **aptr = data; - irc_t *irc = (*aptr)->irc; + account_t *a; + irc_t *irc; +}; + +void cmd_account_del_yes( void *data ) +{ + struct cmd_account_del_data *cad = data; + account_t *a; - if( (*aptr)->ic ) + for( a = cad->irc->accounts; a && a != cad->a; a = a->next ); + + if( a == NULL ) + { + irc_usermsg( cad->irc, "Account already deleted" ); + } + else if( a->ic ) { - irc_usermsg( irc, "Account is still logged in, can't delete" ); + irc_usermsg( cad->irc, "Account is still logged in, can't delete" ); } else { - account_del( irc, (*aptr) ); - irc_usermsg( irc, "Account deleted" ); + account_del( cad->irc, a ); + irc_usermsg( cad->irc, "Account deleted" ); } - g_free( aptr ); + g_free( data ); } -void cmd_account_del_no( gpointer w, void *data ) +void cmd_account_del_no( void *data ) { g_free( data ); } @@ -279,18 +291,19 @@ static void cmd_account( irc_t *irc, char **cmd ) } else { - account_t **aptr; + struct cmd_account_del_data *cad; char *msg; - aptr = g_malloc( sizeof( aptr ) ); - *aptr = a; + cad = g_malloc( sizeof( struct cmd_account_del_data ) ); + cad->a = a; + cad->irc = irc; msg = g_strdup_printf( "If you remove this account (%s(%s)), BitlBee will " "also forget all your saved nicknames. If you want " "to change your username/password, use the `account " "set' command. Are you sure you want to delete this " "account?", a->prpl->name, a->user ); - query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, aptr ); + query_add( irc, NULL, msg, cmd_account_del_yes, cmd_account_del_no, cad ); g_free( msg ); } } -- cgit v1.2.3 From 1195cecc99315c9c38e05c8dd0981792e7663583 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 5 Apr 2008 14:03:31 +0100 Subject: Changed root nicknames are now saved. (Bug #378) --- bitlbee.h | 2 ++ doc/user-guide/commands.xml | 10 ++++++++++ irc.c | 1 + root_commands.c | 17 +++++++++++++++++ 4 files changed, 30 insertions(+) diff --git a/bitlbee.h b/bitlbee.h index 420ab70a..60694a2a 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -159,6 +159,8 @@ void root_command_string( irc_t *irc, user_t *u, char *command, int flags ); void root_command( irc_t *irc, char *command[] ); gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond ); +char *set_eval_root_nick( set_t *set, char *new_nick ); + extern global_t global; #endif diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index c45727b9..6d77f8cd 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -588,6 +588,16 @@ + + root + + + + Normally the "bot" that takes all your BitlBee commands is called "root". If you don't like this name, you can rename it to anything else using the rename command, or by changing this setting. + + + + true diff --git a/irc.c b/irc.c index c929d68b..a6220140 100644 --- a/irc.c +++ b/irc.c @@ -150,6 +150,7 @@ irc_t *irc_new( int fd ) set_add( &irc->set, "password", NULL, passchange, irc ); set_add( &irc->set, "private", "true", set_eval_bool, irc ); set_add( &irc->set, "query_order", "lifo", NULL, irc ); + set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc ); set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc ); set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc ); set_add( &irc->set, "strip_html", "true", NULL, irc ); diff --git a/root_commands.c b/root_commands.c index aec91455..4b27afe3 100644 --- a/root_commands.c +++ b/root_commands.c @@ -602,6 +602,9 @@ static void cmd_rename( irc_t *irc, char **cmd ) { g_free( irc->mynick ); irc->mynick = g_strdup( cmd[2] ); + + if( strcmp( cmd[0], "set_rename" ) != 0 ) + set_setstr( &irc->set, "root_nick", cmd[2] ); } else if( u->send_handler == buddy_send_handler ) { @@ -612,6 +615,20 @@ static void cmd_rename( irc_t *irc, char **cmd ) } } +char *set_eval_root_nick( set_t *set, char *new_nick ) +{ + irc_t *irc = set->data; + + if( strcmp( irc->mynick, new_nick ) != 0 ) + { + char *cmd[] = { "set_rename", irc->mynick, new_nick, NULL }; + + cmd_rename( irc, cmd ); + } + + return strcmp( irc->mynick, new_nick ) == 0 ? new_nick : NULL; +} + static void cmd_remove( irc_t *irc, char **cmd ) { user_t *u; -- cgit v1.2.3 From aa311173a85020bcbbbf61135a5451e171d422f5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 8 Apr 2008 21:44:34 +0100 Subject: Don't automatically enable MSN debugging messages for debugging builds. --- protocols/msn/msn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index c8f4f4c6..63759303 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -28,7 +28,7 @@ #define TYPING_NOTIFICATION_MESSAGE "\r\r\rBEWARE, ME R TYPINK MESSAGE!!!!\r\r\r" #define GROUPCHAT_SWITCHBOARD_MESSAGE "\r\r\rME WANT TALK TO MANY PEOPLE\r\r\r" -#ifdef DEBUG +#ifdef DEBUG_MSN #define debug( text... ) imcb_log( ic, text ); #else #define debug( text... ) -- cgit v1.2.3