From d9d36fc09996ed8c2574f9336c3594aa3cc56941 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 21 Dec 2005 13:13:10 +0100 Subject: Add initial draft of BitlBee schema --- doc/bitlbee.schema | 27 +++++++++++++++++++++++++++ storage.c | 2 ++ 2 files changed, 29 insertions(+) create mode 100644 doc/bitlbee.schema diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema new file mode 100644 index 00000000..47d5e706 --- /dev/null +++ b/doc/bitlbee.schema @@ -0,0 +1,27 @@ +## LDAP Schema file for BitlBee +## +## We need the following object classes and related attributes: +## bitlBeeNick: +## - nick +## - password +## - setting (multiple values) +## +## bitlBeeAccount: +## - protocol (msn, oscar, jabber, yahoo, ...) +## - username +## - password +## - server name +## +## bitlBeeBuddy: +## - nick +## - handle + +## each bitlBeeNick has zero or more bitlBeeAccount subentries +## and bitlBeeAccount entries contain zero or more bitlBeeBuddy entries + +## The admin needs to setup the LDAP server to: +## - allow anonymous users to auth against bitlBeeNick objects on the +## password field +## - allow anonymous users to create new objects that start with nick= +## - allow read/write for a user that is authenticated only to his/her own +## object and subentries diff --git a/storage.c b/storage.c index b766c9e3..7a242c3c 100644 --- a/storage.c +++ b/storage.c @@ -6,6 +6,8 @@ /* Support for multiple storage backends */ +/* Copyright (C) 2005 Jelmer Vernooij */ + /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From a323a22773714a19254db34156500a67e5916451 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 12 Feb 2006 20:25:31 +1300 Subject: Add autoconnect property --- doc/bitlbee.schema | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema index 47d5e706..9fc6895c 100644 --- a/doc/bitlbee.schema +++ b/doc/bitlbee.schema @@ -11,6 +11,7 @@ ## - username ## - password ## - server name +## - autoconnect (true/false) ## ## bitlBeeBuddy: ## - nick -- cgit v1.2.3 From f665dabdff831743ea35e755b6ec1e2fe2551d9c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 12 Feb 2006 21:02:03 +1300 Subject: Initial work on new LDB-based storage backend --- Makefile | 2 ++ configure | 35 +++++++++++++++++++++++++++++++++ storage_ldb.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 storage_ldb.c diff --git a/Makefile b/Makefile index 295fe69e..a32c2639 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,8 @@ objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o unix.o url.o user.o util.o subdirs = protocols +objects += $(LDB_OBJ) + # Expansion of variables subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o) CFLAGS += -Wall diff --git a/configure b/configure index 2731d5b1..f0f2adcc 100755 --- a/configure +++ b/configure @@ -24,6 +24,7 @@ yahoo=1 debug=0 strip=1 ipv6=1 +ldb=auto ssl=auto arch=`uname -s` @@ -59,6 +60,8 @@ Option Description Default --ipv6=0/1 IPv6 socket support $ipv6 +--ldb=0/1/auto LDB support $ldb + --ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto) $ssl EOF @@ -210,6 +213,20 @@ EOF fi; } +detect_ldb() +{ + if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG ldb; then + cat<>Makefile.settings +EFLAGS+=`$PKG_CONFIG --libs ldb` +CFLAGS+=`$PKG_CONFIG --cflags ldb` +EOF + ldb=1 + ret=1 + else + ret=0 + fi +} + if [ "$msn" = 1 -o "$jabber" = 1 ]; then if [ "$ssl" = "auto" ]; then detect_gnutls @@ -270,6 +287,18 @@ if [ "$msn" = 1 -o "$jabber" = 1 ]; then echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings fi +if [ "$ldb" = "auto" ]; then + detect_ldb +fi + +if [ "$ldb" = 0 ]; then + echo "LDB_OBJ=\# no ldb" >> Makefile.settings + echo "#undef LDB" >> config.h +elif [ "$ldb" = 1 ]; then + echo "#define LDB 1" >> config.h + echo "LDB_OBJ=storage_ldb.o" >> Makefile.settings +fi + if [ "$strip" = 0 ]; then echo "STRIP=\# skip strip" >> Makefile.settings; else @@ -407,3 +436,9 @@ if [ -n "$protocols" ]; then else echo ' Building without IM-protocol support. We wish you a lot of fun...'; fi + +if [ "$ldb" = "0" ]; then + echo " LDB storage backend disabled." +else + echo " LDB storage backend enabled." +fi diff --git a/storage_ldb.c b/storage_ldb.c new file mode 100644 index 00000000..09d1452b --- /dev/null +++ b/storage_ldb.c @@ -0,0 +1,63 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Storage backend that uses the LDB embedded LDAP-like database */ + +/* Copyright (C) 2006 Jelmer Vernooij */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#define BITLBEE_CORE +#include "bitlbee.h" +#include + +static void sldb_init (void) +{ +} + +static storage_status_t sldb_load ( const char *my_nick, const char* password, irc_t *irc ) +{ + return STORAGE_OK; +} + +static storage_status_t sldb_save( irc_t *irc, int overwrite ) +{ + return STORAGE_OK; +} + +static storage_status_t sldb_check_pass( const char *nick, const char *password ) +{ + return STORAGE_OK; +} + +static storage_status_t sldb_remove( const char *nick, const char *password ) +{ + return STORAGE_OK; +} + +storage_t storage_ldb = { + .name = "ldb", + .init = sldb_init, + .check_pass = sldb_check_pass, + .remove = sldb_remove, + .load = sldb_load, + .save = sldb_save +}; -- cgit v1.2.3 From f32d5578d7039f1e61e99b2e1f7bfd0a47828c8c Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 24 Mar 2006 16:53:29 +0100 Subject: Switch from LDB to LDAP (LDB's authentication subsystem is not mature enough yet) --- Makefile | 2 +- configure | 30 +++++------ storage_ldap.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ storage_ldb.c | 63 ---------------------- 4 files changed, 178 insertions(+), 79 deletions(-) create mode 100644 storage_ldap.c delete mode 100644 storage_ldb.c diff --git a/Makefile b/Makefile index 9d16c53c..845beb1c 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_com headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h subdirs = protocols -objects += $(LDB_OBJ) +objects += $(LDAP_OBJ) # Expansion of variables subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o) diff --git a/configure b/configure index 60d27b2e..6426a789 100755 --- a/configure +++ b/configure @@ -27,7 +27,7 @@ yahoo=1 debug=0 strip=1 ipv6=1 -ldb=auto +ldap=auto ssl=auto arch=`uname -s` @@ -64,7 +64,7 @@ Option Description Default --ipv6=0/1 IPv6 socket support $ipv6 ---ldb=0/1/auto LDB support $ldb +--ldap=0/1/auto LDAP support $ldap --ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto) $ssl @@ -223,14 +223,14 @@ EOF fi; } -detect_ldb() +detect_ldap() { if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG ldb; then cat<>Makefile.settings EFLAGS+=`$PKG_CONFIG --libs ldb` CFLAGS+=`$PKG_CONFIG --cflags ldb` EOF - ldb=1 + ldap=1 ret=1 else ret=0 @@ -297,16 +297,16 @@ if [ "$msn" = 1 -o "$jabber" = 1 ]; then echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings fi -if [ "$ldb" = "auto" ]; then - detect_ldb +if [ "$ldap" = "auto" ]; then + detect_ldap fi -if [ "$ldb" = 0 ]; then - echo "LDB_OBJ=\# no ldb" >> Makefile.settings - echo "#undef LDB" >> config.h -elif [ "$ldb" = 1 ]; then - echo "#define LDB 1" >> config.h - echo "LDB_OBJ=storage_ldb.o" >> Makefile.settings +if [ "$ldap" = 0 ]; then + echo "LDAP_OBJ=\# no ldap" >> Makefile.settings + echo "#undef LDAP" >> config.h +elif [ "$ldap" = 1 ]; then + echo "#define LDAP 1" >> config.h + echo "LDAP_OBJ=storage_ldap.o" >> Makefile.settings fi if [ "$strip" = 0 ]; then @@ -460,8 +460,8 @@ else echo ' Building without IM-protocol support. We wish you a lot of fun...'; fi -if [ "$ldb" = "0" ]; then - echo " LDB storage backend disabled." +if [ "$ldap" = "0" ]; then + echo " LDAP storage backend disabled." else - echo " LDB storage backend enabled." + echo " LDAP storage backend enabled." fi diff --git a/storage_ldap.c b/storage_ldap.c new file mode 100644 index 00000000..f6119168 --- /dev/null +++ b/storage_ldap.c @@ -0,0 +1,162 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Storage backend that uses a LDAP database */ + +/* Copyright (C) 2006 Jelmer Vernooij */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#define BITLBEE_CORE +#include "bitlbee.h" +#include + +#define BB_LDAP_HOST "localhost" +#define BB_LDAP_BASE "" + +static char *nick_dn(const char *nick) +{ + return g_strdup_printf("bitlBeeNick=%s%s%s", nick, BB_LDAP_BASE?",":"", BB_LDAP_BASE?BB_LDAP_BASE:""); +} + +static storage_status_t nick_connect(const char *nick, const char *password, LDAP **ld) +{ + char *mydn; + int ret; + storage_status_t status; + *ld = ldap_init(BB_LDAP_HOST, LDAP_PORT); + + if (!ld) { + /* FIXME: report error */ + return STORAGE_OTHER_ERROR; + } + + mydn = nick_dn(nick); + + ret = ldap_simple_bind_s(*ld, mydn, password); + + switch (ret) { + case LDAP_SUCCESS: status = STORAGE_OK; break; + case LDAP_INVALID_CREDENTIALS: status = STORAGE_INVALID_PASSWORD; break; + default: + /* FIXME: Log */ + status = STORAGE_OTHER_ERROR; + break; + } + + g_free(mydn); + + return status; +} + +static void sldap_init (void) +{ +} + +static storage_status_t sldap_load ( const char *my_nick, const char* password, irc_t *irc ) +{ + LDAPMessage *res; + LDAP *ld; + int ret; + storage_status_t status; + char *mydn; + + status = nick_connect(my_nick, password, &ld); + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(my_nick); + + ret = ldap_search_s(ld, mydn, LDAP_SCOPE_ONELEVEL, "(objectClass=*)", NULL, 0, &res); + + g_free(mydn); + + /* FIXME: Check ret */ + + /* FIXME: Store in irc_t */ + + return STORAGE_OK; +} + +static storage_status_t sldap_save( irc_t *irc, int overwrite ) +{ + LDAP *ld; + char *mydn; + storage_status_t status; + + status = nick_connect(irc->nick, irc->password, &ld); + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(irc->nick); + + /* FIXME */ + + g_free(mydn); + + return STORAGE_OK; +} + +static storage_status_t sldap_check_pass( const char *nick, const char *password ) +{ + LDAP *ld; + storage_status_t status; + + status = nick_connect(nick, password, &ld); + + ldap_unbind_s(ld); + + return status; +} + +static storage_status_t sldap_remove( const char *nick, const char *password ) +{ + storage_status_t status; + LDAP *ld; + char *mydn; + int ret; + + status = nick_connect(nick, password, &ld); + + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(nick); + + ret = ldap_delete(ld, mydn); + + if (ret != LDAP_SUCCESS) { + /* FIXME: report */ + return STORAGE_OTHER_ERROR; + } + + g_free(mydn); + return STORAGE_OK; +} + +storage_t storage_ldap = { + .name = "ldap", + .init = sldap_init, + .check_pass = sldap_check_pass, + .remove = sldap_remove, + .load = sldap_load, + .save = sldap_save +}; diff --git a/storage_ldb.c b/storage_ldb.c deleted file mode 100644 index 09d1452b..00000000 --- a/storage_ldb.c +++ /dev/null @@ -1,63 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* Storage backend that uses the LDB embedded LDAP-like database */ - -/* Copyright (C) 2006 Jelmer Vernooij */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#define BITLBEE_CORE -#include "bitlbee.h" -#include - -static void sldb_init (void) -{ -} - -static storage_status_t sldb_load ( const char *my_nick, const char* password, irc_t *irc ) -{ - return STORAGE_OK; -} - -static storage_status_t sldb_save( irc_t *irc, int overwrite ) -{ - return STORAGE_OK; -} - -static storage_status_t sldb_check_pass( const char *nick, const char *password ) -{ - return STORAGE_OK; -} - -static storage_status_t sldb_remove( const char *nick, const char *password ) -{ - return STORAGE_OK; -} - -storage_t storage_ldb = { - .name = "ldb", - .init = sldb_init, - .check_pass = sldb_check_pass, - .remove = sldb_remove, - .load = sldb_load, - .save = sldb_save -}; -- cgit v1.2.3 From d5dfc3d7ff2756a5991356bb643630fa7b03f8d9 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 24 Mar 2006 17:48:00 +0100 Subject: Start working on LDAP schema (OID's still need to be filled in) --- doc/bitlbee.schema | 65 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema index 9fc6895c..795f5854 100644 --- a/doc/bitlbee.schema +++ b/doc/bitlbee.schema @@ -1,17 +1,7 @@ ## LDAP Schema file for BitlBee +## Copyright (C) 2006 Jelmer Vernooij ## ## We need the following object classes and related attributes: -## bitlBeeNick: -## - nick -## - password -## - setting (multiple values) -## -## bitlBeeAccount: -## - protocol (msn, oscar, jabber, yahoo, ...) -## - username -## - password -## - server name -## - autoconnect (true/false) ## ## bitlBeeBuddy: ## - nick @@ -26,3 +16,56 @@ ## - allow anonymous users to create new objects that start with nick= ## - allow read/write for a user that is authenticated only to his/her own ## object and subentries + +## - userid +## - userPassword +## - setting (multiple values) +## depends: top, account + +#FIXME: Unique OID + +attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'bitlBeeAutoConnect' + DESC 'Autoconnect setting' + EQUALITY booleanMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) + +#FIXME: Unique OID + +attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'bitlBeeAccountNo' + DESC 'Account number' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) + +#FIXME: Unique OID + +objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeAccount' SUP account STRUCTURAL + DESC 'BitlBee User Account ' + MUST ( userid, userPassword ) + MAY ( ) ) + +## bitlBeeAccount: +## - accountNo 1.3.6.1.4.1.1466.115.121.1.27 +## - protocol (msn, oscar, jabber, yahoo, ...) +## - username +## - password +## - server name +## - autoconnect (true/false) 1.3.6.1.4.1.1466.115.121.1.7 +## depends: top + +#FIXME: Unique OID +objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeIMAccount' SUP account STRUCTURAL + DESC 'BitlBee IM Account ' + MUST ( bitlBeeAccountNo, userid, userPassword ) + MAY ( host, bitlBeeAutoconnect ) ) + +#FIXME: Unique OID +objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeSetting' SUP top STRUCTURAL + DESC 'BitlBee Configuration Setting' + MUST ( bitlBeeSettingName ) + MAY ( bitlBeeSettingValue ) ) + +#FIXME: Unique OID +objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeBuddy' SUP top STRUCTURAL + DESC 'BitlBee Nick Mapping' + MUST ( bitlBeeBuddyHandle ) + MAY ( ircNick ) ) -- cgit v1.2.3 From a15c097fa32028394264cf66ef4fd31f56315eb3 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 24 Mar 2006 17:48:16 +0100 Subject: More work on LDAP backend; report errors --- storage_ldap.c | 75 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/storage_ldap.c b/storage_ldap.c index f6119168..4bc99de5 100644 --- a/storage_ldap.c +++ b/storage_ldap.c @@ -45,7 +45,7 @@ static storage_status_t nick_connect(const char *nick, const char *password, LDA *ld = ldap_init(BB_LDAP_HOST, LDAP_PORT); if (!ld) { - /* FIXME: report error */ + log_message( LOGLVL_WARNING, "Unable to connect to LDAP server at %s", BB_LDAP_HOST ); return STORAGE_OTHER_ERROR; } @@ -57,7 +57,7 @@ static storage_status_t nick_connect(const char *nick, const char *password, LDA case LDAP_SUCCESS: status = STORAGE_OK; break; case LDAP_INVALID_CREDENTIALS: status = STORAGE_INVALID_PASSWORD; break; default: - /* FIXME: Log */ + log_message( LOGLVL_WARNING, "Unable to authenticate %s: %s", mydn, ldap_err2string(ret) ); status = STORAGE_OTHER_ERROR; break; } @@ -67,15 +67,11 @@ static storage_status_t nick_connect(const char *nick, const char *password, LDA return status; } -static void sldap_init (void) -{ -} - static storage_status_t sldap_load ( const char *my_nick, const char* password, irc_t *irc ) { - LDAPMessage *res; + LDAPMessage *res, *msg; LDAP *ld; - int ret; + int ret, i; storage_status_t status; char *mydn; @@ -85,32 +81,22 @@ static storage_status_t sldap_load ( const char *my_nick, const char* password, mydn = nick_dn(my_nick); - ret = ldap_search_s(ld, mydn, LDAP_SCOPE_ONELEVEL, "(objectClass=*)", NULL, 0, &res); + ret = ldap_search_s(ld, mydn, LDAP_SCOPE_BASE, "(objectClass=*)", NULL, 0, &res); + + if (ret != LDAP_SUCCESS) { + log_message( LOGLVL_WARNING, "Unable to search for %s: %s", mydn, ldap_err2string(ret) ); + ldap_unbind_s(ld); + return STORAGE_OTHER_ERROR; + } g_free(mydn); - /* FIXME: Check ret */ + for (msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) { + } /* FIXME: Store in irc_t */ - - return STORAGE_OK; -} - -static storage_status_t sldap_save( irc_t *irc, int overwrite ) -{ - LDAP *ld; - char *mydn; - storage_status_t status; - status = nick_connect(irc->nick, irc->password, &ld); - if (status != STORAGE_OK) - return status; - - mydn = nick_dn(irc->nick); - - /* FIXME */ - - g_free(mydn); + ldap_unbind_s(ld); return STORAGE_OK; } @@ -144,17 +130,46 @@ static storage_status_t sldap_remove( const char *nick, const char *password ) ret = ldap_delete(ld, mydn); if (ret != LDAP_SUCCESS) { - /* FIXME: report */ + log_message( LOGLVL_WARNING, "Error removing %s: %s", mydn, ldap_err2string(ret) ); + ldap_unbind_s(ld); return STORAGE_OTHER_ERROR; } + ldap_unbind_s(ld); + g_free(mydn); return STORAGE_OK; } +static storage_status_t sldap_save( irc_t *irc, int overwrite ) +{ + LDAP *ld; + char *mydn; + storage_status_t status; + LDAPMessage *msg; + + status = nick_connect(irc->nick, irc->password, &ld); + if (status != STORAGE_OK) + return status; + + mydn = nick_dn(irc->nick); + + /* FIXME: Make this a bit more atomic? What if we crash after + * removing the old account but before adding the new one ? */ + if (overwrite) + sldap_remove(irc->nick, irc->password); + + g_free(mydn); + + ldap_unbind_s(ld); + + return STORAGE_OK; +} + + + storage_t storage_ldap = { .name = "ldap", - .init = sldap_init, .check_pass = sldap_check_pass, .remove = sldap_remove, .load = sldap_load, -- cgit v1.2.3 From 5973412f44269f6cb796c9d6d38c151290c7367a Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 3 Jun 2006 22:52:40 +0200 Subject: Try to detect -lldap --- configure | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 97df1e27..c8a4c49f 100755 --- a/configure +++ b/configure @@ -142,16 +142,18 @@ echo CFLAGS+=-I`pwd` -I`pwd`/protocols -I. >> Makefile.settings echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings if [ -n "$CC" ]; then - echo "CC=$CC" >> Makefile.settings; + CC=$CC elif type gcc > /dev/null 2> /dev/null; then - echo "CC=gcc" >> Makefile.settings; + CC=gcc elif type cc > /dev/null 2> /dev/null; then - echo "CC=cc" >> Makefile.settings; + CC=cc else echo 'Cannot find a C compiler, aborting.' exit 1; fi +echo "CC=$CC" >> Makefile.settings; + if [ -n "$LD" ]; then echo "LD=$LD" >> Makefile.settings; elif type ld > /dev/null 2> /dev/null; then @@ -207,14 +209,17 @@ EOF detect_ldap() { - if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG ldb; then + TMPFILE=`mktemp` + if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then cat<>Makefile.settings -EFLAGS+=`$PKG_CONFIG --libs ldb` -CFLAGS+=`$PKG_CONFIG --cflags ldb` +EFLAGS+=-lldap +CFLAGS+= EOF ldap=1 + rm -f $TMPFILE ret=1 else + ldap=0 ret=0 fi } @@ -285,9 +290,9 @@ fi if [ "$ldap" = 0 ]; then echo "LDAP_OBJ=\# no ldap" >> Makefile.settings - echo "#undef LDAP" >> config.h + echo "#undef WITH_LDAP" >> config.h elif [ "$ldap" = 1 ]; then - echo "#define LDAP 1" >> config.h + echo "#define WITH_LDAP 1" >> config.h echo "LDAP_OBJ=storage_ldap.o" >> Makefile.settings fi -- cgit v1.2.3 From 0025b5148725e524dfdc1da57b18fcd2be2608ee Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sat, 3 Jun 2006 23:08:58 +0200 Subject: Use unique OID's and include BitlBee's OID (25873) --- doc/bitlbee.schema | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema index 795f5854..3322e057 100644 --- a/doc/bitlbee.schema +++ b/doc/bitlbee.schema @@ -22,23 +22,17 @@ ## - setting (multiple values) ## depends: top, account -#FIXME: Unique OID - -attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'bitlBeeAutoConnect' +attributetype ( 1.3.6.1.4.1.25873.2.1.1 NAME 'bitlBeeAutoConnect' DESC 'Autoconnect setting' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) -#FIXME: Unique OID - -attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'bitlBeeAccountNo' +attributetype ( 1.3.6.1.4.1.25873.2.1.2 NAME 'bitlBeeAccountNo' DESC 'Account number' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) -#FIXME: Unique OID - -objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeAccount' SUP account STRUCTURAL +objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeAccount' SUP account STRUCTURAL DESC 'BitlBee User Account ' MUST ( userid, userPassword ) MAY ( ) ) @@ -52,20 +46,17 @@ objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeAccount' SUP account STRUCTUR ## - autoconnect (true/false) 1.3.6.1.4.1.1466.115.121.1.7 ## depends: top -#FIXME: Unique OID -objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeIMAccount' SUP account STRUCTURAL +objectclass ( 1.3.6.1.4.1.25873.2.2.1 NAME 'bitlBeeIMAccount' SUP account STRUCTURAL DESC 'BitlBee IM Account ' MUST ( bitlBeeAccountNo, userid, userPassword ) MAY ( host, bitlBeeAutoconnect ) ) -#FIXME: Unique OID -objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeSetting' SUP top STRUCTURAL +objectclass ( 1.3.6.1.4.1.25873.2.2.2 NAME 'bitlBeeSetting' SUP top STRUCTURAL DESC 'BitlBee Configuration Setting' MUST ( bitlBeeSettingName ) MAY ( bitlBeeSettingValue ) ) -#FIXME: Unique OID -objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'bitlBeeBuddy' SUP top STRUCTURAL +objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeBuddy' SUP top STRUCTURAL DESC 'BitlBee Nick Mapping' MUST ( bitlBeeBuddyHandle ) MAY ( ircNick ) ) -- cgit v1.2.3 From a312b6bcbc6aa836850d94fc2abc70ceffe275cd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 7 Jun 2006 13:25:46 +0200 Subject: Added storage_xml.c --- account.c | 2 +- storage_xml.c | 412 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 413 insertions(+), 1 deletion(-) create mode 100644 storage_xml.c diff --git a/account.c b/account.c index 168d18c0..810f3a6f 100644 --- a/account.c +++ b/account.c @@ -34,7 +34,7 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) if( irc->accounts ) { for( a = irc->accounts; a->next; a = a->next ); - a = a->next = g_new0 ( account_t, 1 ); + a = a->next = g_new0( account_t, 1 ); } else { diff --git a/storage_xml.c b/storage_xml.c new file mode 100644 index 00000000..b27e63ad --- /dev/null +++ b/storage_xml.c @@ -0,0 +1,412 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Storage backend that uses an XMLish format for all data. */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#define BITLBEE_CORE +#include "bitlbee.h" + +struct xml_parsedata +{ + irc_t *irc; + char *current_setting; + account_t *current_account; +}; + +static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key ) +{ + int i; + + for( i = 0; attr_names[i]; i ++ ) + if( g_strcasecmp( attr_names[i], key ) == 0 ) + return attr_values[i]; + + return NULL; +} + +static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) +{ + struct xml_parsedata *xd = data; + irc_t *irc = data->irc; + + if( g_strcasecmp( element_name, "user" ) == 0 ) + { + char *nick = xml_attr( attr_names, attr_values, "nick" ); + + if( nick && g_strcasecmp( nick, irc->nick ) == 0 ) + { + /* Okay! */ + } + } + else if( g_strcasecmp( element_name, "account" ) == 0 ) + { + char *protocol, *handle, *password; + struct prpl *prpl = NULL; + + handle = xml_attr( attr_names, attr_values, "handle" ); + password = xml_attr( attr_names, attr_values, "password" ); + + protocol = xml_attr( attr_names, attr_values, "protocol" ); + if( protocol ) + prpl = find_protocol( protocol ); + + if( handle && password && prpl ) + { + xd->current_account = account_add( irc, prpl, handle, password ) + } + } + else if( g_strcasecmp( element_name, "setting" ) == 0 ) + { + if( xd->current_account == NULL ) + { + current_setting = xml_attr( attr_names, attr_values, "name" ); + } + } + else if( g_strcasecmp( element_name, "buddy" ) == 0 ) + { + } + else if( g_strcasecmp( element_name, "password" ) == 0 ) + { + } + else + { + /* Return "unknown element" error. */ + } +} + +static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) +{ +} + +static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +{ + struct xml_parsedata *xd = data; + irc_t *irc = data->irc; + + if( xd->current_setting ) + { + set_setstr( irc, xd->current_setting, text ); + } +} + +static void xml_error( GMarkupParseContext *ctx, GError *error, gpointer data ) +{ +} + +GMarkupParser xml_parser = +{ + xml_start_element, + xml_end_element, + xml_text, + NULL, + xml_error +}; + +static void xml_init( void ) +{ + if( access( global.conf->configdir, F_OK ) != 0 ) + log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG ); + else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 ) + log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); +} + +static storage_status_t xml_load ( const char *my_nick, const char* password, irc_t *irc ) +{ + GMarkupParseContext *ctx; + + ctx = g_markup_parse_context_new( parser, 0, xd, NULL ); + if( irc->status >= USTATUS_IDENTIFIED ) + return( 1 ); + + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" ); + fp = fopen( s, "r" ); + if( !fp ) return STORAGE_NO_SUCH_USER; + + fscanf( fp, "%32[^\n]s", s ); + + if (checkpass (password, s) != 0) + { + fclose( fp ); + return STORAGE_INVALID_PASSWORD; + } + + /* Do this now. If the user runs with AuthMode = Registered, the + account command will not work otherwise. */ + irc->status = USTATUS_IDENTIFIED; + + while( fscanf( fp, "%511[^\n]s", s ) > 0 ) + { + fgetc( fp ); + line = deobfucrypt( s, password ); + if (line == NULL) return STORAGE_OTHER_ERROR; + root_command_string( irc, ru, line, 0 ); + g_free( line ); + } + fclose( fp ); + + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" ); + fp = fopen( s, "r" ); + if( !fp ) return STORAGE_NO_SUCH_USER; + while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 ) + { + struct prpl *prpl; + + prpl = find_protocol_by_id(proto); + + if (!prpl) + continue; + + http_decode( s ); + nick_set( irc, s, prpl, nick ); + } + fclose( fp ); + + if( set_getint( irc, "auto_connect" ) ) + { + strcpy( s, "account on" ); /* Can't do this directly because r_c_s alters the string */ + root_command_string( irc, ru, s, 0 ); + } + + return STORAGE_OK; +} + +static storage_status_t text_save( irc_t *irc, int overwrite ) +{ + char s[512]; + char path[512], new_path[512]; + char *line; + nick_t *n; + set_t *set; + mode_t ou = umask( 0077 ); + account_t *a; + FILE *fp; + char *hash; + + if (!overwrite) { + g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); + if (access( path, F_OK ) != -1) + return STORAGE_ALREADY_EXISTS; + + g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); + if (access( path, F_OK ) != -1) + return STORAGE_ALREADY_EXISTS; + } + + /*\ + * [SH] Nothing should be saved if no password is set, because the + * password is not set if it was wrong, or if one is not identified + * yet. This means that a malicious user could easily overwrite + * files owned by someone else: + * a Bad Thing, methinks + \*/ + + /* [WVG] No? Really? */ + + /*\ + * [SH] Okay, okay, it wasn't really Wilmer who said that, it was + * me. I just thought it was funny. + \*/ + + hash = hashpass( irc->password ); + if( hash == NULL ) + { + irc_usermsg( irc, "Please register yourself if you want to save your settings." ); + return STORAGE_OTHER_ERROR; + } + + g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" ); + fp = fopen( path, "w" ); + if( !fp ) return STORAGE_OTHER_ERROR; + for( n = irc->nicks; n; n = n->next ) + { + strcpy( s, n->handle ); + s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */ + http_encode( s ); + g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick ); + if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 ) + { + irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); + fclose( fp ); + return STORAGE_OTHER_ERROR; + } + } + if( fclose( fp ) != 0 ) + { + irc_usermsg( irc, "fclose() reported an error. Disk full?" ); + return STORAGE_OTHER_ERROR; + } + + g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); + if( unlink( new_path ) != 0 ) + { + if( errno != ENOENT ) + { + irc_usermsg( irc, "Error while removing old .nicks file" ); + return STORAGE_OTHER_ERROR; + } + } + if( rename( path, new_path ) != 0 ) + { + irc_usermsg( irc, "Error while renaming new .nicks file" ); + return STORAGE_OTHER_ERROR; + } + + g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" ); + fp = fopen( path, "w" ); + if( !fp ) return STORAGE_OTHER_ERROR; + if( fprintf( fp, "%s", hash ) != strlen( hash ) ) + { + irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); + fclose( fp ); + return STORAGE_OTHER_ERROR; + } + g_free( hash ); + + for( a = irc->accounts; a; a = a->next ) + { + if( !strcmp(a->prpl->name, "oscar") ) + g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server ); + else + g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"", + a->prpl->name, a->user, a->pass, a->server ? a->server : "" ); + + line = obfucrypt( s, irc->password ); + if( *line ) + { + if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) + { + irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); + fclose( fp ); + return STORAGE_OTHER_ERROR; + } + } + g_free( line ); + } + + for( set = irc->set; set; set = set->next ) + { + if( set->value && set->def ) + { + g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value ); + line = obfucrypt( s, irc->password ); + if( *line ) + { + if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) + { + irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); + fclose( fp ); + return STORAGE_OTHER_ERROR; + } + } + g_free( line ); + } + } + + if( strcmp( irc->mynick, ROOT_NICK ) != 0 ) + { + g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick ); + line = obfucrypt( s, irc->password ); + if( *line ) + { + if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) + { + irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); + fclose( fp ); + return STORAGE_OTHER_ERROR; + } + } + g_free( line ); + } + if( fclose( fp ) != 0 ) + { + irc_usermsg( irc, "fclose() reported an error. Disk full?" ); + return STORAGE_OTHER_ERROR; + } + + g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); + if( unlink( new_path ) != 0 ) + { + if( errno != ENOENT ) + { + irc_usermsg( irc, "Error while removing old .accounts file" ); + return STORAGE_OTHER_ERROR; + } + } + if( rename( path, new_path ) != 0 ) + { + irc_usermsg( irc, "Error while renaming new .accounts file" ); + return STORAGE_OTHER_ERROR; + } + + umask( ou ); + + return STORAGE_OK; +} + +static storage_status_t text_check_pass( const char *nick, const char *password ) +{ + char s[512]; + FILE *fp; + + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" ); + fp = fopen( s, "r" ); + if (!fp) + return STORAGE_NO_SUCH_USER; + + fscanf( fp, "%32[^\n]s", s ); + fclose( fp ); + + if (checkpass( password, s) == -1) + return STORAGE_INVALID_PASSWORD; + + return STORAGE_OK; +} + +static storage_status_t text_remove( const char *nick, const char *password ) +{ + char s[512]; + storage_status_t status; + + status = text_check_pass( nick, password ); + if (status != STORAGE_OK) + return status; + + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" ); + if (unlink( s ) == -1) + return STORAGE_OTHER_ERROR; + + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" ); + if (unlink( s ) == -1) + return STORAGE_OTHER_ERROR; + + return STORAGE_OK; +} + +storage_t storage_xml = { + .name = "xml", + .init = xml_init, + .check_pass = xml_check_pass, + .remove = xml_remove, + .load = xml_load, + .save = xml_save +}; -- cgit v1.2.3 From c121f8945f7249520342ad86ff00f4986642ca0a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 14 Jun 2006 22:30:25 +0200 Subject: xml_load() works pretty well now. --- Makefile | 2 +- conf.c | 2 +- root_commands.c | 3 +- storage.c | 9 +- storage.h | 4 +- storage_xml.c | 390 ++++++++++++++++++++------------------------------------ 6 files changed, 147 insertions(+), 263 deletions(-) diff --git a/Makefile b/Makefile index 845beb1c..af710d59 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ -include Makefile.settings # Program variables -objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o unix.o url.o user.o util.o +objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o storage_xml.o unix.o url.o user.o util.o headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h subdirs = protocols diff --git a/conf.c b/conf.c index 7538825d..dd3a0704 100644 --- a/conf.c +++ b/conf.c @@ -54,7 +54,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->port = 6667; conf->nofork = 0; conf->verbose = 0; - conf->primary_storage = "text"; + conf->primary_storage = "xml"; conf->runmode = RUNMODE_INETD; conf->authmode = AUTHMODE_OPEN; conf->auth_pass = NULL; diff --git a/root_commands.c b/root_commands.c index 0e12e9ab..d44a36b7 100644 --- a/root_commands.c +++ b/root_commands.c @@ -141,8 +141,9 @@ static void cmd_identify( irc_t *irc, char **cmd ) irc_usermsg( irc, "Password accepted" ); irc_umode_set( irc, "+R", 1 ); break; + case STORAGE_OTHER_ERROR: default: - irc_usermsg( irc, "Something very weird happened" ); + irc_usermsg( irc, "Unknown error while loading configuration" ); break; } } diff --git a/storage.c b/storage.c index 7a242c3c..b8e07278 100644 --- a/storage.c +++ b/storage.c @@ -30,9 +30,9 @@ #include "crypting.h" extern storage_t storage_text; +extern storage_t storage_xml; -static GList text_entry = { &storage_text, NULL, NULL }; -static GList *storage_backends = &text_entry; +static GList *storage_backends = NULL; void register_storage_backend(storage_t *backend) { @@ -64,7 +64,10 @@ GList *storage_init(const char *primary, char **migrate) GList *ret = NULL; int i; storage_t *storage; - + + register_storage_backend(&storage_text); + register_storage_backend(&storage_xml); + storage = storage_init_single(primary); if (storage == NULL) return NULL; diff --git a/storage.h b/storage.h index 301b424c..3c641088 100644 --- a/storage.h +++ b/storage.h @@ -32,8 +32,8 @@ typedef enum { STORAGE_INVALID_PASSWORD, STORAGE_ALREADY_EXISTS, STORAGE_OTHER_ERROR /* Error that isn't caused by user input, such as - a database that is unreachable. log() will be - used for the exact error message */ + a database that is unreachable. log() will be + used for the exact error message */ } storage_status_t; typedef struct { diff --git a/storage_xml.c b/storage_xml.c index b27e63ad..29c01e07 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -26,11 +26,23 @@ #define BITLBEE_CORE #include "bitlbee.h" +typedef enum +{ + XML_PASS_CHECK_ONLY = -1, + XML_PASS_UNKNOWN = 0, + XML_PASS_OK +} xml_pass_st; + +#define XML_PASS_ERRORMSG "Wrong username or password" + struct xml_parsedata { irc_t *irc; char *current_setting; account_t *current_account; + char *given_nick; + char *given_pass; + xml_pass_st pass_st; }; static char *xml_attr( const gchar **attr_names, const gchar **attr_values, const gchar *key ) @@ -39,58 +51,118 @@ static char *xml_attr( const gchar **attr_names, const gchar **attr_values, cons for( i = 0; attr_names[i]; i ++ ) if( g_strcasecmp( attr_names[i], key ) == 0 ) - return attr_values[i]; + return (char*) attr_values[i]; return NULL; } +static void xml_destroy_xd( gpointer data ) +{ + struct xml_parsedata *xd = data; + + g_free( xd->given_nick ); + g_free( xd->given_pass ); + g_free( xd ); +} + static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error ) { struct xml_parsedata *xd = data; - irc_t *irc = data->irc; + irc_t *irc = xd->irc; if( g_strcasecmp( element_name, "user" ) == 0 ) { char *nick = xml_attr( attr_names, attr_values, "nick" ); + char *pass = xml_attr( attr_names, attr_values, "password" ); - if( nick && g_strcasecmp( nick, irc->nick ) == 0 ) + if( !nick || !pass ) { - /* Okay! */ + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); } + else if( strcmp( nick, xd->given_nick ) == 0 && + strcmp( pass, xd->given_pass ) == 0 ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + XML_PASS_ERRORMSG ); + } + } + else if( xd->pass_st < XML_PASS_OK ) + { + /* Let's not parse anything else if we only have to check + the password. */ } else if( g_strcasecmp( element_name, "account" ) == 0 ) { - char *protocol, *handle, *password; + char *protocol, *handle, *server, *password; struct prpl *prpl = NULL; handle = xml_attr( attr_names, attr_values, "handle" ); password = xml_attr( attr_names, attr_values, "password" ); + server = xml_attr( attr_names, attr_values, "server" ); protocol = xml_attr( attr_names, attr_values, "protocol" ); if( protocol ) prpl = find_protocol( protocol ); - if( handle && password && prpl ) + if( !handle || !password ) + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + else if( !prpl ) + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing or unknown protocol %s element", element_name ); + else { - xd->current_account = account_add( irc, prpl, handle, password ) + xd->current_account = account_add( irc, prpl, handle, password ); + if( server ) + xd->current_account->server = g_strdup( server ); } } else if( g_strcasecmp( element_name, "setting" ) == 0 ) { if( xd->current_account == NULL ) { - current_setting = xml_attr( attr_names, attr_values, "name" ); + char *setting; + + if( xd->current_setting ) + { + g_free( xd->current_setting ); + xd->current_setting = NULL; + } + + if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) + xd->current_setting = g_strdup( setting ); + else + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); } } else if( g_strcasecmp( element_name, "buddy" ) == 0 ) { - } - else if( g_strcasecmp( element_name, "password" ) == 0 ) - { + char *handle, *nick; + + handle = xml_attr( attr_names, attr_values, "handle" ); + nick = xml_attr( attr_names, attr_values, "nick" ); + + if( xd->current_account && handle && nick ) + { + nick_set( irc, handle, xd->current_account->prpl, nick ); + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); + } } else { - /* Return "unknown element" error. */ + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unkown element: %s", element_name ); } } @@ -101,11 +173,19 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) { struct xml_parsedata *xd = data; - irc_t *irc = data->irc; + irc_t *irc = xd->irc; - if( xd->current_setting ) + if( xd->pass_st < XML_PASS_OK ) + { + /* Let's not parse anything else if we only have to check + the password. */ + } + else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && + xd->current_setting && xd->current_account == NULL ) { - set_setstr( irc, xd->current_setting, text ); + set_setstr( irc, xd->current_setting, (char*) text ); + g_free( xd->current_setting ); + xd->current_setting = NULL; } } @@ -130,79 +210,66 @@ static void xml_init( void ) log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); } -static storage_status_t xml_load ( const char *my_nick, const char* password, irc_t *irc ) +static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc ) { GMarkupParseContext *ctx; + struct xml_parsedata *xd; + char *fn, buf[512]; + GError *gerr = NULL; + int fd, st; - ctx = g_markup_parse_context_new( parser, 0, xd, NULL ); if( irc->status >= USTATUS_IDENTIFIED ) return( 1 ); - g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".accounts" ); - fp = fopen( s, "r" ); - if( !fp ) return STORAGE_NO_SUCH_USER; + xd = g_new0( struct xml_parsedata, 1 ); + xd->irc = irc; + xd->given_nick = g_strdup( my_nick ); + xd->given_pass = g_strdup( password ); + nick_lc( xd->given_nick ); - fscanf( fp, "%32[^\n]s", s ); - - if (checkpass (password, s) != 0) + fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" ); + if( ( fd = open( fn, O_RDONLY ) ) < 0 ) { - fclose( fp ); - return STORAGE_INVALID_PASSWORD; + xml_destroy_xd( xd ); + g_free( fn ); + return STORAGE_NO_SUCH_USER; } + g_free( fn ); - /* Do this now. If the user runs with AuthMode = Registered, the - account command will not work otherwise. */ - irc->status = USTATUS_IDENTIFIED; + ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd ); - while( fscanf( fp, "%511[^\n]s", s ) > 0 ) + while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 ) { - fgetc( fp ); - line = deobfucrypt( s, password ); - if (line == NULL) return STORAGE_OTHER_ERROR; - root_command_string( irc, ru, line, 0 ); - g_free( line ); + if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr ) + { + g_markup_parse_context_free( ctx ); + + /* TODO: Display useful error msg */ + + if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 ) + return STORAGE_INVALID_PASSWORD; + else + return STORAGE_OTHER_ERROR; + } } - fclose( fp ); - g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" ); - fp = fopen( s, "r" ); - if( !fp ) return STORAGE_NO_SUCH_USER; - while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 ) - { - struct prpl *prpl; - - prpl = find_protocol_by_id(proto); - - if (!prpl) - continue; - - http_decode( s ); - nick_set( irc, s, prpl, nick ); - } - fclose( fp ); + g_markup_parse_context_free( ctx ); + + irc->status = USTATUS_IDENTIFIED; if( set_getint( irc, "auto_connect" ) ) { - strcpy( s, "account on" ); /* Can't do this directly because r_c_s alters the string */ - root_command_string( irc, ru, s, 0 ); + /* Can't do this directly because r_c_s alters the string */ + strcpy( buf, "account on" ); + root_command_string( irc, NULL, buf, 0 ); } return STORAGE_OK; } -static storage_status_t text_save( irc_t *irc, int overwrite ) +static storage_status_t xml_save( irc_t *irc, int overwrite ) { - char s[512]; - char path[512], new_path[512]; - char *line; - nick_t *n; - set_t *set; - mode_t ou = umask( 0077 ); - account_t *a; - FILE *fp; - char *hash; - - if (!overwrite) { +/* if (!overwrite) { g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); if (access( path, F_OK ) != -1) return STORAGE_ALREADY_EXISTS; @@ -211,202 +278,15 @@ static storage_status_t text_save( irc_t *irc, int overwrite ) if (access( path, F_OK ) != -1) return STORAGE_ALREADY_EXISTS; } - - /*\ - * [SH] Nothing should be saved if no password is set, because the - * password is not set if it was wrong, or if one is not identified - * yet. This means that a malicious user could easily overwrite - * files owned by someone else: - * a Bad Thing, methinks - \*/ - - /* [WVG] No? Really? */ - - /*\ - * [SH] Okay, okay, it wasn't really Wilmer who said that, it was - * me. I just thought it was funny. - \*/ - - hash = hashpass( irc->password ); - if( hash == NULL ) - { - irc_usermsg( irc, "Please register yourself if you want to save your settings." ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" ); - fp = fopen( path, "w" ); - if( !fp ) return STORAGE_OTHER_ERROR; - for( n = irc->nicks; n; n = n->next ) - { - strcpy( s, n->handle ); - s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */ - http_encode( s ); - g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick ); - if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - if( fclose( fp ) != 0 ) - { - irc_usermsg( irc, "fclose() reported an error. Disk full?" ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); - if( unlink( new_path ) != 0 ) - { - if( errno != ENOENT ) - { - irc_usermsg( irc, "Error while removing old .nicks file" ); - return STORAGE_OTHER_ERROR; - } - } - if( rename( path, new_path ) != 0 ) - { - irc_usermsg( irc, "Error while renaming new .nicks file" ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" ); - fp = fopen( path, "w" ); - if( !fp ) return STORAGE_OTHER_ERROR; - if( fprintf( fp, "%s", hash ) != strlen( hash ) ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - g_free( hash ); - - for( a = irc->accounts; a; a = a->next ) - { - if( !strcmp(a->prpl->name, "oscar") ) - g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server ); - else - g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"", - a->prpl->name, a->user, a->pass, a->server ? a->server : "" ); - - line = obfucrypt( s, irc->password ); - if( *line ) - { - if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - g_free( line ); - } - - for( set = irc->set; set; set = set->next ) - { - if( set->value && set->def ) - { - g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value ); - line = obfucrypt( s, irc->password ); - if( *line ) - { - if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - g_free( line ); - } - } - - if( strcmp( irc->mynick, ROOT_NICK ) != 0 ) - { - g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick ); - line = obfucrypt( s, irc->password ); - if( *line ) - { - if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - g_free( line ); - } - if( fclose( fp ) != 0 ) - { - irc_usermsg( irc, "fclose() reported an error. Disk full?" ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); - if( unlink( new_path ) != 0 ) - { - if( errno != ENOENT ) - { - irc_usermsg( irc, "Error while removing old .accounts file" ); - return STORAGE_OTHER_ERROR; - } - } - if( rename( path, new_path ) != 0 ) - { - irc_usermsg( irc, "Error while renaming new .accounts file" ); - return STORAGE_OTHER_ERROR; - } - - umask( ou ); - - return STORAGE_OK; -} - -static storage_status_t text_check_pass( const char *nick, const char *password ) -{ - char s[512]; - FILE *fp; - - g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" ); - fp = fopen( s, "r" ); - if (!fp) - return STORAGE_NO_SUCH_USER; - - fscanf( fp, "%32[^\n]s", s ); - fclose( fp ); - - if (checkpass( password, s) == -1) - return STORAGE_INVALID_PASSWORD; - - return STORAGE_OK; -} - -static storage_status_t text_remove( const char *nick, const char *password ) -{ - char s[512]; - storage_status_t status; - - status = text_check_pass( nick, password ); - if (status != STORAGE_OK) - return status; - - g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".accounts" ); - if (unlink( s ) == -1) - return STORAGE_OTHER_ERROR; - - g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".nicks" ); - if (unlink( s ) == -1) - return STORAGE_OTHER_ERROR; - +*/ return STORAGE_OK; } storage_t storage_xml = { .name = "xml", .init = xml_init, - .check_pass = xml_check_pass, - .remove = xml_remove, +// .check_pass = xml_check_pass, +// .remove = xml_remove, .load = xml_load, .save = xml_save }; -- cgit v1.2.3 From 10efa911cbf0d3761d42cc3e57973c8cd1a92821 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 17 Jun 2006 13:39:17 +0200 Subject: Fixed bug in LDAP Makefile generation. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index b05aa155..05fb7cb4 100755 --- a/configure +++ b/configure @@ -318,7 +318,7 @@ if [ "$ldap" = "auto" ]; then fi if [ "$ldap" = 0 ]; then - echo "LDAP_OBJ=\# no ldap" >> Makefile.settings + echo "LDAP_OBJ=" >> Makefile.settings echo "#undef WITH_LDAP" >> config.h elif [ "$ldap" = 1 ]; then echo "#define WITH_LDAP 1" >> config.h -- cgit v1.2.3 From d28f3b35855c8f8de0be9589334004b30d1ac394 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 19 Jun 2006 01:07:28 +0200 Subject: Now saving the password's md5sum instead of the plaintext version. --- storage_xml.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index 5eda46cc..12afe472 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -25,6 +25,7 @@ #define BITLBEE_CORE #include "bitlbee.h" +#include "md5.h" typedef enum { @@ -80,16 +81,35 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Missing attributes for %s element", element_name ); } - else if( strcmp( nick, xd->given_nick ) == 0 && - strcmp( pass, xd->given_pass ) == 0 ) - { - if( xd->pass_st != XML_PASS_CHECK_ONLY ) - xd->pass_st = XML_PASS_OK; - } else { - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - XML_PASS_ERRORMSG ); + md5_byte_t pass_md5[16]; + md5_state_t md5_state; + int pass_match, i, j; + + md5_init( &md5_state ); + md5_append( &md5_state, xd->given_pass, strlen( xd->given_pass ) ); + md5_finish( &md5_state, pass_md5 ); + + for( i = 0; i < 16 && pass[i*2] && pass[i*2+1]; i ++ ) + { + sscanf( pass + i * 2, "%2x", &j ); + if( j != pass_md5[i] ) + break; + } + /* If we reached the end of the loop, it was a match! */ + pass_match = i == 16; + + if( strcmp( nick, xd->given_nick ) == 0 && pass_match ) + { + if( xd->pass_st != XML_PASS_CHECK_ONLY ) + xd->pass_st = XML_PASS_OK; + } + else + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + XML_PASS_ERRORMSG ); + } } } else if( xd->pass_st < XML_PASS_OK ) -- cgit v1.2.3 From d028a77c97eeccc8d1345af008e2d8920116b637 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 19 Jun 2006 13:52:34 +0200 Subject: Better detection of incorrect MD5 password hashes. --- storage_xml.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index 12afe472..ff8f1351 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -85,31 +85,35 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { md5_byte_t pass_md5[16]; md5_state_t md5_state; - int pass_match, i, j; + int i, j; md5_init( &md5_state ); - md5_append( &md5_state, xd->given_pass, strlen( xd->given_pass ) ); + md5_append( &md5_state, (md5_byte_t*) xd->given_pass, strlen( xd->given_pass ) ); md5_finish( &md5_state, pass_md5 ); - for( i = 0; i < 16 && pass[i*2] && pass[i*2+1]; i ++ ) + for( i = 0; i < 16; i ++ ) { - sscanf( pass + i * 2, "%2x", &j ); + if( !isxdigit( pass[i*2] ) || !isxdigit( pass[i*2+1] ) || + sscanf( pass + i * 2, "%2x", &j ) != 1 ) + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Incorrect password MD5-hash" ); + break; + } if( j != pass_md5[i] ) + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + XML_PASS_ERRORMSG ); break; + } } - /* If we reached the end of the loop, it was a match! */ - pass_match = i == 16; - if( strcmp( nick, xd->given_nick ) == 0 && pass_match ) + /* 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; } - else - { - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - XML_PASS_ERRORMSG ); - } } } else if( xd->pass_st < XML_PASS_OK ) -- cgit v1.2.3 From 84e9cea2a80d4e8b05bbadbde923301685d05497 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 20 Jun 2006 23:36:53 +0200 Subject: Added xml_remove() and xml_check_pass(). --- storage_xml.c | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index ff8f1351..57388f67 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -34,6 +34,8 @@ typedef enum XML_PASS_OK } xml_pass_st; +/* This isn't very clean, probably making a separate error class + code for + BitlBee would be a better solution. But this will work for now... */ #define XML_PASS_ERRORMSG "Wrong username or password" struct xml_parsedata @@ -193,7 +195,6 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error ) { struct xml_parsedata *xd = data; - // irc_t *irc = xd->irc; if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting ) { @@ -214,7 +215,8 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le if( xd->pass_st < XML_PASS_OK ) { /* Let's not parse anything else if we only have to check - the password. */ + the password, or if we didn't get the chance to check it + yet. */ } else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting && xd->current_account == NULL ) @@ -242,7 +244,7 @@ static void xml_init( void ) log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); } -static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc ) +static storage_status_t xml_load_real( const char *my_nick, const char *password, irc_t *irc, xml_pass_st action ) { GMarkupParseContext *ctx; struct xml_parsedata *xd; @@ -250,13 +252,14 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc GError *gerr = NULL; int fd, st; - if( irc->status & USTATUS_IDENTIFIED ) + if( irc && irc->status & USTATUS_IDENTIFIED ) return( 1 ); xd = g_new0( struct xml_parsedata, 1 ); xd->irc = irc; xd->given_nick = g_strdup( my_nick ); xd->given_pass = g_strdup( password ); + xd->pass_st = action; nick_lc( xd->given_nick ); fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" ); @@ -282,7 +285,7 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc return STORAGE_INVALID_PASSWORD; else { - if( gerr ) + if( gerr && irc ) irc_usermsg( irc, "Error from XML-parser: %s", gerr->message ); return STORAGE_OTHER_ERROR; @@ -293,6 +296,9 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc g_markup_parse_context_free( ctx ); close( fd ); + if( action == XML_PASS_CHECK_ONLY ) + return STORAGE_OK; + irc->status |= USTATUS_IDENTIFIED; if( set_getint( irc, "auto_connect" ) ) @@ -305,6 +311,18 @@ static storage_status_t xml_load( const char *my_nick, const char *password, irc return STORAGE_OK; } +static storage_status_t xml_load( const char *my_nick, const char *password, irc_t *irc ) +{ + return xml_load_real( my_nick, password, irc, XML_PASS_UNKNOWN ); +} + +static storage_status_t xml_check_pass( const char *my_nick, const char *password ) +{ + /* This is a little bit risky because we have to pass NULL for the + irc_t argument. This *should* be fine, if I didn't miss anything... */ + return xml_load_real( my_nick, password, NULL, XML_PASS_CHECK_ONLY ); +} + static int xml_printf( int fd, char *fmt, ... ) { va_list params; @@ -395,11 +413,27 @@ write_error: return STORAGE_OTHER_ERROR; } +static storage_status_t xml_remove( const char *nick, const char *password ) +{ + char s[512]; + storage_status_t status; + + status = xml_check_pass( nick, password ); + if( status != STORAGE_OK ) + return status; + + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, nick, ".xml" ); + if( unlink( s ) == -1 ) + return STORAGE_OTHER_ERROR; + + return STORAGE_OK; +} + storage_t storage_xml = { .name = "xml", .init = xml_init, -// .check_pass = xml_check_pass, -// .remove = xml_remove, + .check_pass = xml_check_pass, + .remove = xml_remove, .load = xml_load, .save = xml_save }; -- cgit v1.2.3 From 2befb95e3bdaf5306b55342c175abca174e40ffb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 20 Jun 2006 23:37:16 +0200 Subject: Added migration storage defaults. --- conf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conf.c b/conf.c index dd3a0704..d70117f5 100644 --- a/conf.c +++ b/conf.c @@ -41,6 +41,7 @@ static int conf_loadini( conf_t *conf, char *file ); conf_t *conf_load( int argc, char *argv[] ) { + char *mig_list[2] = { "text", NULL }; conf_t *conf; int opt, i; @@ -55,6 +56,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->nofork = 0; conf->verbose = 0; conf->primary_storage = "xml"; + conf->migrate_storage = mig_list; conf->runmode = RUNMODE_INETD; conf->authmode = AUTHMODE_OPEN; conf->auth_pass = NULL; -- cgit v1.2.3 From ece2cd2eba78088a8cf9d4744aafb3f34dc97c5b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 20 Jun 2006 23:48:28 +0200 Subject: xml_save() now stores the password's md5sum too. Kind of ... important.. --- storage_xml.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index 57388f67..87fbb693 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -342,11 +342,19 @@ static int xml_printf( int fd, char *fmt, ... ) static storage_status_t xml_save( irc_t *irc, int overwrite ) { - char path[512], *path2; + char path[512], *path2, md5_buf[33]; set_t *set; nick_t *nick; account_t *acc; - int fd; + int fd, i; + md5_byte_t pass_md5[16]; + md5_state_t md5_state; + + if( irc->password == NULL ) + { + irc_usermsg( irc, "Please register yourself if you want to save your settings." ); + return STORAGE_OTHER_ERROR; + } g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, irc->nick, ".xml" ); @@ -360,7 +368,13 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OTHER_ERROR; } - if( !xml_printf( fd, "\n", irc->nick, irc->password ) ) + md5_init( &md5_state ); + md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) ); + md5_finish( &md5_state, pass_md5 ); + for( i = 0; i < 16; i ++ ) + g_snprintf( md5_buf + i * 2, 3, "%02x", pass_md5[i] ); + + if( !xml_printf( fd, "\n", irc->nick, md5_buf ) ) goto write_error; for( set = irc->set; set; set = set->next ) -- cgit v1.2.3 From 9b46b64b83314a177a7ca3f9f990ff8c78282a5a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 21 Jun 2006 00:05:04 +0200 Subject: Fixed error message for unknown protocols. --- storage_xml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index 87fbb693..737f2091 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -136,12 +136,12 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na if( protocol ) prpl = find_protocol( protocol ); - if( !handle || !password ) + if( !handle || !password || !protocol ) g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Missing attributes for %s element", element_name ); else if( !prpl ) g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - "Missing or unknown protocol %s element", element_name ); + "Unknown protocol: %s", protocol ); else { xd->current_account = account_add( irc, prpl, handle, password ); -- cgit v1.2.3 From 2b14eef99faf7e113cc6c17d68bf6402f87ddd66 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 21 Jun 2006 00:14:46 +0200 Subject: Implemented handling of autoconnect attribute. --- account.c | 1 + account.h | 1 + root_commands.c | 2 +- storage_xml.c | 9 +++++++-- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/account.c b/account.c index 810f3a6f..b75afa51 100644 --- a/account.c +++ b/account.c @@ -44,6 +44,7 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) a->prpl = prpl; a->user = g_strdup( user ); a->pass = g_strdup( pass ); + a->auto_connect = 1; a->irc = irc; return( a ); diff --git a/account.h b/account.h index 37cd8814..40efb101 100644 --- a/account.h +++ b/account.h @@ -33,6 +33,7 @@ typedef struct account char *pass; char *server; + int auto_connect; int reconnect; struct irc *irc; diff --git a/root_commands.c b/root_commands.c index 225912b7..d263bb84 100644 --- a/root_commands.c +++ b/root_commands.c @@ -306,7 +306,7 @@ static void cmd_account( irc_t *irc, char **cmd ) irc_usermsg( irc, "Trying to get all accounts connected..." ); for( a = irc->accounts; a; a = a->next ) - if( !a->gc ) + if( !a->gc && a->auto_connect ) account_on( irc, a ); } else diff --git a/storage_xml.c b/storage_xml.c index 737f2091..69e991d2 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -125,12 +125,13 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else if( g_strcasecmp( element_name, "account" ) == 0 ) { - char *protocol, *handle, *server, *password; + char *protocol, *handle, *server, *password, *autoconnect; struct prpl *prpl = NULL; handle = xml_attr( attr_names, attr_values, "handle" ); password = xml_attr( attr_names, attr_values, "password" ); server = xml_attr( attr_names, attr_values, "server" ); + autoconnect = xml_attr( attr_names, attr_values, "autoconnect" ); protocol = xml_attr( attr_names, attr_values, "protocol" ); if( protocol ) @@ -147,6 +148,10 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na xd->current_account = account_add( irc, prpl, handle, password ); if( server ) xd->current_account->server = g_strdup( server ); + if( autoconnect ) + /* Return value doesn't matter, since account_add() already sets + a default! */ + sscanf( autoconnect, "%d", &xd->current_account->auto_connect ); } } else if( g_strcasecmp( element_name, "setting" ) == 0 ) @@ -384,7 +389,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) for( acc = irc->accounts; acc; acc = acc->next ) { - if( !xml_printf( fd, "\tprpl->name, acc->user, acc->pass, "yes" ) ) + if( !xml_printf( fd, "\tprpl->name, acc->user, acc->pass, acc->auto_connect ) ) goto write_error; if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) goto write_error; -- cgit v1.2.3 From 00ab35016e3646aa936ae0c3d7a8531ec68d6f24 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 21 Jun 2006 19:14:49 +0200 Subject: Fixed GError memory leak, correctly setting the migrate_storage default. --- conf.c | 3 +-- storage_xml.c | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/conf.c b/conf.c index d70117f5..3154eb9c 100644 --- a/conf.c +++ b/conf.c @@ -41,7 +41,6 @@ static int conf_loadini( conf_t *conf, char *file ); conf_t *conf_load( int argc, char *argv[] ) { - char *mig_list[2] = { "text", NULL }; conf_t *conf; int opt, i; @@ -56,7 +55,7 @@ conf_t *conf_load( int argc, char *argv[] ) conf->nofork = 0; conf->verbose = 0; conf->primary_storage = "xml"; - conf->migrate_storage = mig_list; + conf->migrate_storage = g_strsplit( "text", ",", -1 ); conf->runmode = RUNMODE_INETD; conf->authmode = AUTHMODE_OPEN; conf->auth_pass = NULL; diff --git a/storage_xml.c b/storage_xml.c index 69e991d2..41a50d8c 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -287,16 +287,22 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password /* Slightly dirty... */ if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 ) + { + g_clear_error( &gerr ); return STORAGE_INVALID_PASSWORD; + } else { if( gerr && irc ) irc_usermsg( irc, "Error from XML-parser: %s", gerr->message ); + g_clear_error( &gerr ); return STORAGE_OTHER_ERROR; } } } + /* Just to be sure... */ + g_clear_error( &gerr ); g_markup_parse_context_free( ctx ); close( fd ); -- cgit v1.2.3 From 812a41362a9316da1734fdaa8b1aad36bde9cb5c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 23 Jun 2006 20:15:28 +0200 Subject: Added saner base64 encoding function (actually, moved the one from libyahoo2.c to core, with some changes), which I need for the XML format password garbling. --- protocols/yahoo/libyahoo2.c | 28 +------------- util.c | 89 +++++++++++++++++++-------------------------- util.h | 1 + 3 files changed, 41 insertions(+), 77 deletions(-) diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index c691f18b..ee0f2f0e 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -694,34 +694,10 @@ static void yahoo_packet_dump(unsigned char *data, int len) } } -static char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789._"; -static void to_y64(unsigned char *out, const unsigned char *in, int inlen) /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ +static void to_y64(unsigned char *out, const unsigned char *in, int inlen) { - for (; inlen >= 3; inlen -= 3) - { - *out++ = base64digits[in[0] >> 2]; - *out++ = base64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = base64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; - *out++ = base64digits[in[2] & 0x3f]; - in += 3; - } - if (inlen > 0) - { - unsigned char fragment; - - *out++ = base64digits[in[0] >> 2]; - fragment = (in[0] << 4) & 0x30; - if (inlen > 1) - fragment |= in[1] >> 4; - *out++ = base64digits[fragment]; - *out++ = (inlen < 2) ? '-' - : base64digits[(in[1] << 2) & 0x3c]; - *out++ = '-'; - } - *out = '\0'; + return base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"); } static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length) diff --git a/util.c b/util.c index dfa0906b..d8d6a4c7 100644 --- a/util.c +++ b/util.c @@ -83,61 +83,48 @@ char *add_cr(char *text) return ret; } -static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/"; - -/* XXX Find bug */ char *tobase64(const char *text) { - char *out = NULL; - const char *c; - unsigned int tmp = 0; - int len = 0, n = 0; - - c = text; - - while (*c) { - tmp = tmp << 8; - tmp += *c; - n++; - - if (n == 3) { - out = g_realloc(out, len + 4); - out[len] = alphabet[(tmp >> 18) & 0x3f]; - out[len + 1] = alphabet[(tmp >> 12) & 0x3f]; - out[len + 2] = alphabet[(tmp >> 6) & 0x3f]; - out[len + 3] = alphabet[tmp & 0x3f]; - len += 4; - tmp = 0; - n = 0; - } - c++; + char *out; + int len; + + len = strlen(text); + out = g_malloc((len + 2) /* the == padding */ + / 3 /* every 3-byte block */ + * 4 /* becomes a 4-byte one */ + + 1); /* and of course, ASCIIZ! */ + + base64_encode_real(text, len, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); + + return out; +} + +void base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, char *b64digits) +{ + for (; inlen >= 3; inlen -= 3) + { + *out++ = b64digits[in[0] >> 2]; + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; + *out++ = b64digits[in[2] & 0x3f]; + in += 3; } - switch (n) { - - case 2: - tmp <<= 8; - out = g_realloc(out, len + 5); - out[len] = alphabet[(tmp >> 18) & 0x3f]; - out[len + 1] = alphabet[(tmp >> 12) & 0x3f]; - out[len + 2] = alphabet[(tmp >> 6) & 0x3f]; - out[len + 3] = '='; - out[len + 4] = 0; - break; - case 1: - tmp <<= 16; - out = g_realloc(out, len + 5); - out[len] = alphabet[(tmp >> 18) & 0x3f]; - out[len + 1] = alphabet[(tmp >> 12) & 0x3f]; - out[len + 2] = '='; - out[len + 3] = '='; - out[len + 4] = 0; - break; - case 0: - out = g_realloc(out, len + 1); - out[len] = 0; - break; + if (inlen > 0) + { + *out++ = b64digits[in[0] >> 2]; + if (inlen > 1) + { + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[((in[1]<<2) & 0x3c)]; + } + else + { + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[64]; + } + *out++ = b64digits[64]; } - return out; + *out = '\0'; } char *normalize(const char *s) diff --git a/util.h b/util.h index 8e13d9dd..c7eec19b 100644 --- a/util.h +++ b/util.h @@ -30,6 +30,7 @@ G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); G_MODULE_EXPORT char *tobase64( const char *text ); +G_MODULE_EXPORT void base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, char *b64digits ); G_MODULE_EXPORT char *normalize( const char *s ); G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); -- cgit v1.2.3 From df1694b9559d4abec748b0506b5f44e684d022a8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 14:15:42 +0200 Subject: Moving all generic files to lib/ instead of having some in / and some in protocols/, and adding RC4 code. --- Makefile | 4 +- bitlbee.h | 2 +- conf.c | 2 +- configure | 2 +- ini.c | 90 ------- ini.h | 43 ---- irc_commands.c | 2 +- lib/Makefile | 37 +++ lib/events.h | 66 ++++++ lib/events_glib.c | 137 +++++++++++ lib/events_libevent.c | 247 ++++++++++++++++++++ lib/http_client.c | 453 ++++++++++++++++++++++++++++++++++++ lib/http_client.h | 57 +++++ lib/ini.c | 90 +++++++ lib/ini.h | 43 ++++ lib/md5.c | 392 +++++++++++++++++++++++++++++++ lib/md5.h | 85 +++++++ lib/misc.c | 481 ++++++++++++++++++++++++++++++++++++++ lib/misc.h | 51 ++++ lib/proxy.c | 556 ++++++++++++++++++++++++++++++++++++++++++++ lib/proxy.h | 53 +++++ lib/rc4.c | 179 ++++++++++++++ lib/rc4.h | 35 +++ lib/sha.c | 173 ++++++++++++++ lib/sha.h | 21 ++ lib/ssl_bogus.c | 57 +++++ lib/ssl_client.h | 42 ++++ lib/ssl_gnutls.c | 206 ++++++++++++++++ lib/ssl_nss.c | 190 +++++++++++++++ lib/ssl_openssl.c | 221 ++++++++++++++++++ lib/url.c | 107 +++++++++ lib/url.h | 44 ++++ protocols/Makefile | 2 +- protocols/events.h | 66 ------ protocols/events_glib.c | 137 ----------- protocols/events_libevent.c | 247 -------------------- protocols/http_client.c | 453 ------------------------------------ protocols/http_client.h | 57 ----- protocols/md5.c | 392 ------------------------------- protocols/md5.h | 85 ------- protocols/proxy.c | 556 -------------------------------------------- protocols/proxy.h | 53 ----- protocols/sha.c | 173 -------------- protocols/sha.h | 21 -- protocols/ssl_bogus.c | 57 ----- protocols/ssl_client.h | 42 ---- protocols/ssl_gnutls.c | 206 ---------------- protocols/ssl_nss.c | 190 --------------- protocols/ssl_openssl.c | 221 ------------------ url.c | 107 --------- url.h | 44 ---- util.c | 481 -------------------------------------- util.h | 51 ---- 53 files changed, 4030 insertions(+), 3779 deletions(-) delete mode 100644 ini.c delete mode 100644 ini.h create mode 100644 lib/Makefile create mode 100644 lib/events.h create mode 100644 lib/events_glib.c create mode 100644 lib/events_libevent.c create mode 100644 lib/http_client.c create mode 100644 lib/http_client.h create mode 100644 lib/ini.c create mode 100644 lib/ini.h create mode 100644 lib/md5.c create mode 100644 lib/md5.h create mode 100644 lib/misc.c create mode 100644 lib/misc.h create mode 100644 lib/proxy.c create mode 100644 lib/proxy.h create mode 100644 lib/rc4.c create mode 100644 lib/rc4.h create mode 100644 lib/sha.c create mode 100644 lib/sha.h create mode 100644 lib/ssl_bogus.c create mode 100644 lib/ssl_client.h create mode 100644 lib/ssl_gnutls.c create mode 100644 lib/ssl_nss.c create mode 100644 lib/ssl_openssl.c create mode 100644 lib/url.c create mode 100644 lib/url.h delete mode 100644 protocols/events.h delete mode 100644 protocols/events_glib.c delete mode 100644 protocols/events_libevent.c delete mode 100644 protocols/http_client.c delete mode 100644 protocols/http_client.h delete mode 100644 protocols/md5.c delete mode 100644 protocols/md5.h delete mode 100644 protocols/proxy.c delete mode 100644 protocols/proxy.h delete mode 100644 protocols/sha.c delete mode 100644 protocols/sha.h delete mode 100644 protocols/ssl_bogus.c delete mode 100644 protocols/ssl_client.h delete mode 100644 protocols/ssl_gnutls.c delete mode 100644 protocols/ssl_nss.c delete mode 100644 protocols/ssl_openssl.c delete mode 100644 url.c delete mode 100644 url.h delete mode 100644 util.c delete mode 100644 util.h diff --git a/Makefile b/Makefile index af710d59..73fee984 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,9 @@ -include Makefile.settings # Program variables -objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o storage_xml.o unix.o url.o user.o util.o +objects = 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_text.o storage_xml.o unix.o user.o headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h -subdirs = protocols +subdirs = protocols lib objects += $(LDAP_OBJ) diff --git a/bitlbee.h b/bitlbee.h index 709856d8..1462316f 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -129,7 +129,7 @@ extern char *CONF_FILE; #include "help.h" #include "query.h" #include "sock.h" -#include "util.h" +#include "misc.h" #include "proxy.h" typedef struct global { diff --git a/conf.c b/conf.c index 3154eb9c..d8b8be72 100644 --- a/conf.c +++ b/conf.c @@ -33,7 +33,7 @@ #include "url.h" #include "ipc.h" -#include "protocols/proxy.h" +#include "proxy.h" char *CONF_FILE; diff --git a/configure b/configure index 05fb7cb4..3a333029 100755 --- a/configure +++ b/configure @@ -143,7 +143,7 @@ else echo 'CFLAGS=-O3' >> Makefile.settings fi -echo CFLAGS+=-I`pwd` -I`pwd`/protocols -I. >> Makefile.settings +echo CFLAGS+=-I`pwd` -I`pwd`/lib -I`pwd`/protocols -I. >> Makefile.settings echo CFLAGS+=-DHAVE_CONFIG_H >> Makefile.settings diff --git a/ini.c b/ini.c deleted file mode 100644 index c63a132e..00000000 --- a/ini.c +++ /dev/null @@ -1,90 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2005 Wilmer van der Gaast and others * - \********************************************************************/ - -/* INI file reading code */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ -#define BITLBEE_CORE -#include "bitlbee.h" - -ini_t *ini_open( char *file ) -{ - ini_t *ini = g_new0( ini_t, 1 ); - - if( ( ini->fp = fopen( file, "r" ) ) == NULL ) - { - g_free( ini ); - return( NULL ); - } - - return( ini ); -} - -int ini_read( ini_t *file ) -{ - char key[MAX_STRING], s[MAX_STRING], *t; - int i; - - while( !feof( file->fp ) ) - { - *s = 0; - fscanf( file->fp, "%127[^\n#]s", s ); - fscanf( file->fp, "%*[^\n]s" ); - fgetc( file->fp ); /* Skip newline */ - file->line ++; - if( strchr( s, '=' ) ) - { - sscanf( s, "%[^ =]s", key ); - if( ( t = strchr( key, '.' ) ) ) - { - *t = 0; - strcpy( file->section, key ); - t ++; - } - else - { - strcpy( file->section, file->c_section ); - t = key; - } - sscanf( t, "%s", file->key ); - t = strchr( s, '=' ) + 1; - for( i = 0; t[i] == ' '; i ++ ); - strcpy( file->value, &t[i] ); - for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- ) - file->value[i] = 0; - - return( 1 ); - } - else if( ( t = strchr( s, '[' ) ) ) - { - strcpy( file->c_section, t + 1 ); - t = strchr( file->c_section, ']' ); - *t = 0; - } - } - return( 0 ); -} - -void ini_close( ini_t *file ) -{ - fclose( file->fp ); - g_free( file ); -} diff --git a/ini.h b/ini.h deleted file mode 100644 index 5eab472b..00000000 --- a/ini.h +++ /dev/null @@ -1,43 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* INI file reading code */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _INI_H -#define _INI_H - -typedef struct -{ - FILE *fp; - int line; - char c_section[MAX_STRING]; - char section[MAX_STRING]; - char key[MAX_STRING]; - char value[MAX_STRING]; -} ini_t; - -ini_t *ini_open( char *file ); -int ini_read( ini_t *file ); -void ini_close( ini_t *file ); - -#endif diff --git a/irc_commands.c b/irc_commands.c index f410bb52..3bb24fdb 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -320,7 +320,7 @@ static void irc_cmd_userhost( irc_t *irc, char **cmd ) static void irc_cmd_ison( irc_t *irc, char **cmd ) { user_t *u; - char buff[IRC_MAX_LINE], *s; + char buff[IRC_MAX_LINE]; int lenleft, i; buff[0] = '\0'; diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 00000000..80cdd9a5 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,37 @@ +########################### +## Makefile for BitlBee ## +## ## +## Copyright 2006 Lintux ## +########################### + +### DEFINITIONS + +-include ../Makefile.settings + +# [SH] Program variables +objects = $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o + +CFLAGS += -Wall +LFLAGS += -r + +# [SH] Phony targets +all: lib.o + +.PHONY: all clean distclean + +clean: $(subdirs) + rm -f *.o $(OUTFILE) core + +distclean: clean $(subdirs) + +### MAIN PROGRAM + +lib.o: $(objects) $(subdirs) + @echo '*' Linking lib.o + @$(LD) $(LFLAGS) $(objects) -o lib.o + +$(objects): ../Makefile.settings Makefile + +$(objects): %.o: %.c + @echo '*' Compiling $< + @$(CC) -c $(CFLAGS) $< -o $@ diff --git a/lib/events.h b/lib/events.h new file mode 100644 index 00000000..781fca6a --- /dev/null +++ b/lib/events.h @@ -0,0 +1,66 @@ +/* + * nogaim + * + * Copyright (C) 2006 Wilmer van der Gaast and others + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* + * Split off the event handling things from proxy.[ch] (and adding timer + * stuff. This to allow BitlBee to use other libs than GLib for event + * handling. + */ + + +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#include +#ifndef _WIN32 +#include +#include +#include +#endif +#include +#include + +typedef enum { + GAIM_INPUT_READ = 1 << 1, + GAIM_INPUT_WRITE = 1 << 2 +} b_input_condition; +typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); + +#define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) +#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) +#define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) + +// #define event_debug( x... ) printf( x ) +#define event_debug( x... ) + +G_MODULE_EXPORT void b_main_init(); +G_MODULE_EXPORT void b_main_run(); +G_MODULE_EXPORT void b_main_quit(); + +G_MODULE_EXPORT gint b_input_add(int fd, b_input_condition cond, b_event_handler func, gpointer data); +G_MODULE_EXPORT gint b_timeout_add(gint timeout, b_event_handler func, gpointer data); +G_MODULE_EXPORT void b_event_remove(gint id); + +#ifdef EVENTS_LIBEVENT +G_MODULE_EXPORT void closesocket(int fd); +#endif + +#endif /* _EVENTS_H_ */ diff --git a/lib/events_glib.c b/lib/events_glib.c new file mode 100644 index 00000000..620720cd --- /dev/null +++ b/lib/events_glib.c @@ -0,0 +1,137 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Event handling (using GLib) + */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#define BITLBEE_CORE +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#else +#include "sock.h" +#define ETIMEDOUT WSAETIMEDOUT +#define EINPROGRESS WSAEINPROGRESS +#endif +#include +#include +#include "proxy.h" + +typedef struct _GaimIOClosure { + b_event_handler function; + guint result; + gpointer data; +} GaimIOClosure; + +static GMainLoop *loop; + +void b_main_init() +{ + loop = g_main_new( FALSE ); +} + +void b_main_run() +{ + g_main_run( loop ); +} + +void b_main_quit() +{ + g_main_quit( loop ); +} + +static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) +{ + GaimIOClosure *closure = data; + b_input_condition gaim_cond = 0; + gboolean st; + + if (condition & GAIM_READ_COND) + gaim_cond |= GAIM_INPUT_READ; + if (condition & GAIM_WRITE_COND) + gaim_cond |= GAIM_INPUT_WRITE; + + event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data ); + + st = closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); + + if( !st ) + event_debug( "Returned FALSE, cancelling.\n" ); + + return st; +} + +static void gaim_io_destroy(gpointer data) +{ + event_debug( "gaim_io_destroy( 0x%x )\n", data ); + g_free(data); +} + +gint b_input_add(gint source, b_input_condition condition, b_event_handler function, gpointer data) +{ + GaimIOClosure *closure = g_new0(GaimIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = 0; + + closure->function = function; + closure->data = data; + + if (condition & GAIM_INPUT_READ) + cond |= GAIM_READ_COND; + if (condition & GAIM_INPUT_WRITE) + cond |= GAIM_WRITE_COND; + + channel = g_io_channel_unix_new(source); + closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + gaim_io_invoke, closure, gaim_io_destroy); + + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (0x%x)\n", source, condition, function, data, closure->result, closure ); + + g_io_channel_unref(channel); + return closure->result; +} + +gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) +{ + gint st = g_timeout_add(timeout, func, data); + + event_debug( "b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st ); + + return st; +} + +void b_event_remove(gint tag) +{ + event_debug( "b_event_remove( %d )\n", tag ); + + if (tag > 0) + g_source_remove(tag); +} diff --git a/lib/events_libevent.c b/lib/events_libevent.c new file mode 100644 index 00000000..1119c2ab --- /dev/null +++ b/lib/events_libevent.c @@ -0,0 +1,247 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2006 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Event handling (using libevent) + */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#define BITLBEE_CORE +#include +#include +#include +#include +#include +#include "proxy.h" + +#include +#include + +static guint id_next; +static GHashTable *id_hash; +static int quitting = 0; + +/* Since libevent doesn't handle two event handlers for one fd-condition + very well (which happens sometimes when BitlBee changes event handlers + for a combination), let's buid some indexes so we can delete them here + already, just in time. */ +static GHashTable *read_hash; +static GHashTable *write_hash; + +struct b_event_data +{ + guint id; + struct event evinfo; + gint timeout; + b_event_handler function; + void *data; +}; + +void b_main_init() +{ + event_init(); + + id_next = 1; + id_hash = g_hash_table_new( g_int_hash, g_int_equal ); + read_hash = g_hash_table_new( g_int_hash, g_int_equal ); + write_hash = g_hash_table_new( g_int_hash, g_int_equal ); +} + +void b_main_run() +{ + event_dispatch(); +} + +void b_main_quit() +{ + struct timeval tv; + + /* libevent sometimes generates events before really quitting, + we want to stop them. */ + quitting = 1; + + memset( &tv, 0, sizeof( struct timeval ) ); + event_loopexit( &tv ); +} + +static void b_event_passthrough( int fd, short event, void *data ) +{ + struct b_event_data *b_ev = data; + b_input_condition cond = 0; + int id; + + if( fd >= 0 ) + { + if( event & EV_READ ) + cond |= GAIM_INPUT_READ; + if( event & EV_WRITE ) + cond |= GAIM_INPUT_WRITE; + } + + event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); + + /* Since the called function might cancel this handler already + (which free()s b_ev, we have to remember the ID here. */ + id = b_ev->id; + + if( quitting ) + { + b_event_remove( id ); + return; + } + + if( !b_ev->function( b_ev->data, fd, cond ) ) + { + event_debug( "Handler returned FALSE: " ); + b_event_remove( id ); + } + else if( fd == -1 ) + { + struct timeval tv; + + tv.tv_sec = b_ev->timeout / 1000; + tv.tv_usec = ( b_ev->timeout % 1000 ) * 1000; + + evtimer_add( &b_ev->evinfo, &tv ); + } +} + +gint b_input_add( gint fd, b_input_condition condition, b_event_handler function, gpointer data ) +{ + struct b_event_data *b_ev; + + event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data ); + + if( ( condition & GAIM_INPUT_READ && ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) || + ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) ) + { + /* We'll stick with this libevent entry, but give it a new BitlBee id. */ + g_hash_table_remove( id_hash, &b_ev->id ); + + event_debug( "(replacing old handler (id = %d)) = %d\n", b_ev->id, id_next ); + + b_ev->id = id_next++; + b_ev->function = function; + b_ev->data = data; + } + else + { + GIOCondition out_cond; + + event_debug( "(new) = %d\n", id_next ); + + b_ev = g_new0( struct b_event_data, 1 ); + b_ev->id = id_next++; + b_ev->function = function; + b_ev->data = data; + + out_cond = EV_PERSIST; + if( condition & GAIM_INPUT_READ ) + out_cond |= EV_READ; + if( condition & GAIM_INPUT_WRITE ) + out_cond |= EV_WRITE; + + event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev ); + event_add( &b_ev->evinfo, NULL ); + + if( out_cond & EV_READ ) + g_hash_table_insert( read_hash, &b_ev->evinfo.ev_fd, b_ev ); + if( out_cond & EV_WRITE ) + g_hash_table_insert( write_hash, &b_ev->evinfo.ev_fd, b_ev ); + } + + g_hash_table_insert( id_hash, &b_ev->id, b_ev ); + return b_ev->id; +} + +/* TODO: Persistence for timers! */ +gint b_timeout_add( gint timeout, b_event_handler function, gpointer data ) +{ + struct b_event_data *b_ev = g_new0( struct b_event_data, 1 ); + struct timeval tv; + + b_ev->id = id_next++; + b_ev->timeout = timeout; + b_ev->function = function; + b_ev->data = data; + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + evtimer_set( &b_ev->evinfo, b_event_passthrough, b_ev ); + evtimer_add( &b_ev->evinfo, &tv ); + + event_debug( "b_timeout_add( %d, 0x%x, 0x%x ) = %d\n", timeout, function, data, b_ev->id ); + + g_hash_table_insert( id_hash, &b_ev->id, b_ev ); + + return b_ev->id; +} + +void b_event_remove( gint id ) +{ + struct b_event_data *b_ev = g_hash_table_lookup( id_hash, &id ); + + event_debug( "b_event_remove( %d )\n", id ); + if( b_ev ) + { + g_hash_table_remove( id_hash, &b_ev->id ); + if( b_ev->evinfo.ev_fd >= 0 ) + { + if( b_ev->evinfo.ev_events & EV_READ ) + g_hash_table_remove( read_hash, &b_ev->evinfo.ev_fd ); + if( b_ev->evinfo.ev_events & EV_WRITE ) + g_hash_table_remove( write_hash, &b_ev->evinfo.ev_fd ); + } + + event_del( &b_ev->evinfo ); + g_free( b_ev ); + } + else + { + event_debug( "Already removed?\n" ); + } +} + +void closesocket( int fd ) +{ + struct b_event_data *b_ev; + + /* Since epoll() (the main reason we use libevent) automatically removes sockets from + the epoll() list when a socket gets closed and some modules have a habit of + closing sockets before removing event handlers, our and libevent's administration + get a little bit messed up. So this little function will remove the handlers + properly before closing a socket. */ + + if( ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) + { + event_debug( "Warning: fd %d still had a read event handler when shutting down.\n", fd ); + b_event_remove( b_ev->id ); + } + if( ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) + { + event_debug( "Warning: fd %d still had a write event handler when shutting down.\n", fd ); + b_event_remove( b_ev->id ); + } + + close( fd ); +} diff --git a/lib/http_client.c b/lib/http_client.c new file mode 100644 index 00000000..b00fcf98 --- /dev/null +++ b/lib/http_client.c @@ -0,0 +1,453 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* HTTP(S) module */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include + +#include "http_client.h" +#include "url.h" +#include "sock.h" + + +static gboolean http_connected( gpointer data, int source, b_input_condition cond ); +static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ); +static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ); + + +void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) +{ + struct http_request *req; + int error = 0; + + req = g_new0( struct http_request, 1 ); + + if( ssl ) + { + req->ssl = ssl_connect( host, port, http_ssl_connected, req ); + if( req->ssl == NULL ) + error = 1; + } + else + { + req->fd = proxy_connect( host, port, http_connected, req ); + if( req->fd < 0 ) + error = 1; + } + + if( error ) + { + g_free( req ); + return( NULL ); + } + + req->func = func; + req->data = data; + req->request = g_strdup( request ); + req->request_length = strlen( request ); + + return( req ); +} + +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) +{ + url_t *url = g_new0( url_t, 1 ); + char *request; + void *ret; + + if( !url_set( url, url_string ) ) + { + g_free( url ); + return NULL; + } + + if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) + { + g_free( url ); + return NULL; + } + + request = g_strdup_printf( "GET %s HTTP/1.0\r\n" + "Host: %s\r\n" + "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" + "\r\n", url->file, url->host ); + + ret = http_dorequest( url->host, url->port, + url->proto == PROTO_HTTPS, request, func, data ); + + g_free( url ); + g_free( request ); + return ret; +} + +/* This one is actually pretty simple... Might get more calls if we can't write + the whole request at once. */ +static gboolean http_connected( gpointer data, int source, b_input_condition cond ) +{ + struct http_request *req = data; + int st; + + if( source < 0 ) + goto error; + + if( req->inpa > 0 ) + b_event_remove( req->inpa ); + + sock_make_nonblocking( req->fd ); + + if( req->ssl ) + { + st = ssl_write( req->ssl, req->request + req->bytes_written, + req->request_length - req->bytes_written ); + if( st < 0 ) + { + if( ssl_errno != SSL_AGAIN ) + { + ssl_disconnect( req->ssl ); + goto error; + } + } + } + else + { + st = write( source, req->request + req->bytes_written, + req->request_length - req->bytes_written ); + if( st < 0 ) + { + if( !sockerr_again() ) + { + closesocket( req->fd ); + goto error; + } + } + } + + if( st > 0 ) + req->bytes_written += st; + + if( req->bytes_written < req->request_length ) + req->inpa = b_input_add( source, + req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, + http_connected, req ); + else + req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); + + return FALSE; + +error: + req->status_string = g_strdup( "Error while writing HTTP request" ); + + req->func( req ); + + g_free( req->request ); + g_free( req ); + + return FALSE; +} + +static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ) +{ + struct http_request *req = data; + + if( source == NULL ) + return http_connected( data, -1, cond ); + + req->fd = ssl_getfd( source ); + + return http_connected( data, req->fd, cond ); +} + +static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) +{ + struct http_request *req = data; + int evil_server = 0; + char buffer[2048]; + char *end1, *end2; + int st; + + if( req->inpa > 0 ) + b_event_remove( req->inpa ); + + if( req->ssl ) + { + st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); + if( st < 0 ) + { + if( ssl_errno != SSL_AGAIN ) + { + /* goto cleanup; */ + + /* YAY! We have to deal with crappy Microsoft + servers that LOVE to send invalid TLS + packets that abort connections! \o/ */ + + goto got_reply; + } + } + else if( st == 0 ) + { + goto got_reply; + } + } + else + { + st = read( req->fd, buffer, sizeof( buffer ) ); + if( st < 0 ) + { + if( !sockerr_again() ) + { + req->status_string = g_strdup( strerror( errno ) ); + goto cleanup; + } + } + else if( st == 0 ) + { + goto got_reply; + } + } + + if( st > 0 ) + { + req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); + memcpy( req->reply_headers + req->bytes_read, buffer, st ); + req->bytes_read += st; + } + + /* There will be more! */ + req->inpa = b_input_add( req->fd, + req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, + http_incoming_data, req ); + + return FALSE; + +got_reply: + /* Maybe if the webserver is overloaded, or when there's bad SSL + support... */ + if( req->bytes_read == 0 ) + { + req->status_string = g_strdup( "Empty HTTP reply" ); + goto cleanup; + } + + /* Zero termination is very convenient. */ + req->reply_headers[req->bytes_read] = 0; + + /* Find the separation between headers and body, and keep stupid + webservers in mind. */ + end1 = strstr( req->reply_headers, "\r\n\r\n" ); + end2 = strstr( req->reply_headers, "\n\n" ); + + if( end2 && end2 < end1 ) + { + end1 = end2 + 1; + evil_server = 1; + } + else if( end1 ) + { + end1 += 2; + } + else + { + req->status_string = g_strdup( "Malformed HTTP reply" ); + goto cleanup; + } + + *end1 = 0; + + if( evil_server ) + req->reply_body = end1 + 1; + else + req->reply_body = end1 + 2; + + req->body_size = req->reply_headers + req->bytes_read - req->reply_body; + + if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) + { + if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) + { + req->status_string = g_strdup( "Can't parse status code" ); + req->status_code = -1; + } + else + { + char *eol; + + if( evil_server ) + eol = strchr( end1, '\n' ); + else + eol = strchr( end1, '\r' ); + + req->status_string = g_strndup( end1 + 1, eol - end1 - 1 ); + + /* Just to be sure... */ + if( ( eol = strchr( req->status_string, '\r' ) ) ) + *eol = 0; + if( ( eol = strchr( req->status_string, '\n' ) ) ) + *eol = 0; + } + } + else + { + req->status_string = g_strdup( "Can't locate status code" ); + req->status_code = -1; + } + + if( req->status_code == 301 || req->status_code == 302 ) + { + char *loc, *new_request, *new_host; + int error = 0, new_port, new_proto; + + /* We might fill it again, so let's not leak any memory. */ + g_free( req->status_string ); + req->status_string = NULL; + + loc = strstr( req->reply_headers, "\nLocation: " ); + if( loc == NULL ) /* We can't handle this redirect... */ + { + req->status_string = g_strdup( "Can't locate Location: header" ); + goto cleanup; + } + + loc += 11; + while( *loc == ' ' ) + loc ++; + + /* TODO/FIXME: Possibly have to handle relative redirections, + and rewrite Host: headers. Not necessary for now, it's + enough for passport authentication like this. */ + + if( *loc == '/' ) + { + /* Just a different pathname... */ + + /* Since we don't cache the servername, and since we + don't need this yet anyway, I won't implement it. */ + + req->status_string = g_strdup( "Can't handle recursive redirects" ); + + goto cleanup; + } + else + { + /* A whole URL */ + url_t *url; + char *s; + + s = strstr( loc, "\r\n" ); + if( s == NULL ) + goto cleanup; + + url = g_new0( url_t, 1 ); + *s = 0; + + if( !url_set( url, loc ) ) + { + req->status_string = g_strdup( "Malformed redirect URL" ); + g_free( url ); + goto cleanup; + } + + /* Okay, this isn't fun! We have to rebuild the request... :-( */ + new_request = g_malloc( req->request_length + strlen( url->file ) ); + + /* So, now I just allocated enough memory, so I'm + going to use strcat(), whether you like it or not. :-) */ + + sprintf( new_request, "GET %s HTTP/1.0", url->file ); + + s = strstr( req->request, "\r\n" ); + if( s == NULL ) + { + req->status_string = g_strdup( "Error while rebuilding request string" ); + g_free( new_request ); + g_free( url ); + goto cleanup; + } + + strcat( new_request, s ); + new_host = g_strdup( url->host ); + new_port = url->port; + new_proto = url->proto; + + g_free( url ); + } + + if( req->ssl ) + ssl_disconnect( req->ssl ); + else + closesocket( req->fd ); + + req->fd = -1; + req->ssl = NULL; + + if( new_proto == PROTO_HTTPS ) + { + req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req ); + if( req->ssl == NULL ) + error = 1; + } + else + { + req->fd = proxy_connect( new_host, new_port, http_connected, req ); + if( req->fd < 0 ) + error = 1; + } + g_free( new_host ); + + if( error ) + { + req->status_string = g_strdup( "Connection problem during redirect" ); + g_free( new_request ); + goto cleanup; + } + + g_free( req->request ); + g_free( req->reply_headers ); + req->request = new_request; + req->request_length = strlen( new_request ); + req->bytes_read = req->bytes_written = req->inpa = 0; + req->reply_headers = req->reply_body = NULL; + + return FALSE; + } + + /* Assume that a closed connection means we're finished, this indeed + breaks with keep-alive connections and faulty connections. */ + req->finished = 1; + +cleanup: + if( req->ssl ) + ssl_disconnect( req->ssl ); + else + closesocket( req->fd ); + + req->func( req ); + + g_free( req->request ); + g_free( req->reply_headers ); + g_free( req->status_string ); + g_free( req ); + + return FALSE; +} diff --git a/lib/http_client.h b/lib/http_client.h new file mode 100644 index 00000000..50ee80cf --- /dev/null +++ b/lib/http_client.h @@ -0,0 +1,57 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* HTTP(S) module */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include + +#include "ssl_client.h" + +struct http_request; + +typedef void (*http_input_function)( struct http_request * ); + +struct http_request +{ + char *request; + int request_length; + int status_code; + char *status_string; + char *reply_headers; + char *reply_body; + int body_size; + int finished; + + void *ssl; + int fd; + + int inpa; + int bytes_written; + int bytes_read; + + http_input_function func; + gpointer data; +}; + +void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); +void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/lib/ini.c b/lib/ini.c new file mode 100644 index 00000000..c63a132e --- /dev/null +++ b/lib/ini.c @@ -0,0 +1,90 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* INI file reading code */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ +#define BITLBEE_CORE +#include "bitlbee.h" + +ini_t *ini_open( char *file ) +{ + ini_t *ini = g_new0( ini_t, 1 ); + + if( ( ini->fp = fopen( file, "r" ) ) == NULL ) + { + g_free( ini ); + return( NULL ); + } + + return( ini ); +} + +int ini_read( ini_t *file ) +{ + char key[MAX_STRING], s[MAX_STRING], *t; + int i; + + while( !feof( file->fp ) ) + { + *s = 0; + fscanf( file->fp, "%127[^\n#]s", s ); + fscanf( file->fp, "%*[^\n]s" ); + fgetc( file->fp ); /* Skip newline */ + file->line ++; + if( strchr( s, '=' ) ) + { + sscanf( s, "%[^ =]s", key ); + if( ( t = strchr( key, '.' ) ) ) + { + *t = 0; + strcpy( file->section, key ); + t ++; + } + else + { + strcpy( file->section, file->c_section ); + t = key; + } + sscanf( t, "%s", file->key ); + t = strchr( s, '=' ) + 1; + for( i = 0; t[i] == ' '; i ++ ); + strcpy( file->value, &t[i] ); + for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- ) + file->value[i] = 0; + + return( 1 ); + } + else if( ( t = strchr( s, '[' ) ) ) + { + strcpy( file->c_section, t + 1 ); + t = strchr( file->c_section, ']' ); + *t = 0; + } + } + return( 0 ); +} + +void ini_close( ini_t *file ) +{ + fclose( file->fp ); + g_free( file ); +} diff --git a/lib/ini.h b/lib/ini.h new file mode 100644 index 00000000..5eab472b --- /dev/null +++ b/lib/ini.h @@ -0,0 +1,43 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* INI file reading code */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _INI_H +#define _INI_H + +typedef struct +{ + FILE *fp; + int line; + char c_section[MAX_STRING]; + char section[MAX_STRING]; + char key[MAX_STRING]; + char value[MAX_STRING]; +} ini_t; + +ini_t *ini_open( char *file ); +int ini_read( ini_t *file ); +void ini_close( ini_t *file ); + +#endif diff --git a/lib/md5.c b/lib/md5.c new file mode 100644 index 00000000..e6273585 --- /dev/null +++ b/lib/md5.c @@ -0,0 +1,392 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include + +#ifdef TEST +/* + * Compile with -DTEST to create a self-contained executable test program. + * The test program should print out the same values as given in section + * A.5 of RFC 1321, reproduced below. + */ +#include +main() +{ + static const char *const test[7] = { + "", /*d41d8cd98f00b204e9800998ecf8427e*/ + "945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/ + "abc", /*900150983cd24fb0d6963f7d28e17f72*/ + "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ + "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + /*d174ab98d277d9f5a5611c2c9f419d9f*/ + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ + }; + int i; + + for (i = 0; i < 7; ++i) { + md5_state_t state; + md5_byte_t digest[16]; + int di; + + md5_init(&state); + md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); + md5_finish(&state, digest); + printf("MD5 (\"%s\") = ", test[i]); + for (di = 0; di < 16; ++di) + printf("%02x", digest[di]); + printf("\n"); + } + return 0; +} +#endif /* TEST */ + + +/* + * For reference, here is the program that computed the T values. + */ +#if 0 +#include +main() +{ + int i; + for (i = 1; i <= 64; ++i) { + unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); + printf("#define T%d 0x%08lx\n", i, v); + } + return 0; +} +#endif +/* + * End of T computation program. + */ +#define T1 0xd76aa478 +#define T2 0xe8c7b756 +#define T3 0x242070db +#define T4 0xc1bdceee +#define T5 0xf57c0faf +#define T6 0x4787c62a +#define T7 0xa8304613 +#define T8 0xfd469501 +#define T9 0x698098d8 +#define T10 0x8b44f7af +#define T11 0xffff5bb1 +#define T12 0x895cd7be +#define T13 0x6b901122 +#define T14 0xfd987193 +#define T15 0xa679438e +#define T16 0x49b40821 +#define T17 0xf61e2562 +#define T18 0xc040b340 +#define T19 0x265e5a51 +#define T20 0xe9b6c7aa +#define T21 0xd62f105d +#define T22 0x02441453 +#define T23 0xd8a1e681 +#define T24 0xe7d3fbc8 +#define T25 0x21e1cde6 +#define T26 0xc33707d6 +#define T27 0xf4d50d87 +#define T28 0x455a14ed +#define T29 0xa9e3e905 +#define T30 0xfcefa3f8 +#define T31 0x676f02d9 +#define T32 0x8d2a4c8a +#define T33 0xfffa3942 +#define T34 0x8771f681 +#define T35 0x6d9d6122 +#define T36 0xfde5380c +#define T37 0xa4beea44 +#define T38 0x4bdecfa9 +#define T39 0xf6bb4b60 +#define T40 0xbebfbc70 +#define T41 0x289b7ec6 +#define T42 0xeaa127fa +#define T43 0xd4ef3085 +#define T44 0x04881d05 +#define T45 0xd9d4d039 +#define T46 0xe6db99e5 +#define T47 0x1fa27cf8 +#define T48 0xc4ac5665 +#define T49 0xf4292244 +#define T50 0x432aff97 +#define T51 0xab9423a7 +#define T52 0xfc93a039 +#define T53 0x655b59c3 +#define T54 0x8f0ccc92 +#define T55 0xffeff47d +#define T56 0x85845dd1 +#define T57 0x6fa87e4f +#define T58 0xfe2ce6e0 +#define T59 0xa3014314 +#define T60 0x4e0811a1 +#define T61 0xf7537e82 +#define T62 0xbd3af235 +#define T63 0x2ad7d2bb +#define T64 0xeb86d391 + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + +#ifndef ARCH_IS_BIG_ENDIAN +# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ +#endif +#if ARCH_IS_BIG_ENDIAN + + /* + * On big-endian machines, we must arrange the bytes in the right + * order. (This also works on machines of unknown byte order.) + */ + md5_word_t X[16]; + const md5_byte_t *xp = data; + int i; + + for (i = 0; i < 16; ++i, xp += 4) + X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + +#else /* !ARCH_IS_BIG_ENDIAN */ + + /* + * On little-endian machines, we can process properly aligned data + * without copying it. + */ + md5_word_t xbuf[16]; + const md5_word_t *X; + + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } +#endif + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = 0xefcdab89; + pms->abcd[2] = 0x98badcfe; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/lib/md5.h b/lib/md5.h new file mode 100644 index 00000000..f24f2ff1 --- /dev/null +++ b/lib/md5.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 1999 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2004-03-09 Jelmer Vernooij add G_MODULE_EXPORT for Bitlbee + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +#include +#include + +/* + * This code has some adaptations for the Ghostscript environment, but it + * will compile and run correctly in any environment with 8-bit chars and + * 32-bit ints. Specifically, it assumes that if the following are + * defined, they have the same meaning as in Ghostscript: P1, P2, P3, + * ARCH_IS_BIG_ENDIAN. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +G_MODULE_EXPORT void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +G_MODULE_EXPORT void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +G_MODULE_EXPORT void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/lib/misc.c b/lib/misc.c new file mode 100644 index 00000000..d8d6a4c7 --- /dev/null +++ b/lib/misc.c @@ -0,0 +1,481 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* + * Various utility functions. Some are copied from Gaim to support the + * IM-modules, most are from BitlBee. + * + * Copyright (C) 1998-1999, Mark Spencer + * (and possibly other members of the Gaim team) + * Copyright 2002-2005 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 as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#define BITLBEE_CORE +#include "nogaim.h" +#include +#include +#include +#include +#include +#include + +void strip_linefeed(gchar *text) +{ + int i, j; + gchar *text2 = g_malloc(strlen(text) + 1); + + for (i = 0, j = 0; text[i]; i++) + if (text[i] != '\r') + text2[j++] = text[i]; + text2[j] = '\0'; + + strcpy(text, text2); + g_free(text2); +} + +char *add_cr(char *text) +{ + char *ret = NULL; + int count = 0, j; + unsigned int i; + + if (text[0] == '\n') + count++; + for (i = 1; i < strlen(text); i++) + if (text[i] == '\n' && text[i - 1] != '\r') + count++; + + if (count == 0) + return g_strdup(text); + + ret = g_malloc0(strlen(text) + count + 1); + + i = 0; j = 0; + if (text[i] == '\n') + ret[j++] = '\r'; + ret[j++] = text[i++]; + for (; i < strlen(text); i++) { + if (text[i] == '\n' && text[i - 1] != '\r') + ret[j++] = '\r'; + ret[j++] = text[i]; + } + + return ret; +} + +char *tobase64(const char *text) +{ + char *out; + int len; + + len = strlen(text); + out = g_malloc((len + 2) /* the == padding */ + / 3 /* every 3-byte block */ + * 4 /* becomes a 4-byte one */ + + 1); /* and of course, ASCIIZ! */ + + base64_encode_real(text, len, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); + + return out; +} + +void base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, char *b64digits) +{ + for (; inlen >= 3; inlen -= 3) + { + *out++ = b64digits[in[0] >> 2]; + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; + *out++ = b64digits[in[2] & 0x3f]; + in += 3; + } + if (inlen > 0) + { + *out++ = b64digits[in[0] >> 2]; + if (inlen > 1) + { + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[((in[1]<<2) & 0x3c)]; + } + else + { + *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + *out++ = b64digits[64]; + } + *out++ = b64digits[64]; + } + *out = '\0'; +} + +char *normalize(const char *s) +{ + static char buf[BUF_LEN]; + char *t, *u; + int x = 0; + + g_return_val_if_fail((s != NULL), NULL); + + u = t = g_strdup(s); + + strcpy(t, s); + g_strdown(t); + + while (*t && (x < BUF_LEN - 1)) { + if (*t != ' ') { + buf[x] = *t; + x++; + } + t++; + } + buf[x] = '\0'; + g_free(u); + return buf; +} + +time_t get_time(int year, int month, int day, int hour, int min, int sec) +{ + struct tm tm; + + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; + return mktime(&tm); +} + +typedef struct htmlentity +{ + char code[8]; + char is[4]; +} htmlentity_t; + +/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */ + +static const htmlentity_t ent[] = +{ + { "lt", "<" }, + { "gt", ">" }, + { "amp", "&" }, + { "quot", "\"" }, + { "aacute", "á" }, + { "eacute", "é" }, + { "iacute", "é" }, + { "oacute", "ó" }, + { "uacute", "ú" }, + { "agrave", "à" }, + { "egrave", "è" }, + { "igrave", "ì" }, + { "ograve", "ò" }, + { "ugrave", "ù" }, + { "acirc", "â" }, + { "ecirc", "ê" }, + { "icirc", "î" }, + { "ocirc", "ô" }, + { "ucirc", "û" }, + { "auml", "ä" }, + { "euml", "ë" }, + { "iuml", "ï" }, + { "ouml", "ö" }, + { "uuml", "ü" }, + { "nbsp", " " }, + { "", "" } +}; + +void strip_html( char *in ) +{ + char *start = in; + char *out = g_malloc( strlen( in ) + 1 ); + char *s = out, *cs; + int i, matched; + + memset( out, 0, strlen( in ) + 1 ); + + while( *in ) + { + if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) ) + { + /* If in points at a < and in+1 points at a letter or a slash, this is probably + a HTML-tag. Try to find a closing > and continue there. If the > can't be + found, assume that it wasn't a HTML-tag after all. */ + + cs = in; + + while( *in && *in != '>' ) + in ++; + + if( *in ) + { + if( g_strncasecmp( cs+1, "br", 2) == 0 ) + *(s++) = '\n'; + in ++; + } + else + { + in = cs; + *(s++) = *(in++); + } + } + else if( *in == '&' ) + { + cs = ++in; + while( *in && isalpha( *in ) ) + in ++; + + if( *in == ';' ) in ++; + matched = 0; + + for( i = 0; *ent[i].code; i ++ ) + if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 ) + { + int j; + + for( j = 0; ent[i].is[j]; j ++ ) + *(s++) = ent[i].is[j]; + + matched = 1; + break; + } + + /* None of the entities were matched, so return the string */ + if( !matched ) + { + in = cs - 1; + *(s++) = *(in++); + } + } + else + { + *(s++) = *(in++); + } + } + + strcpy( start, out ); + g_free( out ); +} + +char *escape_html( const char *html ) +{ + const char *c = html; + GString *ret; + char *str; + + if( html == NULL ) + return( NULL ); + + ret = g_string_new( "" ); + + while( *c ) + { + switch( *c ) + { + case '&': + ret = g_string_append( ret, "&" ); + break; + case '<': + ret = g_string_append( ret, "<" ); + break; + case '>': + ret = g_string_append( ret, ">" ); + break; + case '"': + ret = g_string_append( ret, """ ); + break; + default: + ret = g_string_append_c( ret, *c ); + } + c ++; + } + + str = ret->str; + g_string_free( ret, FALSE ); + return( str ); +} + +void info_string_append(GString *str, char *newline, char *name, char *value) +{ + if( value && value[0] ) + g_string_sprintfa( str, "%s%s: %s", newline, name, value ); +} + +/* Decode%20a%20file%20name */ +void http_decode( char *s ) +{ + char *t; + int i, j, k; + + t = g_new( char, strlen( s ) + 1 ); + + for( i = j = 0; s[i]; i ++, j ++ ) + { + if( s[i] == '%' ) + { + if( sscanf( s + i + 1, "%2x", &k ) ) + { + t[j] = k; + i += 2; + } + else + { + *t = 0; + break; + } + } + else + { + t[j] = s[i]; + } + } + t[j] = 0; + + strcpy( s, t ); + g_free( t ); +} + +/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */ +/* This fuction is safe, but make sure you call it safely as well! */ +void http_encode( char *s ) +{ + char *t; + int i, j; + + t = g_strdup( s ); + + for( i = j = 0; t[i]; i ++, j ++ ) + { + /* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ + if( !isalnum( t[i] ) ) + { + sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); + j += 2; + } + else + { + s[j] = t[i]; + } + } + s[j] = 0; + + g_free( t ); +} + +/* Strip newlines from a string. Modifies the string passed to it. */ +char *strip_newlines( char *source ) +{ + int i; + + for( i = 0; source[i] != '\0'; i ++ ) + if( source[i] == '\n' || source[i] == '\r' ) + source[i] = ' '; + + return source; +} + +#ifdef IPV6 +/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */ +char *ipv6_wrap( char *src ) +{ + static char dst[64]; + int i; + + for( i = 0; src[i]; i ++ ) + if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) + break; + + /* Hmm, it's not even an IP... */ + if( src[i] ) + return src; + + g_snprintf( dst, sizeof( dst ), "::ffff:%s", src ); + + return dst; +} + +/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */ +char *ipv6_unwrap( char *src ) +{ + int i; + + if( g_strncasecmp( src, "::ffff:", 7 ) != 0 ) + return src; + + for( i = 7; src[i]; i ++ ) + if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) + break; + + /* Hmm, it's not even an IP... */ + if( src[i] ) + return src; + + return ( src + 7 ); +} +#endif + +/* Convert from one charset to another. + + from_cs, to_cs: Source and destination charsets + src, dst: Source and destination strings + size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though. + maxbuf: Maximum number of bytes to write to dst + + Returns the number of bytes written to maxbuf or -1 on an error. +*/ +signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ) +{ + GIConv cd; + size_t res; + size_t inbytesleft, outbytesleft; + char *inbuf = src; + char *outbuf = dst; + + cd = g_iconv_open( to_cs, from_cs ); + if( cd == (GIConv) -1 ) + return( -1 ); + + inbytesleft = size ? size : strlen( src ); + outbytesleft = maxbuf - 1; + res = g_iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + *outbuf = '\0'; + g_iconv_close( cd ); + + if( res == (size_t) -1 ) + return( -1 ); + else + return( outbuf - dst ); +} + +char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +{ + GIConv cd; + + if ( g_strncasecmp( value, "none", 4 ) == 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/lib/misc.h b/lib/misc.h new file mode 100644 index 00000000..c7eec19b --- /dev/null +++ b/lib/misc.h @@ -0,0 +1,51 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* Misc. functions */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _UTIL_H +#define _UTIL_H + +G_MODULE_EXPORT void strip_linefeed( gchar *text ); +G_MODULE_EXPORT char *add_cr( char *text ); +G_MODULE_EXPORT char *strip_newlines(char *source); +G_MODULE_EXPORT char *tobase64( const char *text ); +G_MODULE_EXPORT void base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, char *b64digits ); +G_MODULE_EXPORT char *normalize( const char *s ); +G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); + +G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); +double gettime( void ); + +G_MODULE_EXPORT void strip_html( char *msg ); +G_MODULE_EXPORT char *escape_html( const char *html ); +G_MODULE_EXPORT void http_decode( char *s ); +G_MODULE_EXPORT void http_encode( char *s ); + +G_MODULE_EXPORT char *ipv6_wrap( char *src ); +G_MODULE_EXPORT char *ipv6_unwrap( char *src ); + +G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); +char *set_eval_charset( irc_t *irc, set_t *set, char *value ); + +#endif diff --git a/lib/proxy.c b/lib/proxy.c new file mode 100644 index 00000000..b8aa304d --- /dev/null +++ b/lib/proxy.c @@ -0,0 +1,556 @@ +/* + * gaim + * + * Copyright (C) 1998-1999, Mark Spencer + * Copyright (C) 2002-2004, Wilmer van der Gaast, Jelmer Vernooij + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define BITLBEE_CORE +#include +#include +#include +#include +#ifndef _WIN32 +#include +#include +#include +#include +#include +#else +#include "sock.h" +#define ETIMEDOUT WSAETIMEDOUT +#define EINPROGRESS WSAEINPROGRESS +#endif +#include +#include +#include "nogaim.h" +#include "proxy.h" + +char proxyhost[128] = ""; +int proxyport = 0; +int proxytype = PROXY_NONE; +char proxyuser[128] = ""; +char proxypass[128] = ""; + +struct PHB { + b_event_handler func, proxy_func; + gpointer data, proxy_data; + char *host; + int port; + int fd; + gint inpa; +}; + + + +static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) +{ + static struct sockaddr_in sin; + + if (!inet_aton(host, &sin.sin_addr)) { + struct hostent *hp; + if (!(hp = gethostbyname(host))) { + return NULL; + } + memset(&sin, 0, sizeof(struct sockaddr_in)); + memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); + sin.sin_family = hp->h_addrtype; + } else + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + + return &sin; +} + +static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) +{ + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + len = sizeof(error); + +#ifndef _WIN32 + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + closesocket(source); + b_event_remove(phb->inpa); + if( phb->proxy_func ) + phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); + else { + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb); + } + return FALSE; + } +#endif + sock_make_blocking(source); + b_event_remove(phb->inpa); + if( phb->proxy_func ) + phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); + else { + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb); + } + + return FALSE; +} + +static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) +{ + struct sockaddr_in *sin; + int fd = -1; + + if (!(sin = gaim_gethostbyname(host, port))) { + g_free(phb); + return -1; + } + + if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { + g_free(phb); + return -1; + } + + sock_make_nonblocking(fd); + + event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); + + if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { + if (sockerr_again()) { + phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); + phb->fd = fd; + } else { + closesocket(fd); + g_free(phb); + return -1; + } + } + + return fd; +} + + +/* Connecting to HTTP proxies */ + +#define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" +#define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" + +static gboolean http_canread(gpointer data, gint source, b_input_condition cond) +{ + int nlc = 0; + int pos = 0; + struct PHB *phb = data; + char inputline[8192]; + + b_event_remove(phb->inpa); + + while ((pos < sizeof(inputline)-1) && (nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { + if (inputline[pos - 1] == '\n') + nlc++; + else if (inputline[pos - 1] != '\r') + nlc = 0; + } + inputline[pos] = '\0'; + + if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || + (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + + return FALSE; +} + +static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond) +{ + char cmd[384]; + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + if (phb->inpa > 0) + b_event_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + sock_make_blocking(source); + + g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, + phb->host, phb->port); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if (proxyuser && *proxyuser) { + char *t1, *t2; + t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); + t2 = tobase64(t1); + g_free(t1); + g_snprintf(cmd, sizeof(cmd), "Proxy-Authorization: Basic %s\r\n", t2); + g_free(t2); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + } + + g_snprintf(cmd, sizeof(cmd), "\r\n"); + if (send(source, cmd, strlen(cmd), 0) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); + + return FALSE; +} + +static int proxy_connect_http(const char *host, unsigned short port, struct PHB *phb) +{ + phb->host = g_strdup(host); + phb->port = port; + phb->proxy_func = http_canwrite; + phb->proxy_data = phb; + + return( proxy_connect_none( proxyhost, proxyport, phb ) ); +} + + +/* Connecting to SOCKS4 proxies */ + +static gboolean s4_canread(gpointer data, gint source, b_input_condition cond) +{ + unsigned char packet[12]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + memset(packet, 0, sizeof(packet)); + if (read(source, packet, 9) >= 4 && packet[1] == 90) { + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + + return FALSE; +} + +static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond) +{ + unsigned char packet[12]; + struct hostent *hp; + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + if (phb->inpa > 0) + b_event_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + sock_make_blocking(source); + + /* XXX does socks4 not support host name lookups by the proxy? */ + if (!(hp = gethostbyname(phb->host))) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + packet[0] = 4; + packet[1] = 1; + packet[2] = phb->port >> 8; + packet[3] = phb->port & 0xff; + packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; + packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; + packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; + packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; + packet[8] = 0; + if (write(source, packet, 9) != 9) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); + + return FALSE; +} + +static int proxy_connect_socks4(const char *host, unsigned short port, struct PHB *phb) +{ + phb->host = g_strdup(host); + phb->port = port; + phb->proxy_func = s4_canwrite; + phb->proxy_data = phb; + + return( proxy_connect_none( proxyhost, proxyport, phb ) ); +} + + +/* Connecting to SOCKS5 proxies */ + +static gboolean s5_canread_again(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + if (read(source, buf, 10) < 10) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + if ((buf[0] != 0x05) || (buf[1] != 0x00)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->func(phb->data, source, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + + return FALSE; +} + +static void s5_sendconnect(gpointer data, gint source) +{ + unsigned char buf[512]; + struct PHB *phb = data; + int hlen = strlen(phb->host); + + buf[0] = 0x05; + buf[1] = 0x01; /* CONNECT */ + buf[2] = 0x00; /* reserved */ + buf[3] = 0x03; /* address type -- host name */ + buf[4] = hlen; + memcpy(buf + 5, phb->host, hlen); + buf[5 + strlen(phb->host)] = phb->port >> 8; + buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; + + if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); +} + +static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + if (read(source, buf, 2) < 2) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if ((buf[0] != 0x01) || (buf[1] != 0x00)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + s5_sendconnect(phb, source); + + return FALSE; +} + +static gboolean s5_canread(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + struct PHB *phb = data; + + b_event_remove(phb->inpa); + + if (read(source, buf, 2) < 2) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if ((buf[0] != 0x05) || (buf[1] == 0xff)) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + if (buf[1] == 0x02) { + unsigned int i = strlen(proxyuser), j = strlen(proxypass); + buf[0] = 0x01; /* version 1 */ + buf[1] = i; + memcpy(buf + 2, proxyuser, i); + buf[2 + i] = j; + memcpy(buf + 2 + i + 1, proxypass, j); + if (write(source, buf, 3 + i + j) < 3 + i + j) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); + } else { + s5_sendconnect(phb, source); + } + + return FALSE; +} + +static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond) +{ + unsigned char buf[512]; + int i; + struct PHB *phb = data; + unsigned int len; + int error = ETIMEDOUT; + if (phb->inpa > 0) + b_event_remove(phb->inpa); + len = sizeof(error); + if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + sock_make_blocking(source); + + i = 0; + buf[0] = 0x05; /* SOCKS version 5 */ + if (proxyuser[0]) { + buf[1] = 0x02; /* two methods */ + buf[2] = 0x00; /* no authentication */ + buf[3] = 0x02; /* username/password authentication */ + i = 4; + } else { + buf[1] = 0x01; + buf[2] = 0x00; + i = 3; + } + + if (write(source, buf, i) < i) { + close(source); + phb->func(phb->data, -1, GAIM_INPUT_READ); + g_free(phb->host); + g_free(phb); + return FALSE; + } + + phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); + + return FALSE; +} + +static int proxy_connect_socks5(const char *host, unsigned short port, struct PHB *phb) +{ + phb->host = g_strdup(host); + phb->port = port; + phb->proxy_func = s5_canwrite; + phb->proxy_data = phb; + + return( proxy_connect_none( proxyhost, proxyport, phb ) ); +} + + +/* Export functions */ + +int proxy_connect(const char *host, int port, b_event_handler func, gpointer data) +{ + struct PHB *phb; + + if (!host || !port || (port == -1) || !func || strlen(host) > 128) { + return -1; + } + + phb = g_new0(struct PHB, 1); + phb->func = func; + phb->data = data; + +#ifndef _WIN32 + sethostent(1); +#endif + + if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || !proxyport || (proxyport == -1)) + return proxy_connect_none(host, port, phb); + else if (proxytype == PROXY_HTTP) + return proxy_connect_http(host, port, phb); + else if (proxytype == PROXY_SOCKS4) + return proxy_connect_socks4(host, port, phb); + else if (proxytype == PROXY_SOCKS5) + return proxy_connect_socks5(host, port, phb); + + if (phb->host) g_free(phb); + g_free(phb); + return -1; +} diff --git a/lib/proxy.h b/lib/proxy.h new file mode 100644 index 00000000..680790a5 --- /dev/null +++ b/lib/proxy.h @@ -0,0 +1,53 @@ +/* + * nogaim + * + * Copyright (C) 1998-1999, Mark Spencer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* this is the export part of the proxy.c file. it does a little + prototype-ing stuff and redefine some net function to mask them + with some kind of transparent layer */ + +#ifndef _PROXY_H_ +#define _PROXY_H_ + +#include +#ifndef _WIN32 +#include +#include +#include +#endif +#include +#include + +#include "events.h" + +#define PROXY_NONE 0 +#define PROXY_HTTP 1 +#define PROXY_SOCKS4 2 +#define PROXY_SOCKS5 3 + +extern char proxyhost[128]; +extern int proxyport; +extern int proxytype; +extern char proxyuser[128]; +extern char proxypass[128]; + +G_MODULE_EXPORT int proxy_connect(const char *host, int port, b_event_handler func, gpointer data); + +#endif /* _PROXY_H_ */ diff --git a/lib/rc4.c b/lib/rc4.c new file mode 100644 index 00000000..3559f71e --- /dev/null +++ b/lib/rc4.c @@ -0,0 +1,179 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple (but secure) RC4 implementation for safer password storage. * +* * +* Copyright 2006 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 as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +/* + This file implements RC4-encryption, which will mainly be used to save IM + passwords safely in the new XML-format. Possibly other uses will come up + later. It's supposed to be quite reliable (thanks to the use of a 6-byte + IV/seed), certainly compared to the old format. The only realistic way to + crack BitlBee passwords now is to use a sniffer to get your hands on the + user's password. + + If you see that something's wrong in this implementation (I asked a + couple of people to look at it already, but who knows), please tell me. + + The reason I chose for RC4 is because it's pretty simple but effective, + so it will work without adding several KBs or an extra library dependency. +*/ + + +#include +#include +#include +#include "rc4.h" + +/* Add some seed to the password, to make sure we *never* use the same key. + This defines how many byes we use as a seed. */ +#define RC4_IV_LEN 6 + +/* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended + to shuffle S[] just a bit more before you start to use it. This defines how + many bytes we'll request before we'll really use them for encryption. */ +#define RC4_CYCLES 1024 + +struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ) +{ + struct rc4_state *st; + int i, j, tmp; + + st = g_malloc( sizeof( struct rc4_state ) ); + st->i = st->j = 0; + for( i = 0; i < 256; i ++ ) + st->S[i] = i; + + if( kl <= 0 ) + kl = strlen( (char*) key ); + + for( i = j = 0; i < 256; i ++ ) + { + j = ( j + st->S[i] + key[i%kl] ) & 0xff; + tmp = st->S[i]; + st->S[i] = st->S[j]; + st->S[j] = tmp; + } + + for( i = 0; i < cycles; i ++ ) + rc4_getbyte( st ); + + return st; +} + +/* + For those who don't know, RC4 is basically an algorithm that generates a + stream of bytes after you give it a key. Just get a byte from it and xor + it with your cleartext. To decrypt, just give it the same key again and + start xorring. + + The function above initializes the RC4 byte generator, the next function + can be used to get bytes from the generator (and shuffle things a bit). +*/ + +unsigned char rc4_getbyte( struct rc4_state *st ) +{ + unsigned char tmp; + + /* Unfortunately the st-> stuff doesn't really improve readability here... */ + st->i ++; + st->j += st->S[st->i]; + tmp = st->S[st->i]; + st->S[st->i] = st->S[st->j]; + st->S[st->j] = tmp; + + return st->S[(st->S[st->i] + st->S[st->j]) & 0xff]; +} + +/* + The following two functions can be used for reliable encryption and + decryption. Known plaintext attacks are prevented by adding some (6, + by default) random bytes to the password before setting up the RC4 + structures. These 6 bytes are also saved in the results, because of + course we'll need them in rc4_decode(). + + Because the length of the resulting string is unknown to the caller, + it should pass a char**. Since the encode/decode functions allocate + memory for the string, make sure the char** points at a NULL-pointer + (or at least to something you already free()d), or you'll leak + memory. And of course, don't forget to free() the result when you + don't need it anymore. + + Both functions return the number of bytes in the result string. +*/ + +int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password ) +{ + struct rc4_state *st; + unsigned char *key; + int key_len, i; + + key_len = strlen( password ) + RC4_IV_LEN; + if( clear_len <= 0 ) + clear_len = strlen( (char*) clear ); + + /* Prepare buffers and the key + IV */ + *crypt = g_malloc( clear_len + RC4_IV_LEN ); + key = g_malloc( key_len ); + strcpy( (char*) key, password ); + for( i = 0; i < RC4_IV_LEN; i ++ ) + key[key_len-RC4_IV_LEN+i] = crypt[0][i] = rand() & 0xff; + + /* Generate the initial S[] from the IVed key. */ + st = rc4_keymaker( key, key_len, RC4_CYCLES ); + g_free( key ); + + for( i = 0; i < clear_len; i ++ ) + crypt[0][i+RC4_IV_LEN] = clear[i] ^ rc4_getbyte( st ); + + g_free( st ); + + return clear_len + RC4_IV_LEN; +} + +int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password ) +{ + struct rc4_state *st; + unsigned char *key; + int key_len, clear_len, i; + + key_len = strlen( password ) + RC4_IV_LEN; + clear_len = crypt_len - RC4_IV_LEN; + + /* Prepare buffers and the key + IV */ + *clear = g_malloc( clear_len + 1 ); + key = g_malloc( key_len ); + strcpy( (char*) key, password ); + for( i = 0; i < RC4_IV_LEN; i ++ ) + key[key_len-RC4_IV_LEN+i] = crypt[i]; + + /* Generate the initial S[] from the IVed key. */ + st = rc4_keymaker( key, key_len, RC4_CYCLES ); + g_free( key ); + + for( i = 0; i < clear_len; i ++ ) + clear[0][i] = crypt[i+RC4_IV_LEN] ^ rc4_getbyte( st ); + clear[0][i] = 0; /* Nice to have for plaintexts. */ + + g_free( st ); + + return clear_len; +} diff --git a/lib/rc4.h b/lib/rc4.h new file mode 100644 index 00000000..8d50b508 --- /dev/null +++ b/lib/rc4.h @@ -0,0 +1,35 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Simple (but secure) RC4 implementation for safer password storage. * +* * +* Copyright 2006 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 as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + + +struct rc4_state +{ + unsigned char S[256]; + unsigned char i, j; +}; + +struct rc4_state *rc4_keymaker( unsigned char *key, int kl, int cycles ); +unsigned char rc4_getbyte( struct rc4_state *st ); +int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *password ); +int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char *password ); diff --git a/lib/sha.c b/lib/sha.c new file mode 100644 index 00000000..895505a1 --- /dev/null +++ b/lib/sha.c @@ -0,0 +1,173 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is SHA 180-1 Reference Implementation (Compact version) + * + * The Initial Developer of the Original Code is Paul Kocher of + * Cryptography Research. Portions created by Paul Kocher are + * Copyright (C) 1995-9 by Cryptography Research, Inc. All + * Rights Reserved. + * + * Contributor(s): + * + */ + +#define BITLBEE_CORE +#include "nogaim.h" + +static void shaHashBlock(SHA_CTX *ctx); + +void shaInit(SHA_CTX *ctx) { + int i; + + ctx->lenW = 0; + ctx->sizeHi = ctx->sizeLo = 0; + + /* Initialize H with the magic constants (see FIPS180 for constants) + */ + ctx->H[0] = 0x67452301L; + ctx->H[1] = 0xefcdab89L; + ctx->H[2] = 0x98badcfeL; + ctx->H[3] = 0x10325476L; + ctx->H[4] = 0xc3d2e1f0L; + + for (i = 0; i < 80; i++) + ctx->W[i] = 0; +} + + +void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) { + int i; + + /* Read the data into W and process blocks as they get full + */ + for (i = 0; i < len; i++) { + ctx->W[ctx->lenW / 4] <<= 8; + ctx->W[ctx->lenW / 4] |= (guint32)dataIn[i]; + if ((++ctx->lenW) % 64 == 0) { + shaHashBlock(ctx); + ctx->lenW = 0; + } + ctx->sizeLo += 8; + ctx->sizeHi += (ctx->sizeLo < 8); + } +} + + +void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]) { + unsigned char pad0x80 = 0x80; + unsigned char pad0x00 = 0x00; + unsigned char padlen[8]; + int i; + + /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length + */ + padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); + padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); + padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); + padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); + padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); + padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); + padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); + padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); + shaUpdate(ctx, &pad0x80, 1); + while (ctx->lenW != 56) + shaUpdate(ctx, &pad0x00, 1); + shaUpdate(ctx, padlen, 8); + + /* Output hash + */ + for (i = 0; i < 20; i++) { + hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); + ctx->H[i / 4] <<= 8; + } + + /* + * Re-initialize the context (also zeroizes contents) + */ + shaInit(ctx); +} + + +void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) { + SHA_CTX ctx; + + shaInit(&ctx); + shaUpdate(&ctx, dataIn, len); + shaFinal(&ctx, hashout); +} + + +#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) + +static void shaHashBlock(SHA_CTX *ctx) { + int t; + guint32 A,B,C,D,E,TEMP; + + for (t = 16; t <= 79; t++) + ctx->W[t] = + SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); + + A = ctx->H[0]; + B = ctx->H[1]; + C = ctx->H[2]; + D = ctx->H[3]; + E = ctx->H[4]; + + for (t = 0; t <= 19; t++) { + TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 20; t <= 39; t++) { + TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 40; t <= 59; t++) { + TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + for (t = 60; t <= 79; t++) { + TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; + E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; + } + + ctx->H[0] += A; + ctx->H[1] += B; + ctx->H[2] += C; + ctx->H[3] += D; + ctx->H[4] += E; +} + +/*---------------------------------------------------------------------------- + * + * This code added by Thomas "temas" Muldowney for Jabber compatability + * + *---------------------------------------------------------------------------*/ +char *shahash(char *str) +{ + static char final[41]; + char *pos; + unsigned char hashval[20]; + int x; + + if(!str || strlen(str) == 0) + return NULL; + + shaBlock((unsigned char *)str, strlen(str), hashval); + + pos = final; + for(x=0;x<20;x++) + { + g_snprintf(pos, 3, "%02x", hashval[x]); + pos += 2; + } + return (char *)final; +} diff --git a/lib/sha.h b/lib/sha.h new file mode 100644 index 00000000..e8152b1b --- /dev/null +++ b/lib/sha.h @@ -0,0 +1,21 @@ +#ifndef __SHA_H__ +#define __SHA_H__ + +#include + +G_MODULE_EXPORT int strprintsha(char *dest, int *hashval); + +typedef struct { + guint32 H[5]; + guint32 W[80]; + int lenW; + guint32 sizeHi,sizeLo; +} SHA_CTX; + +G_MODULE_EXPORT void shaInit(SHA_CTX *ctx); +G_MODULE_EXPORT void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); +G_MODULE_EXPORT void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]); +G_MODULE_EXPORT void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]); +G_MODULE_EXPORT char *shahash(char *str); + +#endif diff --git a/lib/ssl_bogus.c b/lib/ssl_bogus.c new file mode 100644 index 00000000..00aaa7c4 --- /dev/null +++ b/lib/ssl_bogus.c @@ -0,0 +1,57 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - dummy version */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "ssl_client.h" + +int ssl_errno; + +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) +{ + return( NULL ); +} + +int ssl_read( void *conn, char *buf, int len ) +{ + return( -1 ); +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + return( -1 ); +} + +void ssl_disconnect( void *conn_ ) +{ +} + +int ssl_getfd( void *conn ) +{ + return( -1 ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + return GAIM_INPUT_READ; +} diff --git a/lib/ssl_client.h b/lib/ssl_client.h new file mode 100644 index 00000000..1a9c79e9 --- /dev/null +++ b/lib/ssl_client.h @@ -0,0 +1,42 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include "proxy.h" + +#define SSL_OK 0 +#define SSL_NOHANDSHAKE 1 +#define SSL_AGAIN 2 + +extern int ssl_errno; + +typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); + +G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); +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 ); +G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); +G_MODULE_EXPORT int ssl_getfd( void *conn ); +G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); diff --git a/lib/ssl_gnutls.c b/lib/ssl_gnutls.c new file mode 100644 index 00000000..3ebe1756 --- /dev/null +++ b/lib/ssl_gnutls.c @@ -0,0 +1,206 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - GnuTLS version */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "proxy.h" +#include "ssl_client.h" +#include "sock.h" +#include "stdlib.h" + +int ssl_errno = 0; + +static gboolean initialized = FALSE; + +struct scd +{ + ssl_input_function func; + gpointer data; + int fd; + gboolean established; + int inpa; + + gnutls_session session; + gnutls_certificate_credentials xcred; +}; + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); + + +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 ); + } + + if( !initialized ) + { + gnutls_global_init(); + initialized = TRUE; + atexit( gnutls_global_deinit ); + } + + gnutls_certificate_allocate_credentials( &conn->xcred ); + gnutls_init( &conn->session, GNUTLS_CLIENT ); + gnutls_set_default_priority( conn->session ); + gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); + + return( conn ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + if( source == -1 ) + { + conn->func( conn->data, NULL, cond ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + + g_free( conn ); + + return FALSE; + } + + sock_make_nonblocking( conn->fd ); + gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); + + return ssl_handshake( data, source, cond ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + int st; + + if( ( st = gnutls_handshake( conn->session ) ) < 0 ) + { + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + { + conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), + ssl_handshake, data ); + } + else + { + conn->func( conn->data, NULL, cond ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + closesocket( conn->fd ); + + g_free( conn ); + } + } + else + { + /* For now we can't handle non-blocking perfectly everywhere... */ + sock_make_blocking( conn->fd ); + + conn->established = TRUE; + conn->func( conn->data, conn, cond ); + } + + return FALSE; +} + +int ssl_read( void *conn, char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return( -1 ); + } + + st = gnutls_record_recv( ((struct scd*)conn)->session, buf, len ); + + ssl_errno = SSL_OK; + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + ssl_errno = SSL_AGAIN; + + return st; +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return( -1 ); + } + + st = gnutls_record_send( ((struct scd*)conn)->session, buf, len ); + + ssl_errno = SSL_OK; + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + ssl_errno = SSL_AGAIN; + + return st; +} + +void ssl_disconnect( void *conn_ ) +{ + struct scd *conn = conn_; + + if( conn->inpa != -1 ) + b_event_remove( conn->inpa ); + + if( conn->established ) + gnutls_bye( conn->session, GNUTLS_SHUT_WR ); + + closesocket( conn->fd ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + g_free( conn ); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? + GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} diff --git a/lib/ssl_nss.c b/lib/ssl_nss.c new file mode 100644 index 00000000..218b3a80 --- /dev/null +++ b/lib/ssl_nss.c @@ -0,0 +1,190 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - NSS version */ + +/* Copyright 2005 Jelmer Vernooij */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "bitlbee.h" +#include "proxy.h" +#include "ssl_client.h" +#include "sock.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int ssl_errno = 0; + +static gboolean initialized = FALSE; + +struct scd +{ + ssl_input_function func; + gpointer data; + int fd; + PRFileDesc *prfd; + gboolean established; +}; + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); + + +static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver) +{ + return SECSuccess; +} + +static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket) +{ + PRErrorCode err; + + if(!arg) return SECFailure; + + *(PRErrorCode *)arg = err = PORT_GetError(); + + switch(err) { + case SEC_ERROR_INVALID_AVA: + case SEC_ERROR_INVALID_TIME: + case SEC_ERROR_BAD_SIGNATURE: + case SEC_ERROR_EXPIRED_CERTIFICATE: + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_CERT: + case SEC_ERROR_CERT_VALID: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + case SEC_ERROR_CRL_EXPIRED: + case SEC_ERROR_CRL_BAD_SIGNATURE: + case SEC_ERROR_EXTENSION_VALUE_INVALID: + case SEC_ERROR_CA_CERT_INVALID: + case SEC_ERROR_CERT_USAGES_INVALID: + case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: + return SECSuccess; + + default: + return SECFailure; + } +} + + +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; + + if( conn->fd < 0 ) + { + g_free( conn ); + return( NULL ); + } + + if( !initialized ) + { + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + NSS_NoDB_Init(NULL); + NSS_SetDomesticPolicy(); + } + + + return( conn ); +} + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + if( source == -1 ) + goto ssl_connected_failure; + + /* Until we find out how to handle non-blocking I/O with NSS... */ + sock_make_blocking( conn->fd ); + + conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source)); + SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE); + SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + SSL_BadCertHook(conn->prfd, (SSLBadCertHandler)nss_bad_cert, NULL); + SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate)nss_auth_cert, (void *)CERT_GetDefaultCertDB()); + SSL_ResetHandshake(conn->prfd, PR_FALSE); + + if (SSL_ForceHandshake(conn->prfd)) { + goto ssl_connected_failure; + } + + + conn->established = TRUE; + conn->func( conn->data, conn, cond ); + return FALSE; + + ssl_connected_failure: + + conn->func( conn->data, NULL, cond ); + + PR_Close( conn -> prfd ); + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; +} + +int ssl_read( void *conn, char *buf, int len ) +{ + if( !((struct scd*)conn)->established ) + return( 0 ); + + return( PR_Read( ((struct scd*)conn)->prfd, buf, len ) ); +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + if( !((struct scd*)conn)->established ) + return( 0 ); + + return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); +} + +void ssl_disconnect( void *conn_ ) +{ + struct scd *conn = conn_; + + PR_Close( conn->prfd ); + closesocket( conn->fd ); + + g_free( conn ); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + /* Just in case someone calls us, let's return the most likely case: */ + return GAIM_INPUT_READ; +} diff --git a/lib/ssl_openssl.c b/lib/ssl_openssl.c new file mode 100644 index 00000000..b6f6c520 --- /dev/null +++ b/lib/ssl_openssl.c @@ -0,0 +1,221 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2002-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* SSL module - OpenSSL version */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include + +#include "proxy.h" +#include "ssl_client.h" +#include "sock.h" + +int ssl_errno = 0; + +static gboolean initialized = FALSE; + +struct scd +{ + ssl_input_function func; + gpointer data; + int fd; + gboolean established; + + int inpa; + int lasterr; /* Necessary for SSL_get_error */ + SSL *ssl; + SSL_CTX *ssl_ctx; +}; + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); + + +void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) +{ + struct scd *conn = g_new0( struct scd, 1 ); + SSL_METHOD *meth; + + conn->fd = proxy_connect( host, port, ssl_connected, conn ); + conn->func = func; + conn->data = data; + + if( conn->fd < 0 ) + { + g_free( conn ); + return( NULL ); + } + + if( !initialized ) + { + initialized = TRUE; + SSLeay_add_ssl_algorithms(); + } + + meth = TLSv1_client_method(); + conn->ssl_ctx = SSL_CTX_new( meth ); + if( conn->ssl_ctx == NULL ) + { + conn->fd = -1; + return( NULL ); + } + + conn->ssl = SSL_new( conn->ssl_ctx ); + if( conn->ssl == NULL ) + { + conn->fd = -1; + return( NULL ); + } + + return( conn ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); + +static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + + if( source == -1 ) + return ssl_handshake( data, -1, cond ); + + /* We can do at least the handshake with non-blocking I/O */ + sock_make_nonblocking( conn->fd ); + SSL_set_fd( conn->ssl, conn->fd ); + + return ssl_handshake( data, source, cond ); +} + +static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) +{ + struct scd *conn = data; + int st; + + if( ( st = SSL_connect( conn->ssl ) ) < 0 ) + { + conn->lasterr = SSL_get_error( conn->ssl, st ); + if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) + goto ssl_connected_failure; + + conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); + return FALSE; + } + + conn->established = TRUE; + sock_make_blocking( conn->fd ); /* For now... */ + conn->func( conn->data, conn, cond ); + return FALSE; + +ssl_connected_failure: + conn->func( conn->data, NULL, cond ); + + if( conn->ssl ) + { + SSL_shutdown( conn->ssl ); + SSL_free( conn->ssl ); + } + if( conn->ssl_ctx ) + { + SSL_CTX_free( conn->ssl_ctx ); + } + if( source >= 0 ) closesocket( source ); + g_free( conn ); + + return FALSE; +} + +int ssl_read( void *conn, char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return -1; + } + + st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); + + ssl_errno = SSL_OK; + if( st <= 0 ) + { + ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); + if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) + ssl_errno = SSL_AGAIN; + } + + return st; +} + +int ssl_write( void *conn, const char *buf, int len ) +{ + int st; + + if( !((struct scd*)conn)->established ) + { + ssl_errno = SSL_NOHANDSHAKE; + return -1; + } + + st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); + + ssl_errno = SSL_OK; + if( st <= 0 ) + { + ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); + if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) + ssl_errno = SSL_AGAIN; + } + + return st; +} + +void ssl_disconnect( void *conn_ ) +{ + struct scd *conn = conn_; + + if( conn->inpa != -1 ) + b_event_remove( conn->inpa ); + + if( conn->established ) + SSL_shutdown( conn->ssl ); + + closesocket( conn->fd ); + + SSL_free( conn->ssl ); + SSL_CTX_free( conn->ssl_ctx ); + g_free( conn ); +} + +int ssl_getfd( void *conn ) +{ + return( ((struct scd*)conn)->fd ); +} + +b_input_condition ssl_getdirection( void *conn ) +{ + return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} diff --git a/lib/url.c b/lib/url.c new file mode 100644 index 00000000..e4deac78 --- /dev/null +++ b/lib/url.c @@ -0,0 +1,107 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2001-2005 Wilmer van der Gaast and others * + \********************************************************************/ + +/* URL/mirror stuff - Stolen from Axel */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "url.h" + +/* Convert an URL to a url_t structure */ +int url_set( url_t *url, char *set_url ) +{ + char s[MAX_STRING]; + char *i; + + /* protocol:// */ + if( ( i = strstr( set_url, "://" ) ) == NULL ) + { + url->proto = PROTO_DEFAULT; + strncpy( s, set_url, MAX_STRING ); + } + else + { + if( g_strncasecmp( set_url, "http", i - set_url ) == 0 ) + url->proto = PROTO_HTTP; + else if( g_strncasecmp( set_url, "https", i - set_url ) == 0 ) + url->proto = PROTO_HTTPS; + else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 ) + url->proto = PROTO_SOCKS4; + else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 ) + url->proto = PROTO_SOCKS5; + else + { + return( 0 ); + } + strncpy( s, i + 3, MAX_STRING ); + } + + /* Split */ + if( ( i = strchr( s, '/' ) ) == NULL ) + { + strcpy( url->file, "/" ); + } + else + { + strncpy( url->file, i, MAX_STRING ); + *i = 0; + } + strncpy( url->host, s, MAX_STRING ); + + /* Check for username in host field */ + if( strrchr( url->host, '@' ) != NULL ) + { + strncpy( url->user, url->host, MAX_STRING ); + i = strrchr( url->user, '@' ); + *i = 0; + strcpy( url->host, i + 1 ); + *url->pass = 0; + } + /* If not: Fill in defaults */ + else + { + *url->user = *url->pass = 0; + } + + /* Password? */ + if( ( i = strchr( url->user, ':' ) ) != NULL ) + { + *i = 0; + strcpy( url->pass, i + 1 ); + } + /* Port number? */ + if( ( i = strchr( url->host, ':' ) ) != NULL ) + { + *i = 0; + sscanf( i + 1, "%d", &url->port ); + } + else + { + if( url->proto == PROTO_HTTP ) + url->port = 80; + else if( url->proto == PROTO_HTTPS ) + url->port = 443; + else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS4 ) + url->port = 1080; + } + + return( url->port > 0 ); +} diff --git a/lib/url.h b/lib/url.h new file mode 100644 index 00000000..e9e1ecfe --- /dev/null +++ b/lib/url.h @@ -0,0 +1,44 @@ + /********************************************************************\ + * BitlBee -- An IRC to other IM-networks gateway * + * * + * Copyright 2001-2004 Wilmer van der Gaast and others * + \********************************************************************/ + +/* URL/mirror stuff - Stolen from Axel */ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License with + the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; + if not, write to the Free Software Foundation, Inc., 59 Temple Place, + Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "bitlbee.h" + +#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]; +} url_t; + +int url_set( url_t *url, char *set_url ); diff --git a/protocols/Makefile b/protocols/Makefile index b74212f4..cc45fb09 100644 --- a/protocols/Makefile +++ b/protocols/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = $(EVENT_HANDLER) http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) +objects = nogaim.o # [SH] The next two lines should contain the directory name (in $(subdirs)) # and the name of the object file, which should be linked into diff --git a/protocols/events.h b/protocols/events.h deleted file mode 100644 index 781fca6a..00000000 --- a/protocols/events.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * nogaim - * - * Copyright (C) 2006 Wilmer van der Gaast and others - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * Split off the event handling things from proxy.[ch] (and adding timer - * stuff. This to allow BitlBee to use other libs than GLib for event - * handling. - */ - - -#ifndef _EVENTS_H_ -#define _EVENTS_H_ - -#include -#ifndef _WIN32 -#include -#include -#include -#endif -#include -#include - -typedef enum { - GAIM_INPUT_READ = 1 << 1, - GAIM_INPUT_WRITE = 1 << 2 -} b_input_condition; -typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); - -#define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) -#define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) - -// #define event_debug( x... ) printf( x ) -#define event_debug( x... ) - -G_MODULE_EXPORT void b_main_init(); -G_MODULE_EXPORT void b_main_run(); -G_MODULE_EXPORT void b_main_quit(); - -G_MODULE_EXPORT gint b_input_add(int fd, b_input_condition cond, b_event_handler func, gpointer data); -G_MODULE_EXPORT gint b_timeout_add(gint timeout, b_event_handler func, gpointer data); -G_MODULE_EXPORT void b_event_remove(gint id); - -#ifdef EVENTS_LIBEVENT -G_MODULE_EXPORT void closesocket(int fd); -#endif - -#endif /* _EVENTS_H_ */ diff --git a/protocols/events_glib.c b/protocols/events_glib.c deleted file mode 100644 index 620720cd..00000000 --- a/protocols/events_glib.c +++ /dev/null @@ -1,137 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2006 Wilmer van der Gaast and others * - \********************************************************************/ - -/* - * Event handling (using GLib) - */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#define BITLBEE_CORE -#include -#include -#include -#include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#else -#include "sock.h" -#define ETIMEDOUT WSAETIMEDOUT -#define EINPROGRESS WSAEINPROGRESS -#endif -#include -#include -#include "proxy.h" - -typedef struct _GaimIOClosure { - b_event_handler function; - guint result; - gpointer data; -} GaimIOClosure; - -static GMainLoop *loop; - -void b_main_init() -{ - loop = g_main_new( FALSE ); -} - -void b_main_run() -{ - g_main_run( loop ); -} - -void b_main_quit() -{ - g_main_quit( loop ); -} - -static gboolean gaim_io_invoke(GIOChannel *source, GIOCondition condition, gpointer data) -{ - GaimIOClosure *closure = data; - b_input_condition gaim_cond = 0; - gboolean st; - - if (condition & GAIM_READ_COND) - gaim_cond |= GAIM_INPUT_READ; - if (condition & GAIM_WRITE_COND) - gaim_cond |= GAIM_INPUT_WRITE; - - event_debug( "gaim_io_invoke( %d, %d, 0x%x )\n", g_io_channel_unix_get_fd(source), condition, data ); - - st = closure->function(closure->data, g_io_channel_unix_get_fd(source), gaim_cond); - - if( !st ) - event_debug( "Returned FALSE, cancelling.\n" ); - - return st; -} - -static void gaim_io_destroy(gpointer data) -{ - event_debug( "gaim_io_destroy( 0x%x )\n", data ); - g_free(data); -} - -gint b_input_add(gint source, b_input_condition condition, b_event_handler function, gpointer data) -{ - GaimIOClosure *closure = g_new0(GaimIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = 0; - - closure->function = function; - closure->data = data; - - if (condition & GAIM_INPUT_READ) - cond |= GAIM_READ_COND; - if (condition & GAIM_INPUT_WRITE) - cond |= GAIM_WRITE_COND; - - channel = g_io_channel_unix_new(source); - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - gaim_io_invoke, closure, gaim_io_destroy); - - event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) = %d (0x%x)\n", source, condition, function, data, closure->result, closure ); - - g_io_channel_unref(channel); - return closure->result; -} - -gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) -{ - gint st = g_timeout_add(timeout, func, data); - - event_debug( "b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st ); - - return st; -} - -void b_event_remove(gint tag) -{ - event_debug( "b_event_remove( %d )\n", tag ); - - if (tag > 0) - g_source_remove(tag); -} diff --git a/protocols/events_libevent.c b/protocols/events_libevent.c deleted file mode 100644 index 1119c2ab..00000000 --- a/protocols/events_libevent.c +++ /dev/null @@ -1,247 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2006 Wilmer van der Gaast and others * - \********************************************************************/ - -/* - * Event handling (using libevent) - */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#define BITLBEE_CORE -#include -#include -#include -#include -#include -#include "proxy.h" - -#include -#include - -static guint id_next; -static GHashTable *id_hash; -static int quitting = 0; - -/* Since libevent doesn't handle two event handlers for one fd-condition - very well (which happens sometimes when BitlBee changes event handlers - for a combination), let's buid some indexes so we can delete them here - already, just in time. */ -static GHashTable *read_hash; -static GHashTable *write_hash; - -struct b_event_data -{ - guint id; - struct event evinfo; - gint timeout; - b_event_handler function; - void *data; -}; - -void b_main_init() -{ - event_init(); - - id_next = 1; - id_hash = g_hash_table_new( g_int_hash, g_int_equal ); - read_hash = g_hash_table_new( g_int_hash, g_int_equal ); - write_hash = g_hash_table_new( g_int_hash, g_int_equal ); -} - -void b_main_run() -{ - event_dispatch(); -} - -void b_main_quit() -{ - struct timeval tv; - - /* libevent sometimes generates events before really quitting, - we want to stop them. */ - quitting = 1; - - memset( &tv, 0, sizeof( struct timeval ) ); - event_loopexit( &tv ); -} - -static void b_event_passthrough( int fd, short event, void *data ) -{ - struct b_event_data *b_ev = data; - b_input_condition cond = 0; - int id; - - if( fd >= 0 ) - { - if( event & EV_READ ) - cond |= GAIM_INPUT_READ; - if( event & EV_WRITE ) - cond |= GAIM_INPUT_WRITE; - } - - event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); - - /* Since the called function might cancel this handler already - (which free()s b_ev, we have to remember the ID here. */ - id = b_ev->id; - - if( quitting ) - { - b_event_remove( id ); - return; - } - - if( !b_ev->function( b_ev->data, fd, cond ) ) - { - event_debug( "Handler returned FALSE: " ); - b_event_remove( id ); - } - else if( fd == -1 ) - { - struct timeval tv; - - tv.tv_sec = b_ev->timeout / 1000; - tv.tv_usec = ( b_ev->timeout % 1000 ) * 1000; - - evtimer_add( &b_ev->evinfo, &tv ); - } -} - -gint b_input_add( gint fd, b_input_condition condition, b_event_handler function, gpointer data ) -{ - struct b_event_data *b_ev; - - event_debug( "b_input_add( %d, %d, 0x%x, 0x%x ) ", fd, condition, function, data ); - - if( ( condition & GAIM_INPUT_READ && ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) || - ( condition & GAIM_INPUT_WRITE && ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) ) - { - /* We'll stick with this libevent entry, but give it a new BitlBee id. */ - g_hash_table_remove( id_hash, &b_ev->id ); - - event_debug( "(replacing old handler (id = %d)) = %d\n", b_ev->id, id_next ); - - b_ev->id = id_next++; - b_ev->function = function; - b_ev->data = data; - } - else - { - GIOCondition out_cond; - - event_debug( "(new) = %d\n", id_next ); - - b_ev = g_new0( struct b_event_data, 1 ); - b_ev->id = id_next++; - b_ev->function = function; - b_ev->data = data; - - out_cond = EV_PERSIST; - if( condition & GAIM_INPUT_READ ) - out_cond |= EV_READ; - if( condition & GAIM_INPUT_WRITE ) - out_cond |= EV_WRITE; - - event_set( &b_ev->evinfo, fd, out_cond, b_event_passthrough, b_ev ); - event_add( &b_ev->evinfo, NULL ); - - if( out_cond & EV_READ ) - g_hash_table_insert( read_hash, &b_ev->evinfo.ev_fd, b_ev ); - if( out_cond & EV_WRITE ) - g_hash_table_insert( write_hash, &b_ev->evinfo.ev_fd, b_ev ); - } - - g_hash_table_insert( id_hash, &b_ev->id, b_ev ); - return b_ev->id; -} - -/* TODO: Persistence for timers! */ -gint b_timeout_add( gint timeout, b_event_handler function, gpointer data ) -{ - struct b_event_data *b_ev = g_new0( struct b_event_data, 1 ); - struct timeval tv; - - b_ev->id = id_next++; - b_ev->timeout = timeout; - b_ev->function = function; - b_ev->data = data; - - tv.tv_sec = timeout / 1000; - tv.tv_usec = ( timeout % 1000 ) * 1000; - - evtimer_set( &b_ev->evinfo, b_event_passthrough, b_ev ); - evtimer_add( &b_ev->evinfo, &tv ); - - event_debug( "b_timeout_add( %d, 0x%x, 0x%x ) = %d\n", timeout, function, data, b_ev->id ); - - g_hash_table_insert( id_hash, &b_ev->id, b_ev ); - - return b_ev->id; -} - -void b_event_remove( gint id ) -{ - struct b_event_data *b_ev = g_hash_table_lookup( id_hash, &id ); - - event_debug( "b_event_remove( %d )\n", id ); - if( b_ev ) - { - g_hash_table_remove( id_hash, &b_ev->id ); - if( b_ev->evinfo.ev_fd >= 0 ) - { - if( b_ev->evinfo.ev_events & EV_READ ) - g_hash_table_remove( read_hash, &b_ev->evinfo.ev_fd ); - if( b_ev->evinfo.ev_events & EV_WRITE ) - g_hash_table_remove( write_hash, &b_ev->evinfo.ev_fd ); - } - - event_del( &b_ev->evinfo ); - g_free( b_ev ); - } - else - { - event_debug( "Already removed?\n" ); - } -} - -void closesocket( int fd ) -{ - struct b_event_data *b_ev; - - /* Since epoll() (the main reason we use libevent) automatically removes sockets from - the epoll() list when a socket gets closed and some modules have a habit of - closing sockets before removing event handlers, our and libevent's administration - get a little bit messed up. So this little function will remove the handlers - properly before closing a socket. */ - - if( ( b_ev = g_hash_table_lookup( read_hash, &fd ) ) ) - { - event_debug( "Warning: fd %d still had a read event handler when shutting down.\n", fd ); - b_event_remove( b_ev->id ); - } - if( ( b_ev = g_hash_table_lookup( write_hash, &fd ) ) ) - { - event_debug( "Warning: fd %d still had a write event handler when shutting down.\n", fd ); - b_event_remove( b_ev->id ); - } - - close( fd ); -} diff --git a/protocols/http_client.c b/protocols/http_client.c deleted file mode 100644 index b00fcf98..00000000 --- a/protocols/http_client.c +++ /dev/null @@ -1,453 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2005 Wilmer van der Gaast and others * - \********************************************************************/ - -/* HTTP(S) module */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include - -#include "http_client.h" -#include "url.h" -#include "sock.h" - - -static gboolean http_connected( gpointer data, int source, b_input_condition cond ); -static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ); -static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ); - - -void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ) -{ - struct http_request *req; - int error = 0; - - req = g_new0( struct http_request, 1 ); - - if( ssl ) - { - req->ssl = ssl_connect( host, port, http_ssl_connected, req ); - if( req->ssl == NULL ) - error = 1; - } - else - { - req->fd = proxy_connect( host, port, http_connected, req ); - if( req->fd < 0 ) - error = 1; - } - - if( error ) - { - g_free( req ); - return( NULL ); - } - - req->func = func; - req->data = data; - req->request = g_strdup( request ); - req->request_length = strlen( request ); - - return( req ); -} - -void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ) -{ - url_t *url = g_new0( url_t, 1 ); - char *request; - void *ret; - - if( !url_set( url, url_string ) ) - { - g_free( url ); - return NULL; - } - - if( url->proto != PROTO_HTTP && url->proto != PROTO_HTTPS ) - { - g_free( url ); - return NULL; - } - - request = g_strdup_printf( "GET %s HTTP/1.0\r\n" - "Host: %s\r\n" - "User-Agent: BitlBee " BITLBEE_VERSION " " ARCH "/" CPU "\r\n" - "\r\n", url->file, url->host ); - - ret = http_dorequest( url->host, url->port, - url->proto == PROTO_HTTPS, request, func, data ); - - g_free( url ); - g_free( request ); - return ret; -} - -/* This one is actually pretty simple... Might get more calls if we can't write - the whole request at once. */ -static gboolean http_connected( gpointer data, int source, b_input_condition cond ) -{ - struct http_request *req = data; - int st; - - if( source < 0 ) - goto error; - - if( req->inpa > 0 ) - b_event_remove( req->inpa ); - - sock_make_nonblocking( req->fd ); - - if( req->ssl ) - { - st = ssl_write( req->ssl, req->request + req->bytes_written, - req->request_length - req->bytes_written ); - if( st < 0 ) - { - if( ssl_errno != SSL_AGAIN ) - { - ssl_disconnect( req->ssl ); - goto error; - } - } - } - else - { - st = write( source, req->request + req->bytes_written, - req->request_length - req->bytes_written ); - if( st < 0 ) - { - if( !sockerr_again() ) - { - closesocket( req->fd ); - goto error; - } - } - } - - if( st > 0 ) - req->bytes_written += st; - - if( req->bytes_written < req->request_length ) - req->inpa = b_input_add( source, - req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_WRITE, - http_connected, req ); - else - req->inpa = b_input_add( source, GAIM_INPUT_READ, http_incoming_data, req ); - - return FALSE; - -error: - req->status_string = g_strdup( "Error while writing HTTP request" ); - - req->func( req ); - - g_free( req->request ); - g_free( req ); - - return FALSE; -} - -static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond ) -{ - struct http_request *req = data; - - if( source == NULL ) - return http_connected( data, -1, cond ); - - req->fd = ssl_getfd( source ); - - return http_connected( data, req->fd, cond ); -} - -static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond ) -{ - struct http_request *req = data; - int evil_server = 0; - char buffer[2048]; - char *end1, *end2; - int st; - - if( req->inpa > 0 ) - b_event_remove( req->inpa ); - - if( req->ssl ) - { - st = ssl_read( req->ssl, buffer, sizeof( buffer ) ); - if( st < 0 ) - { - if( ssl_errno != SSL_AGAIN ) - { - /* goto cleanup; */ - - /* YAY! We have to deal with crappy Microsoft - servers that LOVE to send invalid TLS - packets that abort connections! \o/ */ - - goto got_reply; - } - } - else if( st == 0 ) - { - goto got_reply; - } - } - else - { - st = read( req->fd, buffer, sizeof( buffer ) ); - if( st < 0 ) - { - if( !sockerr_again() ) - { - req->status_string = g_strdup( strerror( errno ) ); - goto cleanup; - } - } - else if( st == 0 ) - { - goto got_reply; - } - } - - if( st > 0 ) - { - req->reply_headers = g_realloc( req->reply_headers, req->bytes_read + st + 1 ); - memcpy( req->reply_headers + req->bytes_read, buffer, st ); - req->bytes_read += st; - } - - /* There will be more! */ - req->inpa = b_input_add( req->fd, - req->ssl ? ssl_getdirection( req->ssl ) : GAIM_INPUT_READ, - http_incoming_data, req ); - - return FALSE; - -got_reply: - /* Maybe if the webserver is overloaded, or when there's bad SSL - support... */ - if( req->bytes_read == 0 ) - { - req->status_string = g_strdup( "Empty HTTP reply" ); - goto cleanup; - } - - /* Zero termination is very convenient. */ - req->reply_headers[req->bytes_read] = 0; - - /* Find the separation between headers and body, and keep stupid - webservers in mind. */ - end1 = strstr( req->reply_headers, "\r\n\r\n" ); - end2 = strstr( req->reply_headers, "\n\n" ); - - if( end2 && end2 < end1 ) - { - end1 = end2 + 1; - evil_server = 1; - } - else if( end1 ) - { - end1 += 2; - } - else - { - req->status_string = g_strdup( "Malformed HTTP reply" ); - goto cleanup; - } - - *end1 = 0; - - if( evil_server ) - req->reply_body = end1 + 1; - else - req->reply_body = end1 + 2; - - req->body_size = req->reply_headers + req->bytes_read - req->reply_body; - - if( ( end1 = strchr( req->reply_headers, ' ' ) ) != NULL ) - { - if( sscanf( end1 + 1, "%d", &req->status_code ) != 1 ) - { - req->status_string = g_strdup( "Can't parse status code" ); - req->status_code = -1; - } - else - { - char *eol; - - if( evil_server ) - eol = strchr( end1, '\n' ); - else - eol = strchr( end1, '\r' ); - - req->status_string = g_strndup( end1 + 1, eol - end1 - 1 ); - - /* Just to be sure... */ - if( ( eol = strchr( req->status_string, '\r' ) ) ) - *eol = 0; - if( ( eol = strchr( req->status_string, '\n' ) ) ) - *eol = 0; - } - } - else - { - req->status_string = g_strdup( "Can't locate status code" ); - req->status_code = -1; - } - - if( req->status_code == 301 || req->status_code == 302 ) - { - char *loc, *new_request, *new_host; - int error = 0, new_port, new_proto; - - /* We might fill it again, so let's not leak any memory. */ - g_free( req->status_string ); - req->status_string = NULL; - - loc = strstr( req->reply_headers, "\nLocation: " ); - if( loc == NULL ) /* We can't handle this redirect... */ - { - req->status_string = g_strdup( "Can't locate Location: header" ); - goto cleanup; - } - - loc += 11; - while( *loc == ' ' ) - loc ++; - - /* TODO/FIXME: Possibly have to handle relative redirections, - and rewrite Host: headers. Not necessary for now, it's - enough for passport authentication like this. */ - - if( *loc == '/' ) - { - /* Just a different pathname... */ - - /* Since we don't cache the servername, and since we - don't need this yet anyway, I won't implement it. */ - - req->status_string = g_strdup( "Can't handle recursive redirects" ); - - goto cleanup; - } - else - { - /* A whole URL */ - url_t *url; - char *s; - - s = strstr( loc, "\r\n" ); - if( s == NULL ) - goto cleanup; - - url = g_new0( url_t, 1 ); - *s = 0; - - if( !url_set( url, loc ) ) - { - req->status_string = g_strdup( "Malformed redirect URL" ); - g_free( url ); - goto cleanup; - } - - /* Okay, this isn't fun! We have to rebuild the request... :-( */ - new_request = g_malloc( req->request_length + strlen( url->file ) ); - - /* So, now I just allocated enough memory, so I'm - going to use strcat(), whether you like it or not. :-) */ - - sprintf( new_request, "GET %s HTTP/1.0", url->file ); - - s = strstr( req->request, "\r\n" ); - if( s == NULL ) - { - req->status_string = g_strdup( "Error while rebuilding request string" ); - g_free( new_request ); - g_free( url ); - goto cleanup; - } - - strcat( new_request, s ); - new_host = g_strdup( url->host ); - new_port = url->port; - new_proto = url->proto; - - g_free( url ); - } - - if( req->ssl ) - ssl_disconnect( req->ssl ); - else - closesocket( req->fd ); - - req->fd = -1; - req->ssl = NULL; - - if( new_proto == PROTO_HTTPS ) - { - req->ssl = ssl_connect( new_host, new_port, http_ssl_connected, req ); - if( req->ssl == NULL ) - error = 1; - } - else - { - req->fd = proxy_connect( new_host, new_port, http_connected, req ); - if( req->fd < 0 ) - error = 1; - } - g_free( new_host ); - - if( error ) - { - req->status_string = g_strdup( "Connection problem during redirect" ); - g_free( new_request ); - goto cleanup; - } - - g_free( req->request ); - g_free( req->reply_headers ); - req->request = new_request; - req->request_length = strlen( new_request ); - req->bytes_read = req->bytes_written = req->inpa = 0; - req->reply_headers = req->reply_body = NULL; - - return FALSE; - } - - /* Assume that a closed connection means we're finished, this indeed - breaks with keep-alive connections and faulty connections. */ - req->finished = 1; - -cleanup: - if( req->ssl ) - ssl_disconnect( req->ssl ); - else - closesocket( req->fd ); - - req->func( req ); - - g_free( req->request ); - g_free( req->reply_headers ); - g_free( req->status_string ); - g_free( req ); - - return FALSE; -} diff --git a/protocols/http_client.h b/protocols/http_client.h deleted file mode 100644 index 50ee80cf..00000000 --- a/protocols/http_client.h +++ /dev/null @@ -1,57 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2005 Wilmer van der Gaast and others * - \********************************************************************/ - -/* HTTP(S) module */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include - -#include "ssl_client.h" - -struct http_request; - -typedef void (*http_input_function)( struct http_request * ); - -struct http_request -{ - char *request; - int request_length; - int status_code; - char *status_string; - char *reply_headers; - char *reply_body; - int body_size; - int finished; - - void *ssl; - int fd; - - int inpa; - int bytes_written; - int bytes_read; - - http_input_function func; - gpointer data; -}; - -void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); -void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/protocols/md5.c b/protocols/md5.c deleted file mode 100644 index e6273585..00000000 --- a/protocols/md5.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - Copyright (C) 1999 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321. - It is derived directly from the text of the RFC and not from the - reference implementation. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -#include "md5.h" -#include - -#ifdef TEST -/* - * Compile with -DTEST to create a self-contained executable test program. - * The test program should print out the same values as given in section - * A.5 of RFC 1321, reproduced below. - */ -#include -main() -{ - static const char *const test[7] = { - "", /*d41d8cd98f00b204e9800998ecf8427e*/ - "945399884.61923487334tuvga", /*0cc175b9c0f1b6a831c399e269772661*/ - "abc", /*900150983cd24fb0d6963f7d28e17f72*/ - "message digest", /*f96b697d7cb7938d525a2f31aaf161d0*/ - "abcdefghijklmnopqrstuvwxyz", /*c3fcd3d76192e4007dfb496cca67e13b*/ - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - /*d174ab98d277d9f5a5611c2c9f419d9f*/ - "12345678901234567890123456789012345678901234567890123456789012345678901234567890" /*57edf4a22be3c955ac49da2e2107b67a*/ - }; - int i; - - for (i = 0; i < 7; ++i) { - md5_state_t state; - md5_byte_t digest[16]; - int di; - - md5_init(&state); - md5_append(&state, (const md5_byte_t *)test[i], strlen(test[i])); - md5_finish(&state, digest); - printf("MD5 (\"%s\") = ", test[i]); - for (di = 0; di < 16; ++di) - printf("%02x", digest[di]); - printf("\n"); - } - return 0; -} -#endif /* TEST */ - - -/* - * For reference, here is the program that computed the T values. - */ -#if 0 -#include -main() -{ - int i; - for (i = 1; i <= 64; ++i) { - unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i))); - printf("#define T%d 0x%08lx\n", i, v); - } - return 0; -} -#endif -/* - * End of T computation program. - */ -#define T1 0xd76aa478 -#define T2 0xe8c7b756 -#define T3 0x242070db -#define T4 0xc1bdceee -#define T5 0xf57c0faf -#define T6 0x4787c62a -#define T7 0xa8304613 -#define T8 0xfd469501 -#define T9 0x698098d8 -#define T10 0x8b44f7af -#define T11 0xffff5bb1 -#define T12 0x895cd7be -#define T13 0x6b901122 -#define T14 0xfd987193 -#define T15 0xa679438e -#define T16 0x49b40821 -#define T17 0xf61e2562 -#define T18 0xc040b340 -#define T19 0x265e5a51 -#define T20 0xe9b6c7aa -#define T21 0xd62f105d -#define T22 0x02441453 -#define T23 0xd8a1e681 -#define T24 0xe7d3fbc8 -#define T25 0x21e1cde6 -#define T26 0xc33707d6 -#define T27 0xf4d50d87 -#define T28 0x455a14ed -#define T29 0xa9e3e905 -#define T30 0xfcefa3f8 -#define T31 0x676f02d9 -#define T32 0x8d2a4c8a -#define T33 0xfffa3942 -#define T34 0x8771f681 -#define T35 0x6d9d6122 -#define T36 0xfde5380c -#define T37 0xa4beea44 -#define T38 0x4bdecfa9 -#define T39 0xf6bb4b60 -#define T40 0xbebfbc70 -#define T41 0x289b7ec6 -#define T42 0xeaa127fa -#define T43 0xd4ef3085 -#define T44 0x04881d05 -#define T45 0xd9d4d039 -#define T46 0xe6db99e5 -#define T47 0x1fa27cf8 -#define T48 0xc4ac5665 -#define T49 0xf4292244 -#define T50 0x432aff97 -#define T51 0xab9423a7 -#define T52 0xfc93a039 -#define T53 0x655b59c3 -#define T54 0x8f0ccc92 -#define T55 0xffeff47d -#define T56 0x85845dd1 -#define T57 0x6fa87e4f -#define T58 0xfe2ce6e0 -#define T59 0xa3014314 -#define T60 0x4e0811a1 -#define T61 0xf7537e82 -#define T62 0xbd3af235 -#define T63 0x2ad7d2bb -#define T64 0xeb86d391 - -static void -md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) -{ - md5_word_t - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - md5_word_t t; - -#ifndef ARCH_IS_BIG_ENDIAN -# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */ -#endif -#if ARCH_IS_BIG_ENDIAN - - /* - * On big-endian machines, we must arrange the bytes in the right - * order. (This also works on machines of unknown byte order.) - */ - md5_word_t X[16]; - const md5_byte_t *xp = data; - int i; - - for (i = 0; i < 16; ++i, xp += 4) - X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - -#else /* !ARCH_IS_BIG_ENDIAN */ - - /* - * On little-endian machines, we can process properly aligned data - * without copying it. - */ - md5_word_t xbuf[16]; - const md5_word_t *X; - - if (!((data - (const md5_byte_t *)0) & 3)) { - /* data are properly aligned */ - X = (const md5_word_t *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } -#endif - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + F(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 7, T1); - SET(d, a, b, c, 1, 12, T2); - SET(c, d, a, b, 2, 17, T3); - SET(b, c, d, a, 3, 22, T4); - SET(a, b, c, d, 4, 7, T5); - SET(d, a, b, c, 5, 12, T6); - SET(c, d, a, b, 6, 17, T7); - SET(b, c, d, a, 7, 22, T8); - SET(a, b, c, d, 8, 7, T9); - SET(d, a, b, c, 9, 12, T10); - SET(c, d, a, b, 10, 17, T11); - SET(b, c, d, a, 11, 22, T12); - SET(a, b, c, d, 12, 7, T13); - SET(d, a, b, c, 13, 12, T14); - SET(c, d, a, b, 14, 17, T15); - SET(b, c, d, a, 15, 22, T16); -#undef SET - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + G(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 1, 5, T17); - SET(d, a, b, c, 6, 9, T18); - SET(c, d, a, b, 11, 14, T19); - SET(b, c, d, a, 0, 20, T20); - SET(a, b, c, d, 5, 5, T21); - SET(d, a, b, c, 10, 9, T22); - SET(c, d, a, b, 15, 14, T23); - SET(b, c, d, a, 4, 20, T24); - SET(a, b, c, d, 9, 5, T25); - SET(d, a, b, c, 14, 9, T26); - SET(c, d, a, b, 3, 14, T27); - SET(b, c, d, a, 8, 20, T28); - SET(a, b, c, d, 13, 5, T29); - SET(d, a, b, c, 2, 9, T30); - SET(c, d, a, b, 7, 14, T31); - SET(b, c, d, a, 12, 20, T32); -#undef SET - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + H(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 5, 4, T33); - SET(d, a, b, c, 8, 11, T34); - SET(c, d, a, b, 11, 16, T35); - SET(b, c, d, a, 14, 23, T36); - SET(a, b, c, d, 1, 4, T37); - SET(d, a, b, c, 4, 11, T38); - SET(c, d, a, b, 7, 16, T39); - SET(b, c, d, a, 10, 23, T40); - SET(a, b, c, d, 13, 4, T41); - SET(d, a, b, c, 0, 11, T42); - SET(c, d, a, b, 3, 16, T43); - SET(b, c, d, a, 6, 23, T44); - SET(a, b, c, d, 9, 4, T45); - SET(d, a, b, c, 12, 11, T46); - SET(c, d, a, b, 15, 16, T47); - SET(b, c, d, a, 2, 23, T48); -#undef SET - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti)\ - t = a + I(b,c,d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET(a, b, c, d, 0, 6, T49); - SET(d, a, b, c, 7, 10, T50); - SET(c, d, a, b, 14, 15, T51); - SET(b, c, d, a, 5, 21, T52); - SET(a, b, c, d, 12, 6, T53); - SET(d, a, b, c, 3, 10, T54); - SET(c, d, a, b, 10, 15, T55); - SET(b, c, d, a, 1, 21, T56); - SET(a, b, c, d, 8, 6, T57); - SET(d, a, b, c, 15, 10, T58); - SET(c, d, a, b, 6, 15, T59); - SET(b, c, d, a, 13, 21, T60); - SET(a, b, c, d, 4, 6, T61); - SET(d, a, b, c, 11, 10, T62); - SET(c, d, a, b, 2, 15, T63); - SET(b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -void -md5_init(md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = 0xefcdab89; - pms->abcd[2] = 0x98badcfe; - pms->abcd[3] = 0x10325476; -} - -void -md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) -{ - const md5_byte_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - md5_word_t nbits = (md5_word_t)(nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -void -md5_finish(md5_state_t *pms, md5_byte_t digest[16]) -{ - static const md5_byte_t pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - md5_byte_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/protocols/md5.h b/protocols/md5.h deleted file mode 100644 index f24f2ff1..00000000 --- a/protocols/md5.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - Copyright (C) 1999 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321. - It is derived directly from the text of the RFC and not from the - reference implementation. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2004-03-09 Jelmer Vernooij add G_MODULE_EXPORT for Bitlbee - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - -#ifndef md5_INCLUDED -# define md5_INCLUDED - -#include -#include - -/* - * This code has some adaptations for the Ghostscript environment, but it - * will compile and run correctly in any environment with 8-bit chars and - * 32-bit ints. Specifically, it assumes that if the following are - * defined, they have the same meaning as in Ghostscript: P1, P2, P3, - * ARCH_IS_BIG_ENDIAN. - */ - -typedef unsigned char md5_byte_t; /* 8-bit byte */ -typedef unsigned int md5_word_t; /* 32-bit word */ - -/* Define the state of the MD5 Algorithm. */ -typedef struct md5_state_s { - md5_word_t count[2]; /* message length in bits, lsw first */ - md5_word_t abcd[4]; /* digest buffer */ - md5_byte_t buf[64]; /* accumulate block */ -} md5_state_t; - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* Initialize the algorithm. */ -G_MODULE_EXPORT void md5_init(md5_state_t *pms); - -/* Append a string to the message. */ -G_MODULE_EXPORT void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); - -/* Finish the message and return the digest. */ -G_MODULE_EXPORT void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); - -#ifdef __cplusplus -} /* end extern "C" */ -#endif - -#endif /* md5_INCLUDED */ diff --git a/protocols/proxy.c b/protocols/proxy.c deleted file mode 100644 index b8aa304d..00000000 --- a/protocols/proxy.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * gaim - * - * Copyright (C) 1998-1999, Mark Spencer - * Copyright (C) 2002-2004, Wilmer van der Gaast, Jelmer Vernooij - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#define BITLBEE_CORE -#include -#include -#include -#include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#else -#include "sock.h" -#define ETIMEDOUT WSAETIMEDOUT -#define EINPROGRESS WSAEINPROGRESS -#endif -#include -#include -#include "nogaim.h" -#include "proxy.h" - -char proxyhost[128] = ""; -int proxyport = 0; -int proxytype = PROXY_NONE; -char proxyuser[128] = ""; -char proxypass[128] = ""; - -struct PHB { - b_event_handler func, proxy_func; - gpointer data, proxy_data; - char *host; - int port; - int fd; - gint inpa; -}; - - - -static struct sockaddr_in *gaim_gethostbyname(const char *host, int port) -{ - static struct sockaddr_in sin; - - if (!inet_aton(host, &sin.sin_addr)) { - struct hostent *hp; - if (!(hp = gethostbyname(host))) { - return NULL; - } - memset(&sin, 0, sizeof(struct sockaddr_in)); - memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); - sin.sin_family = hp->h_addrtype; - } else - sin.sin_family = AF_INET; - sin.sin_port = htons(port); - - return &sin; -} - -static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond) -{ - struct PHB *phb = data; - unsigned int len; - int error = ETIMEDOUT; - len = sizeof(error); - -#ifndef _WIN32 - if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - closesocket(source); - b_event_remove(phb->inpa); - if( phb->proxy_func ) - phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ); - else { - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb); - } - return FALSE; - } -#endif - sock_make_blocking(source); - b_event_remove(phb->inpa); - if( phb->proxy_func ) - phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); - else { - phb->func(phb->data, source, GAIM_INPUT_READ); - g_free(phb); - } - - return FALSE; -} - -static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb) -{ - struct sockaddr_in *sin; - int fd = -1; - - if (!(sin = gaim_gethostbyname(host, port))) { - g_free(phb); - return -1; - } - - if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) { - g_free(phb); - return -1; - } - - sock_make_nonblocking(fd); - - event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd); - - if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0) { - if (sockerr_again()) { - phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb); - phb->fd = fd; - } else { - closesocket(fd); - g_free(phb); - return -1; - } - } - - return fd; -} - - -/* Connecting to HTTP proxies */ - -#define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" -#define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" - -static gboolean http_canread(gpointer data, gint source, b_input_condition cond) -{ - int nlc = 0; - int pos = 0; - struct PHB *phb = data; - char inputline[8192]; - - b_event_remove(phb->inpa); - - while ((pos < sizeof(inputline)-1) && (nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { - if (inputline[pos - 1] == '\n') - nlc++; - else if (inputline[pos - 1] != '\r') - nlc = 0; - } - inputline[pos] = '\0'; - - if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || - (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { - phb->func(phb->data, source, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - - return FALSE; -} - -static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond) -{ - char cmd[384]; - struct PHB *phb = data; - unsigned int len; - int error = ETIMEDOUT; - if (phb->inpa > 0) - b_event_remove(phb->inpa); - len = sizeof(error); - if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - sock_make_blocking(source); - - g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, - phb->host, phb->port); - if (send(source, cmd, strlen(cmd), 0) < 0) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - if (proxyuser && *proxyuser) { - char *t1, *t2; - t1 = g_strdup_printf("%s:%s", proxyuser, proxypass); - t2 = tobase64(t1); - g_free(t1); - g_snprintf(cmd, sizeof(cmd), "Proxy-Authorization: Basic %s\r\n", t2); - g_free(t2); - if (send(source, cmd, strlen(cmd), 0) < 0) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - } - - g_snprintf(cmd, sizeof(cmd), "\r\n"); - if (send(source, cmd, strlen(cmd), 0) < 0) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb); - - return FALSE; -} - -static int proxy_connect_http(const char *host, unsigned short port, struct PHB *phb) -{ - phb->host = g_strdup(host); - phb->port = port; - phb->proxy_func = http_canwrite; - phb->proxy_data = phb; - - return( proxy_connect_none( proxyhost, proxyport, phb ) ); -} - - -/* Connecting to SOCKS4 proxies */ - -static gboolean s4_canread(gpointer data, gint source, b_input_condition cond) -{ - unsigned char packet[12]; - struct PHB *phb = data; - - b_event_remove(phb->inpa); - - memset(packet, 0, sizeof(packet)); - if (read(source, packet, 9) >= 4 && packet[1] == 90) { - phb->func(phb->data, source, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - - return FALSE; -} - -static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond) -{ - unsigned char packet[12]; - struct hostent *hp; - struct PHB *phb = data; - unsigned int len; - int error = ETIMEDOUT; - if (phb->inpa > 0) - b_event_remove(phb->inpa); - len = sizeof(error); - if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - sock_make_blocking(source); - - /* XXX does socks4 not support host name lookups by the proxy? */ - if (!(hp = gethostbyname(phb->host))) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - packet[0] = 4; - packet[1] = 1; - packet[2] = phb->port >> 8; - packet[3] = phb->port & 0xff; - packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; - packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; - packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; - packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; - packet[8] = 0; - if (write(source, packet, 9) != 9) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb); - - return FALSE; -} - -static int proxy_connect_socks4(const char *host, unsigned short port, struct PHB *phb) -{ - phb->host = g_strdup(host); - phb->port = port; - phb->proxy_func = s4_canwrite; - phb->proxy_data = phb; - - return( proxy_connect_none( proxyhost, proxyport, phb ) ); -} - - -/* Connecting to SOCKS5 proxies */ - -static gboolean s5_canread_again(gpointer data, gint source, b_input_condition cond) -{ - unsigned char buf[512]; - struct PHB *phb = data; - - b_event_remove(phb->inpa); - - if (read(source, buf, 10) < 10) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - if ((buf[0] != 0x05) || (buf[1] != 0x00)) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - phb->func(phb->data, source, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - - return FALSE; -} - -static void s5_sendconnect(gpointer data, gint source) -{ - unsigned char buf[512]; - struct PHB *phb = data; - int hlen = strlen(phb->host); - - buf[0] = 0x05; - buf[1] = 0x01; /* CONNECT */ - buf[2] = 0x00; /* reserved */ - buf[3] = 0x03; /* address type -- host name */ - buf[4] = hlen; - memcpy(buf + 5, phb->host, hlen); - buf[5 + strlen(phb->host)] = phb->port >> 8; - buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; - - if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return; - } - - phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb); -} - -static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond) -{ - unsigned char buf[512]; - struct PHB *phb = data; - - b_event_remove(phb->inpa); - - if (read(source, buf, 2) < 2) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - if ((buf[0] != 0x01) || (buf[1] != 0x00)) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - s5_sendconnect(phb, source); - - return FALSE; -} - -static gboolean s5_canread(gpointer data, gint source, b_input_condition cond) -{ - unsigned char buf[512]; - struct PHB *phb = data; - - b_event_remove(phb->inpa); - - if (read(source, buf, 2) < 2) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - if ((buf[0] != 0x05) || (buf[1] == 0xff)) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - if (buf[1] == 0x02) { - unsigned int i = strlen(proxyuser), j = strlen(proxypass); - buf[0] = 0x01; /* version 1 */ - buf[1] = i; - memcpy(buf + 2, proxyuser, i); - buf[2 + i] = j; - memcpy(buf + 2 + i + 1, proxypass, j); - if (write(source, buf, 3 + i + j) < 3 + i + j) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb); - } else { - s5_sendconnect(phb, source); - } - - return FALSE; -} - -static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond) -{ - unsigned char buf[512]; - int i; - struct PHB *phb = data; - unsigned int len; - int error = ETIMEDOUT; - if (phb->inpa > 0) - b_event_remove(phb->inpa); - len = sizeof(error); - if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - sock_make_blocking(source); - - i = 0; - buf[0] = 0x05; /* SOCKS version 5 */ - if (proxyuser[0]) { - buf[1] = 0x02; /* two methods */ - buf[2] = 0x00; /* no authentication */ - buf[3] = 0x02; /* username/password authentication */ - i = 4; - } else { - buf[1] = 0x01; - buf[2] = 0x00; - i = 3; - } - - if (write(source, buf, i) < i) { - close(source); - phb->func(phb->data, -1, GAIM_INPUT_READ); - g_free(phb->host); - g_free(phb); - return FALSE; - } - - phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb); - - return FALSE; -} - -static int proxy_connect_socks5(const char *host, unsigned short port, struct PHB *phb) -{ - phb->host = g_strdup(host); - phb->port = port; - phb->proxy_func = s5_canwrite; - phb->proxy_data = phb; - - return( proxy_connect_none( proxyhost, proxyport, phb ) ); -} - - -/* Export functions */ - -int proxy_connect(const char *host, int port, b_event_handler func, gpointer data) -{ - struct PHB *phb; - - if (!host || !port || (port == -1) || !func || strlen(host) > 128) { - return -1; - } - - phb = g_new0(struct PHB, 1); - phb->func = func; - phb->data = data; - -#ifndef _WIN32 - sethostent(1); -#endif - - if ((proxytype == PROXY_NONE) || !proxyhost || !proxyhost[0] || !proxyport || (proxyport == -1)) - return proxy_connect_none(host, port, phb); - else if (proxytype == PROXY_HTTP) - return proxy_connect_http(host, port, phb); - else if (proxytype == PROXY_SOCKS4) - return proxy_connect_socks4(host, port, phb); - else if (proxytype == PROXY_SOCKS5) - return proxy_connect_socks5(host, port, phb); - - if (phb->host) g_free(phb); - g_free(phb); - return -1; -} diff --git a/protocols/proxy.h b/protocols/proxy.h deleted file mode 100644 index 680790a5..00000000 --- a/protocols/proxy.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * nogaim - * - * Copyright (C) 1998-1999, Mark Spencer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* this is the export part of the proxy.c file. it does a little - prototype-ing stuff and redefine some net function to mask them - with some kind of transparent layer */ - -#ifndef _PROXY_H_ -#define _PROXY_H_ - -#include -#ifndef _WIN32 -#include -#include -#include -#endif -#include -#include - -#include "events.h" - -#define PROXY_NONE 0 -#define PROXY_HTTP 1 -#define PROXY_SOCKS4 2 -#define PROXY_SOCKS5 3 - -extern char proxyhost[128]; -extern int proxyport; -extern int proxytype; -extern char proxyuser[128]; -extern char proxypass[128]; - -G_MODULE_EXPORT int proxy_connect(const char *host, int port, b_event_handler func, gpointer data); - -#endif /* _PROXY_H_ */ diff --git a/protocols/sha.c b/protocols/sha.c deleted file mode 100644 index 895505a1..00000000 --- a/protocols/sha.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is SHA 180-1 Reference Implementation (Compact version) - * - * The Initial Developer of the Original Code is Paul Kocher of - * Cryptography Research. Portions created by Paul Kocher are - * Copyright (C) 1995-9 by Cryptography Research, Inc. All - * Rights Reserved. - * - * Contributor(s): - * - */ - -#define BITLBEE_CORE -#include "nogaim.h" - -static void shaHashBlock(SHA_CTX *ctx); - -void shaInit(SHA_CTX *ctx) { - int i; - - ctx->lenW = 0; - ctx->sizeHi = ctx->sizeLo = 0; - - /* Initialize H with the magic constants (see FIPS180 for constants) - */ - ctx->H[0] = 0x67452301L; - ctx->H[1] = 0xefcdab89L; - ctx->H[2] = 0x98badcfeL; - ctx->H[3] = 0x10325476L; - ctx->H[4] = 0xc3d2e1f0L; - - for (i = 0; i < 80; i++) - ctx->W[i] = 0; -} - - -void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len) { - int i; - - /* Read the data into W and process blocks as they get full - */ - for (i = 0; i < len; i++) { - ctx->W[ctx->lenW / 4] <<= 8; - ctx->W[ctx->lenW / 4] |= (guint32)dataIn[i]; - if ((++ctx->lenW) % 64 == 0) { - shaHashBlock(ctx); - ctx->lenW = 0; - } - ctx->sizeLo += 8; - ctx->sizeHi += (ctx->sizeLo < 8); - } -} - - -void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]) { - unsigned char pad0x80 = 0x80; - unsigned char pad0x00 = 0x00; - unsigned char padlen[8]; - int i; - - /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length - */ - padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255); - padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255); - padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255); - padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255); - padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255); - padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255); - padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255); - padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255); - shaUpdate(ctx, &pad0x80, 1); - while (ctx->lenW != 56) - shaUpdate(ctx, &pad0x00, 1); - shaUpdate(ctx, padlen, 8); - - /* Output hash - */ - for (i = 0; i < 20; i++) { - hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24); - ctx->H[i / 4] <<= 8; - } - - /* - * Re-initialize the context (also zeroizes contents) - */ - shaInit(ctx); -} - - -void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]) { - SHA_CTX ctx; - - shaInit(&ctx); - shaUpdate(&ctx, dataIn, len); - shaFinal(&ctx, hashout); -} - - -#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL) - -static void shaHashBlock(SHA_CTX *ctx) { - int t; - guint32 A,B,C,D,E,TEMP; - - for (t = 16; t <= 79; t++) - ctx->W[t] = - SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1); - - A = ctx->H[0]; - B = ctx->H[1]; - C = ctx->H[2]; - D = ctx->H[3]; - E = ctx->H[4]; - - for (t = 0; t <= 19; t++) { - TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 20; t <= 39; t++) { - TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 40; t <= 59; t++) { - TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - for (t = 60; t <= 79; t++) { - TEMP = (SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L) & 0xffffffffL; - E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP; - } - - ctx->H[0] += A; - ctx->H[1] += B; - ctx->H[2] += C; - ctx->H[3] += D; - ctx->H[4] += E; -} - -/*---------------------------------------------------------------------------- - * - * This code added by Thomas "temas" Muldowney for Jabber compatability - * - *---------------------------------------------------------------------------*/ -char *shahash(char *str) -{ - static char final[41]; - char *pos; - unsigned char hashval[20]; - int x; - - if(!str || strlen(str) == 0) - return NULL; - - shaBlock((unsigned char *)str, strlen(str), hashval); - - pos = final; - for(x=0;x<20;x++) - { - g_snprintf(pos, 3, "%02x", hashval[x]); - pos += 2; - } - return (char *)final; -} diff --git a/protocols/sha.h b/protocols/sha.h deleted file mode 100644 index e8152b1b..00000000 --- a/protocols/sha.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __SHA_H__ -#define __SHA_H__ - -#include - -G_MODULE_EXPORT int strprintsha(char *dest, int *hashval); - -typedef struct { - guint32 H[5]; - guint32 W[80]; - int lenW; - guint32 sizeHi,sizeLo; -} SHA_CTX; - -G_MODULE_EXPORT void shaInit(SHA_CTX *ctx); -G_MODULE_EXPORT void shaUpdate(SHA_CTX *ctx, unsigned char *dataIn, int len); -G_MODULE_EXPORT void shaFinal(SHA_CTX *ctx, unsigned char hashout[20]); -G_MODULE_EXPORT void shaBlock(unsigned char *dataIn, int len, unsigned char hashout[20]); -G_MODULE_EXPORT char *shahash(char *str); - -#endif diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c deleted file mode 100644 index 00aaa7c4..00000000 --- a/protocols/ssl_bogus.c +++ /dev/null @@ -1,57 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module - dummy version */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "ssl_client.h" - -int ssl_errno; - -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) -{ - return( NULL ); -} - -int ssl_read( void *conn, char *buf, int len ) -{ - return( -1 ); -} - -int ssl_write( void *conn, const char *buf, int len ) -{ - return( -1 ); -} - -void ssl_disconnect( void *conn_ ) -{ -} - -int ssl_getfd( void *conn ) -{ - return( -1 ); -} - -b_input_condition ssl_getdirection( void *conn ) -{ - return GAIM_INPUT_READ; -} diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h deleted file mode 100644 index 1a9c79e9..00000000 --- a/protocols/ssl_client.h +++ /dev/null @@ -1,42 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include "proxy.h" - -#define SSL_OK 0 -#define SSL_NOHANDSHAKE 1 -#define SSL_AGAIN 2 - -extern int ssl_errno; - -typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); - -G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); -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 ); -G_MODULE_EXPORT void ssl_disconnect( void *conn_ ); -G_MODULE_EXPORT int ssl_getfd( void *conn ); -G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c deleted file mode 100644 index 3ebe1756..00000000 --- a/protocols/ssl_gnutls.c +++ /dev/null @@ -1,206 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module - GnuTLS version */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include "proxy.h" -#include "ssl_client.h" -#include "sock.h" -#include "stdlib.h" - -int ssl_errno = 0; - -static gboolean initialized = FALSE; - -struct scd -{ - ssl_input_function func; - gpointer data; - int fd; - gboolean established; - int inpa; - - gnutls_session session; - gnutls_certificate_credentials xcred; -}; - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); - - -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 ); - } - - if( !initialized ) - { - gnutls_global_init(); - initialized = TRUE; - atexit( gnutls_global_deinit ); - } - - gnutls_certificate_allocate_credentials( &conn->xcred ); - gnutls_init( &conn->session, GNUTLS_CLIENT ); - gnutls_set_default_priority( conn->session ); - gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, conn->xcred ); - - return( conn ); -} - -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - - if( source == -1 ) - { - conn->func( conn->data, NULL, cond ); - - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); - - g_free( conn ); - - return FALSE; - } - - sock_make_nonblocking( conn->fd ); - gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); - - return ssl_handshake( data, source, cond ); -} - -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - int st; - - if( ( st = gnutls_handshake( conn->session ) ) < 0 ) - { - if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) - { - conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), - ssl_handshake, data ); - } - else - { - conn->func( conn->data, NULL, cond ); - - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); - closesocket( conn->fd ); - - g_free( conn ); - } - } - else - { - /* For now we can't handle non-blocking perfectly everywhere... */ - sock_make_blocking( conn->fd ); - - conn->established = TRUE; - conn->func( conn->data, conn, cond ); - } - - return FALSE; -} - -int ssl_read( void *conn, char *buf, int len ) -{ - int st; - - if( !((struct scd*)conn)->established ) - { - ssl_errno = SSL_NOHANDSHAKE; - return( -1 ); - } - - st = gnutls_record_recv( ((struct scd*)conn)->session, buf, len ); - - ssl_errno = SSL_OK; - if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) - ssl_errno = SSL_AGAIN; - - return st; -} - -int ssl_write( void *conn, const char *buf, int len ) -{ - int st; - - if( !((struct scd*)conn)->established ) - { - ssl_errno = SSL_NOHANDSHAKE; - return( -1 ); - } - - st = gnutls_record_send( ((struct scd*)conn)->session, buf, len ); - - ssl_errno = SSL_OK; - if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) - ssl_errno = SSL_AGAIN; - - return st; -} - -void ssl_disconnect( void *conn_ ) -{ - struct scd *conn = conn_; - - if( conn->inpa != -1 ) - b_event_remove( conn->inpa ); - - if( conn->established ) - gnutls_bye( conn->session, GNUTLS_SHUT_WR ); - - closesocket( conn->fd ); - - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); - g_free( conn ); -} - -int ssl_getfd( void *conn ) -{ - return( ((struct scd*)conn)->fd ); -} - -b_input_condition ssl_getdirection( void *conn ) -{ - return( gnutls_record_get_direction( ((struct scd*)conn)->session ) ? - GAIM_INPUT_WRITE : GAIM_INPUT_READ ); -} diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c deleted file mode 100644 index 218b3a80..00000000 --- a/protocols/ssl_nss.c +++ /dev/null @@ -1,190 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2005 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module - NSS version */ - -/* Copyright 2005 Jelmer Vernooij */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "bitlbee.h" -#include "proxy.h" -#include "ssl_client.h" -#include "sock.h" -#include -#include -#include -#include -#include -#include -#include -#include - -int ssl_errno = 0; - -static gboolean initialized = FALSE; - -struct scd -{ - ssl_input_function func; - gpointer data; - int fd; - PRFileDesc *prfd; - gboolean established; -}; - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); - - -static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver) -{ - return SECSuccess; -} - -static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket) -{ - PRErrorCode err; - - if(!arg) return SECFailure; - - *(PRErrorCode *)arg = err = PORT_GetError(); - - switch(err) { - case SEC_ERROR_INVALID_AVA: - case SEC_ERROR_INVALID_TIME: - case SEC_ERROR_BAD_SIGNATURE: - case SEC_ERROR_EXPIRED_CERTIFICATE: - case SEC_ERROR_UNKNOWN_ISSUER: - case SEC_ERROR_UNTRUSTED_CERT: - case SEC_ERROR_CERT_VALID: - case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: - case SEC_ERROR_CRL_EXPIRED: - case SEC_ERROR_CRL_BAD_SIGNATURE: - case SEC_ERROR_EXTENSION_VALUE_INVALID: - case SEC_ERROR_CA_CERT_INVALID: - case SEC_ERROR_CERT_USAGES_INVALID: - case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: - return SECSuccess; - - default: - return SECFailure; - } -} - - -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; - - if( conn->fd < 0 ) - { - g_free( conn ); - return( NULL ); - } - - if( !initialized ) - { - PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); - NSS_NoDB_Init(NULL); - NSS_SetDomesticPolicy(); - } - - - return( conn ); -} - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - - if( source == -1 ) - goto ssl_connected_failure; - - /* Until we find out how to handle non-blocking I/O with NSS... */ - sock_make_blocking( conn->fd ); - - conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source)); - SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE); - SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); - SSL_BadCertHook(conn->prfd, (SSLBadCertHandler)nss_bad_cert, NULL); - SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate)nss_auth_cert, (void *)CERT_GetDefaultCertDB()); - SSL_ResetHandshake(conn->prfd, PR_FALSE); - - if (SSL_ForceHandshake(conn->prfd)) { - goto ssl_connected_failure; - } - - - conn->established = TRUE; - conn->func( conn->data, conn, cond ); - return FALSE; - - ssl_connected_failure: - - conn->func( conn->data, NULL, cond ); - - PR_Close( conn -> prfd ); - if( source >= 0 ) closesocket( source ); - g_free( conn ); - - return FALSE; -} - -int ssl_read( void *conn, char *buf, int len ) -{ - if( !((struct scd*)conn)->established ) - return( 0 ); - - return( PR_Read( ((struct scd*)conn)->prfd, buf, len ) ); -} - -int ssl_write( void *conn, const char *buf, int len ) -{ - if( !((struct scd*)conn)->established ) - return( 0 ); - - return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) ); -} - -void ssl_disconnect( void *conn_ ) -{ - struct scd *conn = conn_; - - PR_Close( conn->prfd ); - closesocket( conn->fd ); - - g_free( conn ); -} - -int ssl_getfd( void *conn ) -{ - return( ((struct scd*)conn)->fd ); -} - -b_input_condition ssl_getdirection( void *conn ) -{ - /* Just in case someone calls us, let's return the most likely case: */ - return GAIM_INPUT_READ; -} diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c deleted file mode 100644 index b6f6c520..00000000 --- a/protocols/ssl_openssl.c +++ /dev/null @@ -1,221 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* SSL module - OpenSSL version */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include - -#include "proxy.h" -#include "ssl_client.h" -#include "sock.h" - -int ssl_errno = 0; - -static gboolean initialized = FALSE; - -struct scd -{ - ssl_input_function func; - gpointer data; - int fd; - gboolean established; - - int inpa; - int lasterr; /* Necessary for SSL_get_error */ - SSL *ssl; - SSL_CTX *ssl_ctx; -}; - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ); - - -void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ) -{ - struct scd *conn = g_new0( struct scd, 1 ); - SSL_METHOD *meth; - - conn->fd = proxy_connect( host, port, ssl_connected, conn ); - conn->func = func; - conn->data = data; - - if( conn->fd < 0 ) - { - g_free( conn ); - return( NULL ); - } - - if( !initialized ) - { - initialized = TRUE; - SSLeay_add_ssl_algorithms(); - } - - meth = TLSv1_client_method(); - conn->ssl_ctx = SSL_CTX_new( meth ); - if( conn->ssl_ctx == NULL ) - { - conn->fd = -1; - return( NULL ); - } - - conn->ssl = SSL_new( conn->ssl_ctx ); - if( conn->ssl == NULL ) - { - conn->fd = -1; - return( NULL ); - } - - return( conn ); -} - -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ); - -static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - - if( source == -1 ) - return ssl_handshake( data, -1, cond ); - - /* We can do at least the handshake with non-blocking I/O */ - sock_make_nonblocking( conn->fd ); - SSL_set_fd( conn->ssl, conn->fd ); - - return ssl_handshake( data, source, cond ); -} - -static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond ) -{ - struct scd *conn = data; - int st; - - if( ( st = SSL_connect( conn->ssl ) ) < 0 ) - { - conn->lasterr = SSL_get_error( conn->ssl, st ); - if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) - goto ssl_connected_failure; - - conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); - return FALSE; - } - - conn->established = TRUE; - sock_make_blocking( conn->fd ); /* For now... */ - conn->func( conn->data, conn, cond ); - return FALSE; - -ssl_connected_failure: - conn->func( conn->data, NULL, cond ); - - if( conn->ssl ) - { - SSL_shutdown( conn->ssl ); - SSL_free( conn->ssl ); - } - if( conn->ssl_ctx ) - { - SSL_CTX_free( conn->ssl_ctx ); - } - if( source >= 0 ) closesocket( source ); - g_free( conn ); - - return FALSE; -} - -int ssl_read( void *conn, char *buf, int len ) -{ - int st; - - if( !((struct scd*)conn)->established ) - { - ssl_errno = SSL_NOHANDSHAKE; - return -1; - } - - st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); - - ssl_errno = SSL_OK; - if( st <= 0 ) - { - ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); - if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) - ssl_errno = SSL_AGAIN; - } - - return st; -} - -int ssl_write( void *conn, const char *buf, int len ) -{ - int st; - - if( !((struct scd*)conn)->established ) - { - ssl_errno = SSL_NOHANDSHAKE; - return -1; - } - - st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); - - ssl_errno = SSL_OK; - if( st <= 0 ) - { - ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); - if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) - ssl_errno = SSL_AGAIN; - } - - return st; -} - -void ssl_disconnect( void *conn_ ) -{ - struct scd *conn = conn_; - - if( conn->inpa != -1 ) - b_event_remove( conn->inpa ); - - if( conn->established ) - SSL_shutdown( conn->ssl ); - - closesocket( conn->fd ); - - SSL_free( conn->ssl ); - SSL_CTX_free( conn->ssl_ctx ); - g_free( conn ); -} - -int ssl_getfd( void *conn ) -{ - return( ((struct scd*)conn)->fd ); -} - -b_input_condition ssl_getdirection( void *conn ) -{ - return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); -} diff --git a/url.c b/url.c deleted file mode 100644 index e4deac78..00000000 --- a/url.c +++ /dev/null @@ -1,107 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2001-2005 Wilmer van der Gaast and others * - \********************************************************************/ - -/* URL/mirror stuff - Stolen from Axel */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "url.h" - -/* Convert an URL to a url_t structure */ -int url_set( url_t *url, char *set_url ) -{ - char s[MAX_STRING]; - char *i; - - /* protocol:// */ - if( ( i = strstr( set_url, "://" ) ) == NULL ) - { - url->proto = PROTO_DEFAULT; - strncpy( s, set_url, MAX_STRING ); - } - else - { - if( g_strncasecmp( set_url, "http", i - set_url ) == 0 ) - url->proto = PROTO_HTTP; - else if( g_strncasecmp( set_url, "https", i - set_url ) == 0 ) - url->proto = PROTO_HTTPS; - else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 ) - url->proto = PROTO_SOCKS4; - else if( g_strncasecmp( set_url, "socks5", i - set_url ) == 0 ) - url->proto = PROTO_SOCKS5; - else - { - return( 0 ); - } - strncpy( s, i + 3, MAX_STRING ); - } - - /* Split */ - if( ( i = strchr( s, '/' ) ) == NULL ) - { - strcpy( url->file, "/" ); - } - else - { - strncpy( url->file, i, MAX_STRING ); - *i = 0; - } - strncpy( url->host, s, MAX_STRING ); - - /* Check for username in host field */ - if( strrchr( url->host, '@' ) != NULL ) - { - strncpy( url->user, url->host, MAX_STRING ); - i = strrchr( url->user, '@' ); - *i = 0; - strcpy( url->host, i + 1 ); - *url->pass = 0; - } - /* If not: Fill in defaults */ - else - { - *url->user = *url->pass = 0; - } - - /* Password? */ - if( ( i = strchr( url->user, ':' ) ) != NULL ) - { - *i = 0; - strcpy( url->pass, i + 1 ); - } - /* Port number? */ - if( ( i = strchr( url->host, ':' ) ) != NULL ) - { - *i = 0; - sscanf( i + 1, "%d", &url->port ); - } - else - { - if( url->proto == PROTO_HTTP ) - url->port = 80; - else if( url->proto == PROTO_HTTPS ) - url->port = 443; - else if( url->proto == PROTO_SOCKS4 || url->proto == PROTO_SOCKS4 ) - url->port = 1080; - } - - return( url->port > 0 ); -} diff --git a/url.h b/url.h deleted file mode 100644 index e9e1ecfe..00000000 --- a/url.h +++ /dev/null @@ -1,44 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2001-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* URL/mirror stuff - Stolen from Axel */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "bitlbee.h" - -#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]; -} url_t; - -int url_set( url_t *url, char *set_url ); diff --git a/util.c b/util.c deleted file mode 100644 index d8d6a4c7..00000000 --- a/util.c +++ /dev/null @@ -1,481 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* - * Various utility functions. Some are copied from Gaim to support the - * IM-modules, most are from BitlBee. - * - * Copyright (C) 1998-1999, Mark Spencer - * (and possibly other members of the Gaim team) - * Copyright 2002-2005 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 as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#define BITLBEE_CORE -#include "nogaim.h" -#include -#include -#include -#include -#include -#include - -void strip_linefeed(gchar *text) -{ - int i, j; - gchar *text2 = g_malloc(strlen(text) + 1); - - for (i = 0, j = 0; text[i]; i++) - if (text[i] != '\r') - text2[j++] = text[i]; - text2[j] = '\0'; - - strcpy(text, text2); - g_free(text2); -} - -char *add_cr(char *text) -{ - char *ret = NULL; - int count = 0, j; - unsigned int i; - - if (text[0] == '\n') - count++; - for (i = 1; i < strlen(text); i++) - if (text[i] == '\n' && text[i - 1] != '\r') - count++; - - if (count == 0) - return g_strdup(text); - - ret = g_malloc0(strlen(text) + count + 1); - - i = 0; j = 0; - if (text[i] == '\n') - ret[j++] = '\r'; - ret[j++] = text[i++]; - for (; i < strlen(text); i++) { - if (text[i] == '\n' && text[i - 1] != '\r') - ret[j++] = '\r'; - ret[j++] = text[i]; - } - - return ret; -} - -char *tobase64(const char *text) -{ - char *out; - int len; - - len = strlen(text); - out = g_malloc((len + 2) /* the == padding */ - / 3 /* every 3-byte block */ - * 4 /* becomes a 4-byte one */ - + 1); /* and of course, ASCIIZ! */ - - base64_encode_real(text, len, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); - - return out; -} - -void base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, char *b64digits) -{ - for (; inlen >= 3; inlen -= 3) - { - *out++ = b64digits[in[0] >> 2]; - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; - *out++ = b64digits[in[2] & 0x3f]; - in += 3; - } - if (inlen > 0) - { - *out++ = b64digits[in[0] >> 2]; - if (inlen > 1) - { - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[((in[1]<<2) & 0x3c)]; - } - else - { - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[64]; - } - *out++ = b64digits[64]; - } - *out = '\0'; -} - -char *normalize(const char *s) -{ - static char buf[BUF_LEN]; - char *t, *u; - int x = 0; - - g_return_val_if_fail((s != NULL), NULL); - - u = t = g_strdup(s); - - strcpy(t, s); - g_strdown(t); - - while (*t && (x < BUF_LEN - 1)) { - if (*t != ' ') { - buf[x] = *t; - x++; - } - t++; - } - buf[x] = '\0'; - g_free(u); - return buf; -} - -time_t get_time(int year, int month, int day, int hour, int min, int sec) -{ - struct tm tm; - - tm.tm_year = year - 1900; - tm.tm_mon = month - 1; - tm.tm_mday = day; - tm.tm_hour = hour; - tm.tm_min = min; - tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60; - return mktime(&tm); -} - -typedef struct htmlentity -{ - char code[8]; - char is[4]; -} htmlentity_t; - -/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */ - -static const htmlentity_t ent[] = -{ - { "lt", "<" }, - { "gt", ">" }, - { "amp", "&" }, - { "quot", "\"" }, - { "aacute", "á" }, - { "eacute", "é" }, - { "iacute", "é" }, - { "oacute", "ó" }, - { "uacute", "ú" }, - { "agrave", "à" }, - { "egrave", "è" }, - { "igrave", "ì" }, - { "ograve", "ò" }, - { "ugrave", "ù" }, - { "acirc", "â" }, - { "ecirc", "ê" }, - { "icirc", "î" }, - { "ocirc", "ô" }, - { "ucirc", "û" }, - { "auml", "ä" }, - { "euml", "ë" }, - { "iuml", "ï" }, - { "ouml", "ö" }, - { "uuml", "ü" }, - { "nbsp", " " }, - { "", "" } -}; - -void strip_html( char *in ) -{ - char *start = in; - char *out = g_malloc( strlen( in ) + 1 ); - char *s = out, *cs; - int i, matched; - - memset( out, 0, strlen( in ) + 1 ); - - while( *in ) - { - if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) ) - { - /* If in points at a < and in+1 points at a letter or a slash, this is probably - a HTML-tag. Try to find a closing > and continue there. If the > can't be - found, assume that it wasn't a HTML-tag after all. */ - - cs = in; - - while( *in && *in != '>' ) - in ++; - - if( *in ) - { - if( g_strncasecmp( cs+1, "br", 2) == 0 ) - *(s++) = '\n'; - in ++; - } - else - { - in = cs; - *(s++) = *(in++); - } - } - else if( *in == '&' ) - { - cs = ++in; - while( *in && isalpha( *in ) ) - in ++; - - if( *in == ';' ) in ++; - matched = 0; - - for( i = 0; *ent[i].code; i ++ ) - if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 ) - { - int j; - - for( j = 0; ent[i].is[j]; j ++ ) - *(s++) = ent[i].is[j]; - - matched = 1; - break; - } - - /* None of the entities were matched, so return the string */ - if( !matched ) - { - in = cs - 1; - *(s++) = *(in++); - } - } - else - { - *(s++) = *(in++); - } - } - - strcpy( start, out ); - g_free( out ); -} - -char *escape_html( const char *html ) -{ - const char *c = html; - GString *ret; - char *str; - - if( html == NULL ) - return( NULL ); - - ret = g_string_new( "" ); - - while( *c ) - { - switch( *c ) - { - case '&': - ret = g_string_append( ret, "&" ); - break; - case '<': - ret = g_string_append( ret, "<" ); - break; - case '>': - ret = g_string_append( ret, ">" ); - break; - case '"': - ret = g_string_append( ret, """ ); - break; - default: - ret = g_string_append_c( ret, *c ); - } - c ++; - } - - str = ret->str; - g_string_free( ret, FALSE ); - return( str ); -} - -void info_string_append(GString *str, char *newline, char *name, char *value) -{ - if( value && value[0] ) - g_string_sprintfa( str, "%s%s: %s", newline, name, value ); -} - -/* Decode%20a%20file%20name */ -void http_decode( char *s ) -{ - char *t; - int i, j, k; - - t = g_new( char, strlen( s ) + 1 ); - - for( i = j = 0; s[i]; i ++, j ++ ) - { - if( s[i] == '%' ) - { - if( sscanf( s + i + 1, "%2x", &k ) ) - { - t[j] = k; - i += 2; - } - else - { - *t = 0; - break; - } - } - else - { - t[j] = s[i]; - } - } - t[j] = 0; - - strcpy( s, t ); - g_free( t ); -} - -/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */ -/* This fuction is safe, but make sure you call it safely as well! */ -void http_encode( char *s ) -{ - char *t; - int i, j; - - t = g_strdup( s ); - - for( i = j = 0; t[i]; i ++, j ++ ) - { - /* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */ - if( !isalnum( t[i] ) ) - { - sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] ); - j += 2; - } - else - { - s[j] = t[i]; - } - } - s[j] = 0; - - g_free( t ); -} - -/* Strip newlines from a string. Modifies the string passed to it. */ -char *strip_newlines( char *source ) -{ - int i; - - for( i = 0; source[i] != '\0'; i ++ ) - if( source[i] == '\n' || source[i] == '\r' ) - source[i] = ' '; - - return source; -} - -#ifdef IPV6 -/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */ -char *ipv6_wrap( char *src ) -{ - static char dst[64]; - int i; - - for( i = 0; src[i]; i ++ ) - if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) - break; - - /* Hmm, it's not even an IP... */ - if( src[i] ) - return src; - - g_snprintf( dst, sizeof( dst ), "::ffff:%s", src ); - - return dst; -} - -/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */ -char *ipv6_unwrap( char *src ) -{ - int i; - - if( g_strncasecmp( src, "::ffff:", 7 ) != 0 ) - return src; - - for( i = 7; src[i]; i ++ ) - if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' ) - break; - - /* Hmm, it's not even an IP... */ - if( src[i] ) - return src; - - return ( src + 7 ); -} -#endif - -/* Convert from one charset to another. - - from_cs, to_cs: Source and destination charsets - src, dst: Source and destination strings - size: Size if src. 0 == use strlen(). strlen() is not reliable for UNICODE/UTF16 strings though. - maxbuf: Maximum number of bytes to write to dst - - Returns the number of bytes written to maxbuf or -1 on an error. -*/ -signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ) -{ - GIConv cd; - size_t res; - size_t inbytesleft, outbytesleft; - char *inbuf = src; - char *outbuf = dst; - - cd = g_iconv_open( to_cs, from_cs ); - if( cd == (GIConv) -1 ) - return( -1 ); - - inbytesleft = size ? size : strlen( src ); - outbytesleft = maxbuf - 1; - res = g_iconv( cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); - *outbuf = '\0'; - g_iconv_close( cd ); - - if( res == (size_t) -1 ) - return( -1 ); - else - return( outbuf - dst ); -} - -char *set_eval_charset( irc_t *irc, set_t *set, char *value ) -{ - GIConv cd; - - if ( g_strncasecmp( value, "none", 4 ) == 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/util.h b/util.h deleted file mode 100644 index c7eec19b..00000000 --- a/util.h +++ /dev/null @@ -1,51 +0,0 @@ - /********************************************************************\ - * BitlBee -- An IRC to other IM-networks gateway * - * * - * Copyright 2002-2004 Wilmer van der Gaast and others * - \********************************************************************/ - -/* Misc. functions */ - -/* - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License with - the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL; - if not, write to the Free Software Foundation, Inc., 59 Temple Place, - Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _UTIL_H -#define _UTIL_H - -G_MODULE_EXPORT void strip_linefeed( gchar *text ); -G_MODULE_EXPORT char *add_cr( char *text ); -G_MODULE_EXPORT char *strip_newlines(char *source); -G_MODULE_EXPORT char *tobase64( const char *text ); -G_MODULE_EXPORT void base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, char *b64digits ); -G_MODULE_EXPORT char *normalize( const char *s ); -G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); - -G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec ); -double gettime( void ); - -G_MODULE_EXPORT void strip_html( char *msg ); -G_MODULE_EXPORT char *escape_html( const char *html ); -G_MODULE_EXPORT void http_decode( char *s ); -G_MODULE_EXPORT void http_encode( char *s ); - -G_MODULE_EXPORT char *ipv6_wrap( char *src ); -G_MODULE_EXPORT char *ipv6_unwrap( char *src ); - -G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); -char *set_eval_charset( irc_t *irc, set_t *set, char *value ); - -#endif -- cgit v1.2.3 From 7ed3199067034b4fda4055778e02274f83bcfcb8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 16:07:01 +0200 Subject: Moved Base64-related functions to a separate file and added decode funtions. --- lib/Makefile | 2 +- lib/base64.c | 153 ++++++++++++++++++++++++++++++++++++++++++++ lib/base64.h | 33 ++++++++++ lib/misc.c | 44 ------------- lib/misc.h | 2 - lib/proxy.c | 1 + lib/rc4.c | 1 - lib/rc4.h | 1 - protocols/yahoo/libyahoo2.c | 4 +- 9 files changed, 191 insertions(+), 50 deletions(-) create mode 100644 lib/base64.c create mode 100644 lib/base64.h diff --git a/lib/Makefile b/lib/Makefile index 80cdd9a5..6408c5ba 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,7 +9,7 @@ -include ../Makefile.settings # [SH] Program variables -objects = $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o +objects = base64.o $(EVENT_HANDLER) http_client.o ini.o md5.o misc.o proxy.o rc4.o sha.o $(SSL_CLIENT) url.o CFLAGS += -Wall LFLAGS += -r diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 00000000..69069dae --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,153 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Base64 handling functions. encode_real() is mostly based on the y64 en- * +* coder from libyahoo2. Moving it to a new file because it's getting big. * +* * +* Copyright 2006 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 as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include +#include +#include "base64.h" + +static const char real_b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +char *tobase64(const char *text) +{ + return base64_encode(text, strlen(text)); +} + +char *base64_encode(const char *in, int len) +{ + char *out; + + out = g_malloc((len + 2) /* the == padding */ + / 3 /* every 3-byte block */ + * 4 /* becomes a 4-byte one */ + + 1); /* and of course, ASCIIZ! */ + + base64_encode_real((unsigned char*) in, len, (unsigned char*) out, real_b64); + + return out; +} + +int base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, const char *b64digits) +{ + int outlen = 0; + + for (; inlen >= 3; inlen -= 3) + { + out[outlen++] = b64digits[in[0] >> 2]; + out[outlen++] = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + out[outlen++] = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; + out[outlen++] = b64digits[in[2] & 0x3f]; + in += 3; + } + if (inlen > 0) + { + out[outlen++] = b64digits[in[0] >> 2]; + if (inlen > 1) + { + out[outlen++] = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; + out[outlen++] = b64digits[((in[1]<<2) & 0x3c)]; + } + else + { + out[outlen++] = b64digits[((in[0]<<4) & 0x30)]; + out[outlen++] = b64digits[64]; + } + out[outlen++] = b64digits[64]; + } + out[outlen] = 0; + + return outlen; +} + +/* Just a simple wrapper, but usually not very convenient because of zero + termination. */ +char *frombase64(const char *in) +{ + unsigned char *out; + + base64_decode(in, &out); + + return (char*) out; +} + +/* FIXME: Lookup table stuff is not threadsafe! (But for now BitlBee is not threaded.) */ +int base64_decode(const char *in, unsigned char **out) +{ + static char b64rev[256] = { 0 }; + int len, i; + + /* Create a reverse-lookup for the Base64 sequence. */ + if( b64rev[0] == 0 ) + { + memset( b64rev, 0xff, 256 ); + for( i = 0; i <= 64; i ++ ) + b64rev[(int)real_b64[i]] = i; + } + + len = strlen( in ); + *out = g_malloc( ( len + 6 ) / 4 * 3 ); + len = base64_decode_real( (unsigned char*) in, *out, b64rev ); + *out = g_realloc( *out, len + 1 ); + out[0][len] = 0; /* Zero termination can't hurt. */ + + return len; +} + +int base64_decode_real(const unsigned char *in, unsigned char *out, char *b64rev) +{ + int i, outlen = 0; + + for( i = 0; in[i]; i += 4 ) + { + int sx; + + sx = b64rev[(int)in[i+0]]; + if( sx >= 64 ) + break; + out[outlen] = ( sx << 2 ) & 0xfc; + + sx = b64rev[(int)in[i+1]]; + if( sx >= 64 ) + break; + out[outlen] |= ( sx >> 4 ) & 0x03; + outlen ++; + out[outlen] = ( sx << 4 ) & 0xf0; + + sx = b64rev[(int)in[i+2]]; + if( sx >= 64 ) + break; + out[outlen] |= ( sx >> 2 ) & 0x0f; + outlen ++; + out[outlen] = ( sx << 6 ) & 0xc0; + + sx = b64rev[(int)in[i+3]]; + if( sx >= 64 ) + break; + out[outlen] |= sx; + outlen ++; + } + + /* If sx > 64 the base64 string was damaged. Should we ignore this? */ + + return outlen; +} diff --git a/lib/base64.h b/lib/base64.h new file mode 100644 index 00000000..570f2b14 --- /dev/null +++ b/lib/base64.h @@ -0,0 +1,33 @@ +/***************************************************************************\ +* * +* BitlBee - An IRC to IM gateway * +* Base64 handling functions. encode_real() is mostly based on the y64 en- * +* coder from libyahoo2. Moving it to a new file because it's getting big. * +* * +* Copyright 2006 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 as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License along * +* with this program; if not, write to the Free Software Foundation, Inc., * +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* * +\***************************************************************************/ + +#include +#include + +G_MODULE_EXPORT char *tobase64( const char *text ); +G_MODULE_EXPORT char *base64_encode( const char *in, int len ); +G_MODULE_EXPORT int base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, const char *b64digits ); +G_MODULE_EXPORT char *frombase64( const char *in ); +G_MODULE_EXPORT int base64_decode( const char *in, unsigned char **out ); +G_MODULE_EXPORT int base64_decode_real( const unsigned char *in, unsigned char *out, char *b64reverse ); diff --git a/lib/misc.c b/lib/misc.c index d8d6a4c7..9f592289 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -83,50 +83,6 @@ char *add_cr(char *text) return ret; } -char *tobase64(const char *text) -{ - char *out; - int len; - - len = strlen(text); - out = g_malloc((len + 2) /* the == padding */ - / 3 /* every 3-byte block */ - * 4 /* becomes a 4-byte one */ - + 1); /* and of course, ASCIIZ! */ - - base64_encode_real(text, len, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="); - - return out; -} - -void base64_encode_real(const unsigned char *in, int inlen, unsigned char *out, char *b64digits) -{ - for (; inlen >= 3; inlen -= 3) - { - *out++ = b64digits[in[0] >> 2]; - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[((in[1]<<2) & 0x3c) | (in[2]>>6)]; - *out++ = b64digits[in[2] & 0x3f]; - in += 3; - } - if (inlen > 0) - { - *out++ = b64digits[in[0] >> 2]; - if (inlen > 1) - { - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[((in[1]<<2) & 0x3c)]; - } - else - { - *out++ = b64digits[((in[0]<<4) & 0x30) | (in[1]>>4)]; - *out++ = b64digits[64]; - } - *out++ = b64digits[64]; - } - *out = '\0'; -} - char *normalize(const char *s) { static char buf[BUF_LEN]; diff --git a/lib/misc.h b/lib/misc.h index c7eec19b..ed019bd8 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -29,8 +29,6 @@ G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); G_MODULE_EXPORT char *strip_newlines(char *source); -G_MODULE_EXPORT char *tobase64( const char *text ); -G_MODULE_EXPORT void base64_encode_real( const unsigned char *in, int inlen, unsigned char *out, char *b64digits ); G_MODULE_EXPORT char *normalize( const char *s ); G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value ); diff --git a/lib/proxy.c b/lib/proxy.c index b8aa304d..453cde91 100644 --- a/lib/proxy.c +++ b/lib/proxy.c @@ -40,6 +40,7 @@ #include #include "nogaim.h" #include "proxy.h" +#include "base64.h" char proxyhost[128] = ""; int proxyport = 0; diff --git a/lib/rc4.c b/lib/rc4.c index 3559f71e..2b732ba2 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -5,7 +5,6 @@ * * * Copyright 2006 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 as published by * * the Free Software Foundation; either version 2 of the License, or * diff --git a/lib/rc4.h b/lib/rc4.h index 8d50b508..6c9ea6b9 100644 --- a/lib/rc4.h +++ b/lib/rc4.h @@ -5,7 +5,6 @@ * * * Copyright 2006 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 as published by * * the Free Software Foundation; either version 2 of the License, or * diff --git a/protocols/yahoo/libyahoo2.c b/protocols/yahoo/libyahoo2.c index ee0f2f0e..69b63baa 100644 --- a/protocols/yahoo/libyahoo2.c +++ b/protocols/yahoo/libyahoo2.c @@ -89,6 +89,8 @@ char *strchr (), *strrchr (); #define vsnprintf _vsnprintf #endif +#include "base64.h" + #ifdef USE_STRUCT_CALLBACKS struct yahoo_callbacks *yc=NULL; @@ -697,7 +699,7 @@ static void yahoo_packet_dump(unsigned char *data, int len) /* raw bytes in quasi-big-endian order to base 64 string (NUL-terminated) */ static void to_y64(unsigned char *out, const unsigned char *in, int inlen) { - return base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"); + base64_encode_real(in, inlen, out, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"); } static void yahoo_add_to_send_queue(struct yahoo_input_data *yid, void *data, int length) -- cgit v1.2.3 From 6e1fed7057ee26f21b0e59a5aeb292d4f3f0e8ae Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 19:07:25 +0200 Subject: Using salted MD5 checksums for the user's BitlBee password and salted RC4 encryption for the IM account passwords, plus some calls to srand() to keep the salts secure and unique. --- bitlbee.c | 4 ++++ irc.c | 3 +-- storage_xml.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-------------- unix.c | 14 +++++------ 4 files changed, 70 insertions(+), 28 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index 1d4e2b34..cbad61dc 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -290,6 +290,10 @@ static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition { irc_t *irc; + /* Since we're fork()ing here, let's make sure we won't + get the same random numbers as the parent/siblings. */ + srand( time( NULL ) ^ getpid() ); + /* Close the listening socket, we're a client. */ close( global.listen_socket ); b_event_remove( global.listen_watch_source_id ); diff --git a/irc.c b/irc.c index c045d12b..b5751859 100644 --- a/irc.c +++ b/irc.c @@ -328,11 +328,10 @@ void irc_free(irc_t * irc) Sets pass without checking */ void irc_setpass (irc_t *irc, const char *pass) { - if (irc->password) g_free (irc->password); + g_free (irc->password); if (pass) { irc->password = g_strdup (pass); - irc_usermsg (irc, "Password successfully changed"); } else { irc->password = NULL; } diff --git a/storage_xml.c b/storage_xml.c index 41a50d8c..35d74935 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -25,6 +25,8 @@ #define BITLBEE_CORE #include "bitlbee.h" +#include "base64.h" +#include "rc4.h" #include "md5.h" typedef enum @@ -77,32 +79,32 @@ 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; 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 ) + { + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Error while decoding password attribute" ); + } else { md5_byte_t pass_md5[16]; md5_state_t md5_state; - int i, j; + 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( !isxdigit( pass[i*2] ) || !isxdigit( pass[i*2+1] ) || - sscanf( pass + i * 2, "%2x", &j ) != 1 ) - { - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - "Incorrect password MD5-hash" ); - break; - } - if( j != pass_md5[i] ) + if( pass_dec[i] != pass_md5[i] ) { g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, XML_PASS_ERRORMSG ); @@ -117,6 +119,8 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na xd->pass_st = XML_PASS_OK; } } + + g_free( pass_dec ); } else if( xd->pass_st < XML_PASS_OK ) { @@ -126,10 +130,12 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na else if( g_strcasecmp( element_name, "account" ) == 0 ) { char *protocol, *handle, *server, *password, *autoconnect; + char *pass_b64 = NULL, *pass_rc4 = NULL; + int pass_len; struct prpl *prpl = NULL; handle = xml_attr( attr_names, attr_values, "handle" ); - password = xml_attr( attr_names, attr_values, "password" ); + pass_b64 = xml_attr( attr_names, attr_values, "password" ); server = xml_attr( attr_names, attr_values, "server" ); autoconnect = xml_attr( attr_names, attr_values, "autoconnect" ); @@ -137,13 +143,15 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na if( protocol ) prpl = find_protocol( protocol ); - if( !handle || !password || !protocol ) + if( !handle || !pass_b64 || !protocol ) g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Missing attributes for %s element", element_name ); else if( !prpl ) g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Unknown protocol: %s", protocol ); - else + else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_rc4 ) ) && + rc4_decode( (unsigned char*) pass_rc4, pass_len, + (unsigned char**) &password, xd->given_pass ) ) { xd->current_account = account_add( irc, prpl, handle, password ); if( server ) @@ -153,6 +161,16 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na a default! */ sscanf( autoconnect, "%d", &xd->current_account->auto_connect ); } + else + { + /* Actually the _decode functions don't even return error codes, + but maybe they will later... */ + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Error while decrypting account password" ); + } + + g_free( pass_rc4 ); + g_free( password ); } else if( g_strcasecmp( element_name, "setting" ) == 0 ) { @@ -353,12 +371,12 @@ static int xml_printf( int fd, char *fmt, ... ) static storage_status_t xml_save( irc_t *irc, int overwrite ) { - char path[512], *path2, md5_buf[33]; + char path[512], *path2, *pass_buf = NULL; set_t *set; nick_t *nick; account_t *acc; int fd, i; - md5_byte_t pass_md5[16]; + md5_byte_t pass_md5[21]; md5_state_t md5_state; if( irc->password == NULL ) @@ -379,15 +397,23 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OTHER_ERROR; } + /* Generate a salted md5sum of the password. Use 5 bytes for the salt + (to prevent dictionary lookups of passwords) to end up with a 21- + byte password hash, more convenient for base64 encoding. */ + for( i = 0; i < 5; i ++ ) + pass_md5[16+i] = rand() & 0xff; md5_init( &md5_state ); md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) ); + md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */ md5_finish( &md5_state, pass_md5 ); - for( i = 0; i < 16; i ++ ) - g_snprintf( md5_buf + i * 2, 3, "%02x", pass_md5[i] ); + /* Save the hash in base64-encoded form. */ + pass_buf = base64_encode( (char*) pass_md5, 21 ); - if( !xml_printf( fd, "\n", irc->nick, md5_buf ) ) + if( !xml_printf( fd, "\n", irc->nick, pass_buf ) ) goto write_error; + g_free( pass_buf ); + for( set = irc->set; set; set = set->next ) if( set->value && set->def ) if( !xml_printf( fd, "\t%s\n", set->key, set->value ) ) @@ -395,8 +421,21 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) for( acc = irc->accounts; acc; acc = acc->next ) { - if( !xml_printf( fd, "\tprpl->name, acc->user, acc->pass, acc->auto_connect ) ) + char *pass_rc4, *pass_b64; + int pass_len; + + pass_len = rc4_encode( (unsigned char*) acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password ); + pass_b64 = base64_encode( pass_rc4, pass_len ); + + if( !xml_printf( fd, "\tprpl->name, acc->user, pass_b64, acc->auto_connect ) ) + { + g_free( pass_rc4 ); + g_free( pass_b64 ); goto write_error; + } + g_free( pass_rc4 ); + g_free( pass_b64 ); + if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) goto write_error; if( !xml_printf( fd, ">\n" ) ) @@ -432,6 +471,8 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OK; write_error: + g_free( pass_buf ); + irc_usermsg( irc, "Write error. Disk full?" ); close( fd ); diff --git a/unix.c b/unix.c index 360281ee..23ae1b91 100644 --- a/unix.c +++ b/unix.c @@ -47,20 +47,18 @@ int main( int argc, char *argv[], char **envp ) memset( &global, 0, sizeof( global_t ) ); b_main_init(); - log_init(); - nogaim_init(); - - CONF_FILE = g_strdup( CONF_FILE_DEF ); + srand( time( NULL ) ^ getpid() ); + + CONF_FILE = g_strdup( CONF_FILE_DEF ); global.helpfile = g_strdup( HELP_FILE ); - + global.conf = conf_load( argc, argv ); if( global.conf == NULL ) return( 1 ); - - + if( global.conf->runmode == RUNMODE_INETD ) { i = bitlbee_inetd_init(); @@ -88,7 +86,7 @@ int main( int argc, char *argv[], char **envp ) } if( i != 0 ) return( i ); - + global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage ); if ( global.storage == NULL) { log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage ); -- cgit v1.2.3 From 88086dbd9002123be39d00c53460f1ec9f2b719a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 19:23:27 +0200 Subject: Added versioning information to the XML-file (convenient for later format changes), got rid of confusing "Password successfully changed" message when the user uses the identify-command and protected rc4_decode() against short inputs. --- irc.c | 7 ++++--- lib/rc4.c | 6 ++++++ storage_xml.c | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/irc.c b/irc.c index b5751859..c07a3ea3 100644 --- a/irc.c +++ b/irc.c @@ -32,10 +32,11 @@ static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond ); GSList *irc_connection_list = NULL; -static char *passchange (irc_t *irc, void *set, char *value) +static char *passchange( irc_t *irc, void *set, char *value ) { - irc_setpass (irc, value); - return (NULL); + irc_setpass( irc, value ); + irc_usermsg( irc, "Password successfully changed" ); + return NULL; } irc_t *irc_new( int fd ) diff --git a/lib/rc4.c b/lib/rc4.c index 2b732ba2..cbe0e2c0 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -157,6 +157,12 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char key_len = strlen( password ) + RC4_IV_LEN; clear_len = crypt_len - RC4_IV_LEN; + if( clear_len < 0 ) + { + *clear = g_strdup( "" ); + return 0; + } + /* Prepare buffers and the key + IV */ *clear = g_malloc( clear_len + 1 ); key = g_malloc( key_len ); diff --git a/storage_xml.c b/storage_xml.c index 35d74935..0bbcd99a 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -39,6 +39,7 @@ typedef enum /* This isn't very clean, probably making a separate error class + code for BitlBee would be a better solution. But this will work for now... */ #define XML_PASS_ERRORMSG "Wrong username or password" +#define XML_FORMAT_VERSION 1 struct xml_parsedata { @@ -409,7 +410,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* Save the hash in base64-encoded form. */ pass_buf = base64_encode( (char*) pass_md5, 21 ); - if( !xml_printf( fd, "\n", irc->nick, pass_buf ) ) + if( !xml_printf( fd, "\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) goto write_error; g_free( pass_buf ); -- cgit v1.2.3 From 6ee9d2d65ec05d3871e69c2b03b860c6bdd509e9 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 25 Jun 2006 20:25:13 +0200 Subject: Forgot to initialize pass_rc4 (which caused memory management mess when trying to load a damaged XML-file). --- root_commands.c | 2 +- storage_xml.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/root_commands.c b/root_commands.c index d263bb84..e69b9981 100644 --- a/root_commands.c +++ b/root_commands.c @@ -138,7 +138,7 @@ static void cmd_identify( irc_t *irc, char **cmd ) irc_usermsg( irc, "The nick is (probably) not registered" ); break; case STORAGE_OK: - irc_usermsg( irc, "Password accepted" ); + irc_usermsg( irc, "Password accepted, settings and accounts loaded" ); irc_umode_set( irc, "+R", 1 ); break; case STORAGE_OTHER_ERROR: diff --git a/storage_xml.c b/storage_xml.c index 0bbcd99a..7d72c781 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -130,7 +130,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else if( g_strcasecmp( element_name, "account" ) == 0 ) { - char *protocol, *handle, *server, *password, *autoconnect; + char *protocol, *handle, *server, *password = NULL, *autoconnect; char *pass_b64 = NULL, *pass_rc4 = NULL; int pass_len; struct prpl *prpl = NULL; -- cgit v1.2.3 From c9f0c79af4d1d02e3e37c3d98c0ed33355bce113 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Jun 2006 14:04:21 +0200 Subject: Implemented cleaner way of passing the "Incorrect password" error. --- storage_xml.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/storage_xml.c b/storage_xml.c index 7d72c781..20f3c6a9 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -33,12 +33,11 @@ typedef enum { XML_PASS_CHECK_ONLY = -1, XML_PASS_UNKNOWN = 0, + XML_PASS_WRONG, XML_PASS_OK } xml_pass_st; -/* This isn't very clean, probably making a separate error class + code for - BitlBee would be a better solution. But this will work for now... */ -#define XML_PASS_ERRORMSG "Wrong username or password" +/* To make it easier later when extending the format: */ #define XML_FORMAT_VERSION 1 struct xml_parsedata @@ -107,8 +106,9 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { 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, - XML_PASS_ERRORMSG ); + "Password mismatch" ); break; } } @@ -301,11 +301,12 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password { if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr ) { + xml_pass_st pass_st = xd->pass_st; + g_markup_parse_context_free( ctx ); close( fd ); - /* Slightly dirty... */ - if( gerr && strcmp( gerr->message, XML_PASS_ERRORMSG ) == 0 ) + if( pass_st == XML_PASS_WRONG ) { g_clear_error( &gerr ); return STORAGE_INVALID_PASSWORD; @@ -331,6 +332,7 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password irc->status |= USTATUS_IDENTIFIED; + /* TODO: This really shouldn't be here, I think... */ if( set_getint( irc, "auto_connect" ) ) { /* Can't do this directly because r_c_s alters the string */ -- cgit v1.2.3 From 90bbb0efeae19bcc6a1096d8c89fbf3981c83503 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 26 Jun 2006 18:50:47 +0200 Subject: Moved the call to "account on" to the right place. --- root_commands.c | 5 +++++ storage_text.c | 6 ------ storage_xml.c | 8 -------- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/root_commands.c b/root_commands.c index e69b9981..47143531 100644 --- a/root_commands.c +++ b/root_commands.c @@ -126,9 +126,12 @@ static void cmd_help( irc_t *irc, char **cmd ) } } +static void cmd_account( irc_t *irc, char **cmd ); + static void cmd_identify( irc_t *irc, char **cmd ) { storage_status_t status = storage_load( irc->nick, cmd[1], irc ); + char *account_on[] = { "account", "on", NULL }; switch (status) { case STORAGE_INVALID_PASSWORD: @@ -140,6 +143,8 @@ static void cmd_identify( irc_t *irc, char **cmd ) case STORAGE_OK: irc_usermsg( irc, "Password accepted, settings and accounts loaded" ); irc_umode_set( irc, "+R", 1 ); + if( set_getint( irc, "auto_connect" ) ) + cmd_account( irc, account_on ); break; case STORAGE_OTHER_ERROR: default: diff --git a/storage_text.c b/storage_text.c index 506c9f03..06d278aa 100644 --- a/storage_text.c +++ b/storage_text.c @@ -116,12 +116,6 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i } fclose( fp ); - if( set_getint( irc, "auto_connect" ) ) - { - strcpy( s, "account on" ); /* Can't do this directly because r_c_s alters the string */ - root_command_string( irc, ru, s, 0 ); - } - return STORAGE_OK; } diff --git a/storage_xml.c b/storage_xml.c index 20f3c6a9..cc3498af 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -332,14 +332,6 @@ static storage_status_t xml_load_real( const char *my_nick, const char *password irc->status |= USTATUS_IDENTIFIED; - /* TODO: This really shouldn't be here, I think... */ - if( set_getint( irc, "auto_connect" ) ) - { - /* Can't do this directly because r_c_s alters the string */ - strcpy( buf, "account on" ); - root_command_string( irc, NULL, buf, 0 ); - } - return STORAGE_OK; } -- cgit v1.2.3 From b3c467bc312114eb7cdd45e6bc36a3d87bee6064 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 28 Jun 2006 11:59:33 +0200 Subject: Cleaned up Makefiles + configure: Cleaning up bitlbee.pc, removed the second piece of libevent probing code that mysteriously appeared (?), better handling of storage backends, an SSL module is now always included (so BitlBee can be compiled again when building without MSN- and Jabber-support (http_client also depends on SSL libs and can't be disabled)), oh, and fixed a compiler warning. --- Makefile | 6 +-- configure | 179 +++++++++++++++++++++++++++----------------------------------- storage.c | 2 +- 3 files changed, 80 insertions(+), 107 deletions(-) diff --git a/Makefile b/Makefile index 36afa236..54e03401 100644 --- a/Makefile +++ b/Makefile @@ -9,12 +9,10 @@ -include Makefile.settings # Program variables -objects = 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_text.o storage_xml.o unix.o user.o +objects = 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_OBJS) unix.o user.o headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ini.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h url.h user.h protocols/http_client.h protocols/md5.h protocols/nogaim.h protocols/proxy.h protocols/sha.h protocols/ssl_client.h subdirs = protocols lib -objects += $(LDAP_OBJ) - # Expansion of variables subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o) CFLAGS += -Wall @@ -43,7 +41,7 @@ clean: $(subdirs) rm -f *.o $(OUTFILE) core utils/bitlbeed encode decode distclean: clean $(subdirs) - rm -f Makefile.settings config.h + rm -f Makefile.settings config.h bitlbee.pc find . -name 'DEADJOE' -o -name '*.orig' -o -name '*.rej' -o -name '*~' -exec rm -f {} \; check: diff --git a/configure b/configure index fc9caffe..7cc99b41 100755 --- a/configure +++ b/configure @@ -206,29 +206,6 @@ else fi echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings -if [ "$events" = "libevent" ]; then - if ! [ -e "${libevent}include/event.h" ]; then - echo - echo 'Warning: Could not find event.h, you might have to install it and/or specify' - echo 'its location using the --libevent= argument. (Example: If event.h is in' - echo '/usr/local/include and binaries are in /usr/local/lib: --libevent=/usr/local)' - fi - - echo '#define EVENTS_LIBEVENT' >> config.h - cat <>Makefile.settings -EFLAGS+=-levent -L${libevent}lib -CFLAGS+=-I${libevent}include -EOF -elif [ "$events" = "glib" ]; then - ## We already use glib anyway, so this is all we need (and in fact not even this, but just to be sure...): - echo '#define EVENTS_GLIB' >> config.h -else - echo - echo 'ERROR: Unknown event handler specified.' - exit 1 -fi -echo 'EVENT_HANDLER=events_'$events'.o' >> Makefile.settings - detect_gnutls() { if libgnutls-config --version > /dev/null 2> /dev/null; then @@ -276,78 +253,89 @@ EOF fi } -if [ "$msn" = 1 -o "$jabber" = 1 ]; then - if [ "$ssl" = "auto" ]; then - detect_gnutls - if [ "$ret" = "0" ]; then - detect_nss - fi; - elif [ "$ssl" = "gnutls" ]; then - detect_gnutls; - elif [ "$ssl" = "nss" ]; then - detect_nss; - elif [ "$ssl" = "openssl" ]; then - echo - echo 'No detection code exists for OpenSSL. Make sure that you have a complete' - echo 'install of OpenSSL (including devel/header files) before reporting' - echo 'compilation problems.' - echo - echo 'Also, keep in mind that the OpenSSL is, according to some people, not' - echo 'completely GPL-compatible. Using GnuTLS or NSS is recommended and better' - echo 'supported by us. However, on many BSD machines, OpenSSL can be considered' - echo 'part of the operating system, which makes it GPL-compatible.' - echo - echo 'For more info, see: http://www.openssl.org/support/faq.html#LEGAL2' - echo ' http://www.gnome.org/~markmc/openssl-and-the-gpl.html' - echo - echo 'Please note that distributing a BitlBee binary which links to OpenSSL is' - echo 'probably illegal. If you want to create and distribute a binary BitlBee' - echo 'package, you really should use GnuTLS or NSS instead.' - echo - echo 'Also, the OpenSSL license requires us to say this:' - echo ' * "This product includes software developed by the OpenSSL Project' - echo ' * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"' - - echo 'EFLAGS+=-lssl -lcrypto' >> Makefile.settings - - ret=1; - elif [ "$ssl" = "bogus" ]; then - echo - echo 'Using bogus SSL code. This will not make the MSN module work, but it will' - echo 'allow you to use the Jabber module - although without working SSL support.' - - ret=1; - else - echo - echo 'ERROR: Unknown SSL library specified.' - exit 1; +if [ "$ssl" = "auto" ]; then + detect_gnutls + if [ "$ret" = "0" ]; then + detect_nss fi +elif [ "$ssl" = "gnutls" ]; then + detect_gnutls +elif [ "$ssl" = "nss" ]; then + detect_nss +elif [ "$ssl" = "openssl" ]; then + echo + echo 'No detection code exists for OpenSSL. Make sure that you have a complete' + echo 'install of OpenSSL (including devel/header files) before reporting' + echo 'compilation problems.' + echo + echo 'Also, keep in mind that the OpenSSL is, according to some people, not' + echo 'completely GPL-compatible. Using GnuTLS or NSS is recommended and better' + echo 'supported by us. However, on many BSD machines, OpenSSL can be considered' + echo 'part of the operating system, which makes it GPL-compatible.' + echo + echo 'For more info, see: http://www.openssl.org/support/faq.html#LEGAL2' + echo ' http://www.gnome.org/~markmc/openssl-and-the-gpl.html' + echo + echo 'Please note that distributing a BitlBee binary which links to OpenSSL is' + echo 'probably illegal. If you want to create and distribute a binary BitlBee' + echo 'package, you really should use GnuTLS or NSS instead.' + echo + echo 'Also, the OpenSSL license requires us to say this:' + echo ' * "This product includes software developed by the OpenSSL Project' + echo ' * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"' - if [ "$ret" = "0" ]; then + echo 'EFLAGS+=-lssl -lcrypto' >> Makefile.settings + + ret=1 +elif [ "$ssl" = "bogus" ]; then + echo + echo 'Using bogus SSL code. This means some features have to be disabled.' + + ## Yes, you, at the console! How can you authenticate if you don't have any SSL!? + if [ "$msn" = "1" ]; then echo - echo 'ERROR: Could not find a suitable SSL library (GnuTLS, libnss or OpenSSL).' - echo ' This is necessary for MSN and full Jabber support. To continue,' - echo ' install a suitable SSL library or disable MSN support (--msn=0).' - echo ' If you want Jabber without SSL support you can try --ssl=bogus.' - - exit 1; - fi; + echo 'Real SSL support is necessary for MSN authentication, will build without' + echo 'MSN protocol support.' + msn=0 + fi - echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings + ret=1 +else + echo + echo 'ERROR: Unknown SSL library specified.' + exit 1 fi +if [ "$ret" = "0" ]; then + echo + echo 'ERROR: Could not find a suitable SSL library (GnuTLS, libnss or OpenSSL).' + echo ' Please note that this script doesn'\''t have detection code for OpenSSL,' + echo ' so if you want to use that, you have to select it by hand. If you don'\''t' + echo ' need SSL support, you can select the "bogus" SSL library. (--ssl=bogus)' + + exit 1 +fi; + +echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings + +STORAGES="text xml" + if [ "$ldap" = "auto" ]; then detect_ldap fi if [ "$ldap" = 0 ]; then - echo "LDAP_OBJ=" >> Makefile.settings echo "#undef WITH_LDAP" >> config.h elif [ "$ldap" = 1 ]; then echo "#define WITH_LDAP 1" >> config.h - echo "LDAP_OBJ=storage_ldap.o" >> Makefile.settings + STORAGES="$STORAGES ldap" fi +for i in $STORAGES; do + STORAGE_OBJS="$STORAGE_OBJS storage_$i.o" +done +echo "STORAGE_OBJS="$STORAGE_OBJS >> Makefile.settings + if [ "$strip" = 0 ]; then echo "STRIP=\# skip strip" >> Makefile.settings; else @@ -360,8 +348,6 @@ else echo "STRIP=$STRIP" >> Makefile.settings; elif type strip > /dev/null 2> /dev/null; then echo "STRIP=strip" >> Makefile.settings; - elif /bin/test -x /usr/ccs/bin/strip; then - echo "STRIP=/usr/ccs/bin/strip" >> Makefile.settings; else echo echo 'No strip utility found, cannot remove unnecessary parts from executable.' @@ -440,7 +426,7 @@ fi if [ "$protocols" = "PROTOCOLS = " ]; then echo "WARNING: You haven't selected any communication protocol to compile!" - echo " Bitlbee will run, but you will be unable to connect to IM servers!" + echo " BitlBee will run, but you will be unable to connect to IM servers!" fi echo "PROTOCOLS = $protocols" >> Makefile.settings @@ -475,34 +461,23 @@ echo echo 'Configuration done:' if [ "$debug" = "1" ]; then - echo ' Debugging enabled.'; + echo ' Debugging enabled.' else - echo ' Debugging disabled.'; + echo ' Debugging disabled.' fi if [ "$strip" = "1" ]; then - echo ' Binary stripping enabled.'; + echo ' Binary stripping enabled.' else - echo ' Binary stripping disabled.'; + echo ' Binary stripping disabled.' fi -echo ' Using event handler: '$events; -echo ' Using SSL library: '$ssl; - -#if [ "$flood" = "0" ]; then -# echo ' Flood protection disabled.'; -#else -# echo ' Flood protection enabled.'; -#fi +echo ' Using event handler: '$events +echo ' Using SSL library: '$ssl +echo ' Building with these storage backends: '$STORAGES if [ -n "$protocols" ]; then - echo ' Building with these protocols:' $protocols; -else - echo ' Building without IM-protocol support. We wish you a lot of fun...'; -fi - -if [ "$ldap" = "0" ]; then - echo " LDAP storage backend disabled." + echo ' Building with these protocols:' $protocols else - echo " LDAP storage backend enabled." + echo ' Building without IM-protocol support. We wish you a lot of fun...' fi diff --git a/storage.c b/storage.c index b8e07278..807d5bb4 100644 --- a/storage.c +++ b/storage.c @@ -42,7 +42,7 @@ void register_storage_backend(storage_t *backend) static storage_t *storage_init_single(const char *name) { GList *gl; - storage_t *st; + storage_t *st = NULL; for (gl = storage_backends; gl; gl = gl->next) { st = gl->data; -- cgit v1.2.3 From 171946457cccb7280f0918201093e79bbc9eac72 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 28 Jun 2006 16:47:05 +0200 Subject: Added random_bytes() function for better/more reliable randomization and moved set_eval_ops() to a slightly more suitable place. --- lib/misc.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++----------- lib/misc.h | 10 +++++--- lib/rc4.c | 9 +++++-- set.c | 14 +++++++++++ set.h | 4 +-- storage_xml.c | 5 ++-- 6 files changed, 96 insertions(+), 24 deletions(-) diff --git a/lib/misc.c b/lib/misc.c index 9f592289..784d80d6 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2006 Wilmer van der Gaast and others * \********************************************************************/ /* @@ -10,7 +10,7 @@ * * Copyright (C) 1998-1999, Mark Spencer * (and possibly other members of the Gaim team) - * Copyright 2002-2005 Wilmer van der Gaast + * Copyright 2002-2006 Wilmer van der Gaast */ /* @@ -421,17 +421,67 @@ signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t si return( outbuf - dst ); } -char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +/* A pretty reliable random number generator. Tries to use the /dev/random + devices first, and falls back to the random number generator from libc + when it fails. Opens randomizer devices with O_NONBLOCK to make sure a + lack of entropy won't halt BitlBee. */ +void random_bytes( unsigned char *buf, int count ) { - GIConv cd; - - if ( g_strncasecmp( value, "none", 4 ) == 0 ) - return( value ); - - cd = g_iconv_open( "UTF-8", value ); - if( cd == (GIConv) -1 ) - return( NULL ); - - g_iconv_close( cd ); - return( value ); + static int use_dev = -1; + + /* Actually this probing code isn't really necessary, is it? */ + if( use_dev == -1 ) + { + if( access( "/dev/random", R_OK ) == 0 || access( "/dev/urandom", R_OK ) == 0 ) + use_dev = 1; + else + { + use_dev = 0; + srand( ( getpid() << 16 ) ^ time( NULL ) ); + } + } + + if( use_dev ) + { + int fd; + + /* At least on Linux, /dev/random can block if there's not + enough entropy. We really don't want that, so if it can't + give anything, use /dev/urandom instead. */ + if( ( fd = open( "/dev/random", O_RDONLY | O_NONBLOCK ) ) >= 0 ) + if( read( fd, buf, count ) == count ) + { + close( fd ); + return; + } + close( fd ); + + /* urandom isn't supposed to block at all, but just to be + sure. If it blocks, we'll disable use_dev and use the libc + randomizer instead. */ + if( ( fd = open( "/dev/urandom", O_RDONLY | O_NONBLOCK ) ) >= 0 ) + if( read( fd, buf, count ) == count ) + { + close( fd ); + return; + } + close( fd ); + + /* If /dev/random blocks once, we'll still try to use it + again next time. If /dev/urandom also fails for some + reason, stick with libc during this session. */ + + use_dev = 0; + srand( ( getpid() << 16 ) ^ time( NULL ) ); + } + + if( !use_dev ) + { + int i; + + /* Possibly the LSB of rand() isn't very random on some + platforms. Seems okay on at least Linux and OSX though. */ + for( i = 0; i < count; i ++ ) + buf[i] = rand() & 0xff; + } } diff --git a/lib/misc.h b/lib/misc.h index ed019bd8..57ff3e37 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -23,8 +23,11 @@ Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _UTIL_H -#define _UTIL_H +#ifndef _MISC_H +#define _MISC_H + +#include +#include G_MODULE_EXPORT void strip_linefeed( gchar *text ); G_MODULE_EXPORT char *add_cr( char *text ); @@ -44,6 +47,7 @@ G_MODULE_EXPORT char *ipv6_wrap( char *src ); G_MODULE_EXPORT char *ipv6_unwrap( char *src ); G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char *dst, size_t size, size_t maxbuf ); -char *set_eval_charset( irc_t *irc, set_t *set, char *value ); + +G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); #endif diff --git a/lib/rc4.c b/lib/rc4.c index cbe0e2c0..86b74ef5 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -38,8 +38,10 @@ #include +#include #include #include +#include "misc.h" #include "rc4.h" /* Add some seed to the password, to make sure we *never* use the same key. @@ -133,8 +135,11 @@ int rc4_encode( unsigned char *clear, int clear_len, unsigned char **crypt, char *crypt = g_malloc( clear_len + RC4_IV_LEN ); key = g_malloc( key_len ); strcpy( (char*) key, password ); - for( i = 0; i < RC4_IV_LEN; i ++ ) - key[key_len-RC4_IV_LEN+i] = crypt[0][i] = rand() & 0xff; + + /* Add the salt. Save it for later (when decrypting) and, of course, + add it to the encryption key. */ + random_bytes( crypt[0], RC4_IV_LEN ); + memcpy( key + key_len - RC4_IV_LEN, crypt[0], RC4_IV_LEN ); /* Generate the initial S[] from the IVed key. */ st = rc4_keymaker( key, key_len, RC4_CYCLES ); diff --git a/set.c b/set.c index 60912e10..a26bc17b 100644 --- a/set.c +++ b/set.c @@ -223,3 +223,17 @@ char *set_eval_ops( irc_t *irc, set_t *set, char *value ) return( NULL ); } +char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +{ + GIConv cd; + + if ( g_strncasecmp( value, "none", 4 ) == 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 ebebf2d0..8a7b6747 100644 --- a/set.h +++ b/set.h @@ -46,7 +46,7 @@ void set_del( irc_t *irc, char *key ); char *set_eval_int( irc_t *irc, set_t *set, char *value ); char *set_eval_bool( irc_t *irc, set_t *set, char *value ); + char *set_eval_to_char( irc_t *irc, set_t *set, char *value ); char *set_eval_ops( irc_t *irc, set_t *set, char *value ); - - +char *set_eval_charset( irc_t *irc, set_t *set, char *value ); diff --git a/storage_xml.c b/storage_xml.c index cc3498af..5a8b51ef 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -370,7 +370,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) set_t *set; nick_t *nick; account_t *acc; - int fd, i; + int fd; md5_byte_t pass_md5[21]; md5_state_t md5_state; @@ -395,8 +395,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* Generate a salted md5sum of the password. Use 5 bytes for the salt (to prevent dictionary lookups of passwords) to end up with a 21- byte password hash, more convenient for base64 encoding. */ - for( i = 0; i < 5; i ++ ) - pass_md5[16+i] = rand() & 0xff; + random_bytes( pass_md5 + 16, 5 ); md5_init( &md5_state ); md5_append( &md5_state, (md5_byte_t*) irc->password, strlen( irc->password ) ); md5_append( &md5_state, pass_md5 + 16, 5 ); /* Add the salt. */ -- cgit v1.2.3 From 5c9512ffa716f2bc8bbf9e2c31ee40624a0ff842 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 30 Jun 2006 11:17:18 +0200 Subject: Made set.c API more generic so it's not specific to irc_t structures anymore, but can be used for account_t structures too, for example. --- conf.c | 2 +- irc.c | 58 ++++++++++++------------- irc_commands.c | 2 +- nick.c | 2 +- protocols/nogaim.c | 53 +++++++++++------------ protocols/nogaim.h | 2 +- query.c | 4 +- root_commands.c | 6 +-- set.c | 121 +++++++++++++++++++++++++---------------------------- set.h | 36 ++++++++-------- storage_xml.c | 5 +-- user.c | 2 +- 12 files changed, 143 insertions(+), 150 deletions(-) diff --git a/conf.c b/conf.c index d8b8be72..13f150a7 100644 --- a/conf.c +++ b/conf.c @@ -322,7 +322,7 @@ void conf_loaddefaults( irc_t *irc ) { if( g_strcasecmp( ini->section, "defaults" ) == 0 ) { - set_t *s = set_find( irc, ini->key ); + set_t *s = set_find( &irc->set, ini->key ); if( s ) { diff --git a/irc.c b/irc.c index f6e7cbb7..60769735 100644 --- a/irc.c +++ b/irc.c @@ -120,26 +120,26 @@ irc_t *irc_new( int fd ) irc_connection_list = g_slist_append( irc_connection_list, irc ); - set_add( irc, "away_devoice", "true", set_eval_away_devoice ); - set_add( irc, "auto_connect", "true", set_eval_bool ); - set_add( irc, "auto_reconnect", "false", set_eval_bool ); - set_add( irc, "auto_reconnect_delay", "300", set_eval_int ); - set_add( irc, "buddy_sendbuffer", "false", set_eval_bool ); - set_add( irc, "buddy_sendbuffer_delay", "200", set_eval_int ); - set_add( irc, "charset", "iso8859-1", set_eval_charset ); - set_add( irc, "debug", "false", set_eval_bool ); - set_add( irc, "default_target", "root", NULL ); - set_add( irc, "display_namechanges", "false", set_eval_bool ); - set_add( irc, "handle_unknown", "root", NULL ); - set_add( irc, "lcnicks", "true", set_eval_bool ); - set_add( irc, "ops", "both", set_eval_ops ); - set_add( irc, "private", "true", set_eval_bool ); - set_add( irc, "query_order", "lifo", NULL ); - set_add( irc, "save_on_quit", "true", set_eval_bool ); - set_add( irc, "strip_html", "true", NULL ); - set_add( irc, "to_char", ": ", set_eval_to_char ); - set_add( irc, "typing_notice", "false", set_eval_bool ); - set_add( irc, "password", NULL, passchange); + set_add( &irc->set, "away_devoice", "true", set_eval_away_devoice, irc ); + set_add( &irc->set, "auto_connect", "true", set_eval_bool, irc ); + set_add( &irc->set, "auto_reconnect", "false", set_eval_bool, irc ); + set_add( &irc->set, "auto_reconnect_delay", "300", set_eval_int, irc ); + set_add( &irc->set, "buddy_sendbuffer", "false", set_eval_bool, irc ); + set_add( &irc->set, "buddy_sendbuffer_delay", "200", set_eval_int, irc ); + set_add( &irc->set, "charset", "iso8859-1", set_eval_charset, irc ); + set_add( &irc->set, "debug", "false", set_eval_bool, irc ); + set_add( &irc->set, "default_target", "root", NULL, irc ); + set_add( &irc->set, "display_namechanges", "false", set_eval_bool, irc ); + set_add( &irc->set, "handle_unknown", "root", NULL, irc ); + set_add( &irc->set, "lcnicks", "true", set_eval_bool, irc ); + set_add( &irc->set, "ops", "both", set_eval_ops, irc ); + 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, "save_on_quit", "true", set_eval_bool, irc ); + set_add( &irc->set, "strip_html", "true", NULL, irc ); + set_add( &irc->set, "to_char", ": ", set_eval_to_char, irc ); + set_add( &irc->set, "typing_notice", "false", set_eval_bool, irc ); conf_loaddefaults( irc ); @@ -211,7 +211,7 @@ void irc_free(irc_t * irc) log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); - if( irc->status & USTATUS_IDENTIFIED && set_getint( irc, "save_on_quit" ) ) + if( irc->status & USTATUS_IDENTIFIED && set_getint( &irc->set, "save_on_quit" ) ) if( storage_save( irc, TRUE ) != STORAGE_OK ) irc_usermsg( irc, "Error while saving settings!" ); @@ -363,7 +363,7 @@ void irc_process( irc_t *irc ) break; } - if( ( cs = set_getstr( irc, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) { conv[IRC_MAX_LINE] = 0; if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) != -1 ) @@ -583,7 +583,7 @@ 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, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) + if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) ) { char conv[IRC_MAX_LINE+1]; @@ -665,7 +665,7 @@ void irc_names( irc_t *irc, char *channel ) { if( u->gc && control ) { - if( set_getint( irc, "away_devoice" ) && !u->away ) + if( set_getint( &irc->set, "away_devoice" ) && !u->away ) s = "+"; else s = ""; @@ -674,9 +674,9 @@ void irc_names( irc_t *irc, char *channel ) } else if( !u->gc ) { - if( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( set_getstr( irc, "ops" ), "root" ) == 0 || strcmp( set_getstr( irc, "ops" ), "both" ) == 0 ) ) + if( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( set_getstr( &irc->set, "ops" ), "root" ) == 0 || strcmp( set_getstr( &irc->set, "ops" ), "both" ) == 0 ) ) s = "@"; - else if( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( set_getstr( irc, "ops" ), "user" ) == 0 || strcmp( set_getstr( irc, "ops" ), "both" ) == 0 ) ) + else if( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( set_getstr( &irc->set, "ops" ), "user" ) == 0 || strcmp( set_getstr( &irc->set, "ops" ), "both" ) == 0 ) ) s = "@"; else s = ""; @@ -1083,7 +1083,7 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) { if( !u || !u->gc ) return; - if( set_getint( irc, "buddy_sendbuffer" ) && set_getint( irc, "buddy_sendbuffer_delay" ) > 0 ) + if( set_getint( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 ) { int delay; @@ -1110,7 +1110,7 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) strcat( u->sendbuf, msg ); strcat( u->sendbuf, "\n" ); - delay = set_getint( irc, "buddy_sendbuffer_delay" ); + delay = set_getint( &irc->set, "buddy_sendbuffer_delay" ); if( delay <= 5 ) delay *= 1000; @@ -1175,7 +1175,7 @@ int irc_msgfrom( irc_t *irc, char *nick, char *msg ) { int len = strlen( irc->nick) + 3; prefix = g_new (char, len ); - g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( irc, "to_char" ) ); + g_snprintf( prefix, len, "%s%s", irc->nick, set_getstr( &irc->set, "to_char" ) ); prefix[len-1] = 0; } else diff --git a/irc_commands.c b/irc_commands.c index 3a7ace1c..a3fa0e6e 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -229,7 +229,7 @@ static void irc_cmd_privmsg( irc_t *irc, char **cmd ) if( g_strcasecmp( cmd[1], irc->channel ) == 0 ) { unsigned int i; - char *t = set_getstr( irc, "default_target" ); + char *t = set_getstr( &irc->set, "default_target" ); if( g_strcasecmp( t, "last" ) == 0 && irc->last_target ) cmd[1] = irc->last_target; diff --git a/nick.c b/nick.c index 68dd9802..56d6d378 100644 --- a/nick.c +++ b/nick.c @@ -85,7 +85,7 @@ char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char * g_snprintf( nick, MAX_NICK_LENGTH, "%s", realname ); nick_strip( nick ); - if (set_getint(irc, "lcnicks")) + if( set_getint( &irc->set, "lcnicks" ) ) nick_lc( nick ); } diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 04d1ee3e..f94d936d 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -219,8 +219,8 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... ) text = g_strdup_vprintf( format, params ); va_end( params ); - if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) + if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( gc->flags & OPT_CONN_HTML ) && set_getint( &gc->irc->set, "strip_html" ) ) ) strip_html( text ); /* Try to find a different connection on the same protocol. */ @@ -323,9 +323,9 @@ void signoff( struct gaim_connection *gc ) { /* Uhm... This is very sick. */ } - else if( !gc->wants_to_die && set_getint( irc, "auto_reconnect" ) ) + else if( !gc->wants_to_die && set_getint( &irc->set, "auto_reconnect" ) ) { - int delay = set_getint( irc, "auto_reconnect_delay" ); + int delay = set_getint( &irc->set, "auto_reconnect_delay" ); serv_got_crap( gc, "Reconnecting in %d seconds..", delay ); a->reconnect = b_timeout_add( delay * 1000, auto_reconnect, a ); @@ -364,12 +364,12 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea char *s; irc_t *irc = gc->irc; - if( set_getint( irc, "debug" ) && 0 ) /* This message is too useless */ + if( set_getint( &irc->set, "debug" ) && 0 ) /* This message is too useless */ serv_got_crap( gc, "Receiving user add from handle: %s", handle ); if( user_findhandle( gc, handle ) ) { - if( set_getint( irc, "debug" ) ) + if( set_getint( &irc->set, "debug" ) ) serv_got_crap( gc, "User already exists, ignoring add request: %s", handle ); return; @@ -457,7 +457,7 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname u->realname = g_strdup( realname ); - if( ( gc->flags & OPT_LOGGED_IN ) && set_getint( gc->irc, "display_namechanges" ) ) + if( ( gc->flags & OPT_LOGGED_IN ) && set_getint( &gc->irc->set, "display_namechanges" ) ) serv_got_crap( gc, "User `%s' changed name to `%s'", u->nick, u->realname ); } } @@ -513,14 +513,14 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in if( !u ) { - if( g_strcasecmp( set_getstr( gc->irc, "handle_unknown" ), "add" ) == 0 ) + if( g_strcasecmp( set_getstr( &gc->irc->set, "handle_unknown" ), "add" ) == 0 ) { add_buddy( gc, NULL, handle, NULL ); u = user_findhandle( gc, handle ); } else { - if( set_getint( gc->irc, "debug" ) || g_strcasecmp( set_getstr( gc->irc, "handle_unknown" ), "ignore" ) != 0 ) + if( set_getint( &gc->irc->set, "debug" ) || g_strcasecmp( set_getstr( &gc->irc->set, "handle_unknown" ), "ignore" ) != 0 ) { serv_got_crap( gc, "serv_got_update() for handle %s:", handle ); serv_got_crap( gc, "loggedin = %d, type = %d", loggedin, type ); @@ -579,7 +579,7 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in u->away = NULL; /* LISPy... */ - if( ( set_getint( gc->irc, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ + if( ( set_getint( &gc->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ ( u->online ) && /* Don't touch offline people */ ( ( ( u->online != oo ) && !u->away ) || /* Voice joining people */ ( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* (De)voice people changing state */ @@ -598,18 +598,18 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f if( !u ) { - char *h = set_getstr( irc, "handle_unknown" ); + char *h = set_getstr( &irc->set, "handle_unknown" ); if( g_strcasecmp( h, "ignore" ) == 0 ) { - if( set_getint( irc, "debug" ) ) + if( set_getint( &irc->set, "debug" ) ) serv_got_crap( gc, "Ignoring message from unknown handle %s", handle ); return; } else if( g_strncasecmp( h, "add", 3 ) == 0 ) { - int private = set_getint( irc, "private" ); + int private = set_getint( &irc->set, "private" ); if( h[3] ) { @@ -630,8 +630,8 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f } } - if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) + if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( gc->flags & OPT_CONN_HTML ) && set_getint( &gc->irc->set, "strip_html" ) ) ) strip_html( msg ); while( strlen( msg ) > 425 ) @@ -671,7 +671,7 @@ void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int { user_t *u; - if( !set_getint( gc->irc, "typing_notice" ) ) + if( !set_getint( &gc->irc->set, "typing_notice" ) ) return; if( ( u = user_findhandle( gc, handle ) ) ) { @@ -693,7 +693,7 @@ void serv_got_chat_left( struct gaim_connection *gc, int id ) struct conversation *c, *l = NULL; GList *ir; - if( set_getint( gc->irc, "debug" ) ) + if( set_getint( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "You were removed from conversation %d", (int) id ); for( c = gc->conversations; c && c->id != id; c = (l=c)->next ); @@ -738,8 +738,8 @@ void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whispe u = user_findhandle( gc, who ); for( c = gc->conversations; c && c->id != id; c = c->next ); - if( ( g_strcasecmp( set_getstr( gc->irc, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getint( gc->irc, "strip_html" ) ) ) + if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || + ( ( gc->flags & OPT_CONN_HTML ) && set_getint( &gc->irc->set, "strip_html" ) ) ) strip_html( msg ); if( c && u ) @@ -772,7 +772,7 @@ struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, c c->channel = g_strdup( s ); g_free( s ); - if( set_getint( gc->irc, "debug" ) ) + if( set_getint( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "Creating new conversation: (id=%d,handle=%s)", id, handle ); return( c ); @@ -786,7 +786,7 @@ void add_chat_buddy( struct conversation *b, char *handle ) user_t *u = user_findhandle( b->gc, handle ); int me = 0; - if( set_getint( b->gc->irc, "debug" ) ) + if( set_getint( &b->gc->irc->set, "debug" ) ) serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); /* It might be yourself! */ @@ -820,7 +820,7 @@ void remove_chat_buddy( struct conversation *b, char *handle, char *reason ) user_t *u; int me = 0; - if( set_getint( b->gc->irc, "debug" ) ) + if( set_getint( &b->gc->irc->set, "debug" ) ) serv_got_crap( b->gc, "User %s removed from conversation %d (%s)", handle, b->id, reason ? reason : "" ); /* It might be yourself! */ @@ -882,8 +882,9 @@ struct conversation *conv_findchannel( char *channel ) return( NULL ); } -char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ) +char *set_eval_away_devoice( set_t *set, char *value ) { + irc_t *irc = set->data; int st; if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) @@ -897,7 +898,7 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ) /* Horror.... */ - if( st != set_getint( irc, "away_devoice" ) ) + if( st != set_getint( &irc->set, "away_devoice" ) ) { char list[80] = ""; user_t *u = irc->users; @@ -937,7 +938,7 @@ char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ) irc->channel, pm, v, list ); } - return( set_eval_bool( irc, set, value ) ); + return( set_eval_bool( set, value ) ); } @@ -1017,7 +1018,7 @@ int bim_set_away( struct gaim_connection *gc, char *away ) if( s ) { gc->prpl->set_away( gc, s, away ); - if( set_getint( gc->irc, "debug" ) ) + if( set_getint( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "Setting away state to %s", s ); } else diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 2080465c..4d71da24 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -205,7 +205,7 @@ void bim_add_block( struct gaim_connection *gc, char *handle ); void bim_rem_block( struct gaim_connection *gc, char *handle ); void nogaim_init(); -char *set_eval_away_devoice( irc_t *irc, set_t *set, char *value ); +char *set_eval_away_devoice( set_t *set, char *value ); gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ); void cancel_auto_reconnect( struct account *a ); diff --git a/query.c b/query.c index 39821f3a..40dbb439 100644 --- a/query.c +++ b/query.c @@ -62,7 +62,7 @@ query_t *query_add( irc_t *irc, struct gaim_connection *gc, char *question, void irc->queries = q; } - if( g_strcasecmp( set_getstr( irc, "query_order" ), "lifo" ) == 0 || irc->queries == q ) + if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "lifo" ) == 0 || irc->queries == q ) query_display( irc, q ); return( q ); @@ -171,7 +171,7 @@ static query_t *query_default( irc_t *irc ) { query_t *q; - if( g_strcasecmp( set_getstr( irc, "query_order" ), "fifo" ) == 0 ) + if( g_strcasecmp( set_getstr( &irc->set, "query_order" ), "fifo" ) == 0 ) q = irc->queries; else for( q = irc->queries; q && q->next; q = q->next ); diff --git a/root_commands.c b/root_commands.c index 47143531..815d618b 100644 --- a/root_commands.c +++ b/root_commands.c @@ -143,7 +143,7 @@ static void cmd_identify( irc_t *irc, char **cmd ) case STORAGE_OK: irc_usermsg( irc, "Password accepted, settings and accounts loaded" ); irc_umode_set( irc, "+R", 1 ); - if( set_getint( irc, "auto_connect" ) ) + if( set_getint( &irc->set, "auto_connect" ) ) cmd_account( irc, account_on ); break; case STORAGE_OTHER_ERROR: @@ -671,14 +671,14 @@ static void cmd_set( irc_t *irc, char **cmd ) { if( cmd[1] && cmd[2] ) { - set_setstr( irc, cmd[1], cmd[2] ); + set_setstr( &irc->set, cmd[1], cmd[2] ); if( ( strcmp( cmd[2], "=" ) ) == 0 && cmd[3] ) irc_usermsg( irc, "Warning: Correct syntax: \002set \002 (without =)" ); } if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */ { - char *s = set_getstr( irc, cmd[1] ); + char *s = set_getstr( &irc->set, cmd[1] ); if( s ) irc_usermsg( irc, "%s = `%s'", cmd[1], s ); } diff --git a/set.c b/set.c index a26bc17b..b511a358 100644 --- a/set.c +++ b/set.c @@ -25,23 +25,24 @@ #define BITLBEE_CORE #include "bitlbee.h" -set_t *set_add( irc_t *irc, char *key, char *def, void *eval ) +set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ) { - set_t *s = set_find( irc, key ); + set_t *s = set_find( head, key ); + /* Possibly the setting already exists. If it doesn't exist yet, + we create it. If it does, we'll just change the default. */ if( !s ) { - if( ( s = irc->set ) ) + if( ( s = *head ) ) { while( s->next ) s = s->next; - s->next = g_new ( set_t, 1 ); + s->next = g_new0( set_t, 1 ); s = s->next; } else { - s = irc->set = g_new( set_t, 1 ); + s = *head = g_new0( set_t, 1 ); } - memset( s, 0, sizeof( set_t ) ); s->key = g_strdup( key ); } @@ -52,19 +53,15 @@ set_t *set_add( irc_t *irc, char *key, char *def, void *eval ) } if( def ) s->def = g_strdup( def ); - if( s->eval ) - { - g_free( s->eval ); - s->eval = NULL; - } - if( eval ) s->eval = eval; + s->eval = eval; + s->data = data; - return( s ); + return s; } -set_t *set_find( irc_t *irc, char *key ) +set_t *set_find( set_t **head, char *key ) { - set_t *s = irc->set; + set_t *s = *head; while( s ) { @@ -73,46 +70,46 @@ set_t *set_find( irc_t *irc, char *key ) s = s->next; } - return( s ); + return s; } -char *set_getstr( irc_t *irc, char *key ) +char *set_getstr( set_t **head, char *key ) { - set_t *s = set_find( irc, key ); + set_t *s = set_find( head, key ); if( !s || ( !s->value && !s->def ) ) - return( NULL ); + return NULL; - return( s->value?s->value:s->def ); + return s->value ? s->value : s->def; } -int set_getint( irc_t *irc, char *key ) +int set_getint( set_t **head, char *key ) { - char *s = set_getstr( irc, key ); + char *s = set_getstr( head, key ); int i = 0; if( !s ) - return( 0 ); + return 0; if( ( g_strcasecmp( s, "true" ) == 0 ) || ( g_strcasecmp( s, "yes" ) == 0 ) || ( g_strcasecmp( s, "on" ) == 0 ) ) - return( 1 ); + return 1; if( sscanf( s, "%d", &i ) != 1 ) - return( 0 ); + return 0; - return( i ); + return i; } -int set_setstr( irc_t *irc, char *key, char *value ) +int set_setstr( set_t **head, char *key, char *value ) { - set_t *s = set_find( irc, key ); + set_t *s = set_find( head, key ); char *nv = value; if( !s ) - s = set_add( irc, key, NULL, NULL ); + s = set_add( head, key, NULL, NULL, NULL ); - if( s->eval && !( nv = s->eval( irc, s, value ) ) ) - return( 0 ); + if( s->eval && !( nv = s->eval( s, value ) ) ) + return 0; if( s->value ) { @@ -120,26 +117,28 @@ int set_setstr( irc_t *irc, char *key, char *value ) s->value = NULL; } + /* If there's a default setting and it's equal to what we're trying to + set, stick with s->value = NULL. Otherwise, remember the setting. */ if( !s->def || ( strcmp( nv, s->def ) != 0 ) ) s->value = g_strdup( nv ); if( nv != value ) g_free( nv ); - return( 1 ); + return 1; } -int set_setint( irc_t *irc, char *key, int value ) +int set_setint( set_t **head, char *key, int value ) { char s[24]; /* Not quite 128-bit clean eh? ;-) */ - sprintf( s, "%d", value ); - return( set_setstr( irc, key, s ) ); + g_snprintf( s, sizeof( s ), "%d", value ); + return set_setstr( head, key, s ); } -void set_del( irc_t *irc, char *key ) +void set_del( set_t **head, char *key ) { - set_t *s = irc->set, *t = NULL; + set_t *s = *head, *t = NULL; while( s ) { @@ -152,7 +151,7 @@ void set_del( irc_t *irc, char *key ) if( t ) t->next = s->next; else - irc->set = s->next; + *head = s->next; g_free( s->key ); if( s->value ) g_free( s->value ); @@ -161,27 +160,27 @@ void set_del( irc_t *irc, char *key ) } } -char *set_eval_int( irc_t *irc, set_t *set, char *value ) +char *set_eval_int( set_t *set, char *value ) { - char *s = value; + char *s; - for( ; *s; s ++ ) + for( s = value; *s; s ++ ) if( *s < '0' || *s > '9' ) - return( NULL ); + return NULL; - return( value ); + return value; } -char *set_eval_bool( irc_t *irc, set_t *set, char *value ) +char *set_eval_bool( set_t *set, char *value ) { if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) return( value ); if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) return( value ); - return( set_eval_int( irc, set, value ) ); + return( set_eval_int( set, value ) ); } -char *set_eval_to_char( irc_t *irc, set_t *set, char *value ) +char *set_eval_to_char( set_t *set, char *value ) { char *s = g_new( char, 3 ); @@ -190,50 +189,42 @@ char *set_eval_to_char( irc_t *irc, set_t *set, char *value ) else sprintf( s, "%c ", *value ); - return( s ); + return s; } -char *set_eval_ops( irc_t *irc, set_t *set, char *value ) +char *set_eval_ops( set_t *set, char *value ) { + irc_t *irc = set->data; + if( g_strcasecmp( value, "user" ) == 0 ) - { irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost, irc->channel, "+o-o", irc->nick, irc->mynick ); - return( value ); - } else if( g_strcasecmp( value, "root" ) == 0 ) - { irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost, irc->channel, "-o+o", irc->nick, irc->mynick ); - return( value ); - } else if( g_strcasecmp( value, "both" ) == 0 ) - { irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost, irc->channel, "+oo", irc->nick, irc->mynick ); - return( value ); - } else if( g_strcasecmp( value, "none" ) == 0 ) - { irc_write( irc, ":%s!%s@%s MODE %s %s %s %s", irc->mynick, irc->mynick, irc->myhost, irc->channel, "-oo", irc->nick, irc->mynick ); - return( value ); - } + else + return NULL; - return( NULL ); + return value; } -char *set_eval_charset( irc_t *irc, set_t *set, char *value ) +char *set_eval_charset( set_t *set, char *value ) { GIConv cd; if ( g_strncasecmp( value, "none", 4 ) == 0 ) - return( value ); + return value; cd = g_iconv_open( "UTF-8", value ); if( cd == (GIConv) -1 ) - return( NULL ); + return NULL; g_iconv_close( cd ); - return( value ); + return value; } diff --git a/set.h b/set.h index 8a7b6747..15e97b5d 100644 --- a/set.h +++ b/set.h @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2006 Wilmer van der Gaast and others * \********************************************************************/ /* Some stuff to register, handle and save user preferences */ @@ -25,28 +25,30 @@ typedef struct set { + void *data; + char *key; char *value; char *def; /* Default */ - /* Eval: Returns NULL if the value is incorrect. Can return a - corrected value. set_setstr() should be able to free() the - returned string! */ - char *(*eval) ( irc_t *irc, struct set *set, char *value ); + /* Eval: Returns NULL if the value is incorrect or exactly the + passed value variable. When returning a corrected value, + set_setstr() should be able to free() the returned string! */ + char *(*eval) ( struct set *set, char *value ); struct set *next; } set_t; -set_t *set_add( irc_t *irc, char *key, char *def, void *eval ); -G_MODULE_EXPORT set_t *set_find( irc_t *irc, char *key ); -G_MODULE_EXPORT char *set_getstr( irc_t *irc, char *key ); -G_MODULE_EXPORT int set_getint( irc_t *irc, char *key ); -int set_setstr( irc_t *irc, char *key, char *value ); -int set_setint( irc_t *irc, char *key, int value ); -void set_del( irc_t *irc, char *key ); +set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ); +G_MODULE_EXPORT set_t *set_find( set_t **head, char *key ); +G_MODULE_EXPORT char *set_getstr( set_t **head, char *key ); +G_MODULE_EXPORT int set_getint( set_t **head, char *key ); +int set_setstr( set_t **head, char *key, char *value ); +int set_setint( set_t **head, char *key, int value ); +void set_del( set_t **head, char *key ); -char *set_eval_int( irc_t *irc, set_t *set, char *value ); -char *set_eval_bool( irc_t *irc, set_t *set, char *value ); +char *set_eval_int( set_t *set, char *value ); +char *set_eval_bool( set_t *set, char *value ); -char *set_eval_to_char( irc_t *irc, set_t *set, char *value ); -char *set_eval_ops( irc_t *irc, set_t *set, char *value ); -char *set_eval_charset( irc_t *irc, set_t *set, char *value ); +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 ); diff --git a/storage_xml.c b/storage_xml.c index 5a8b51ef..e0ffc481 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -245,7 +245,7 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting && xd->current_account == NULL ) { - set_setstr( irc, xd->current_setting, (char*) text ); + set_setstr( &irc->set, xd->current_setting, (char*) text ); g_free( xd->current_setting ); xd->current_setting = NULL; } @@ -420,14 +420,13 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) pass_len = rc4_encode( (unsigned char*) acc->pass, strlen( acc->pass ), (unsigned char**) &pass_rc4, irc->password ); pass_b64 = base64_encode( pass_rc4, pass_len ); + g_free( pass_rc4 ); if( !xml_printf( fd, "\tprpl->name, acc->user, pass_b64, acc->auto_connect ) ) { - g_free( pass_rc4 ); g_free( pass_b64 ); goto write_error; } - g_free( pass_rc4 ); g_free( pass_b64 ); if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) diff --git a/user.c b/user.c index 5f0952f5..30228c70 100644 --- a/user.c +++ b/user.c @@ -66,7 +66,7 @@ user_t *user_add( irc_t *irc, char *nick ) } u->user = u->realname = u->host = u->nick = g_strdup( nick ); - u->is_private = set_getint( irc, "private" ); + u->is_private = set_getint( &irc->set, "private" ); key = g_strdup( nick ); nick_lc( key ); -- cgit v1.2.3 From 0a3c243b6659dc10efb227e507f324c2711d6dcd Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 Jul 2006 01:18:56 +0200 Subject: Got rid of struct aim_user (now using account_t everywhere). Needs some more testing though. --- account.c | 13 +------ irc.c | 14 +++---- irc_commands.c | 16 ++++---- protocols/jabber/jabber.c | 24 ++++++------ protocols/msn/msn.c | 6 +-- protocols/nogaim.c | 99 ++++++++++++++++++++--------------------------- protocols/nogaim.h | 24 ++---------- protocols/oscar/oscar.c | 35 +++++++---------- protocols/yahoo/yahoo.c | 8 ++-- root_commands.c | 35 +++++++++-------- user.c | 2 +- 11 files changed, 115 insertions(+), 161 deletions(-) diff --git a/account.c b/account.c index b75afa51..ced62e25 100644 --- a/account.c +++ b/account.c @@ -142,8 +142,6 @@ void account_del( irc_t *irc, account_t *acc ) void account_on( irc_t *irc, account_t *a ) { - struct aim_user *u; - if( a->gc ) { /* Trying to enable an already-enabled account */ @@ -152,17 +150,8 @@ void account_on( irc_t *irc, account_t *a ) cancel_auto_reconnect( a ); - u = g_new0 ( struct aim_user, 1 ); - u->irc = irc; - u->prpl = a->prpl; - strncpy( u->username, a->user, sizeof( u->username ) - 1 ); - strncpy( u->password, a->pass, sizeof( u->password ) - 1 ); - if( a->server) strncpy( u->proto_opt[0], a->server, sizeof( u->proto_opt[0] ) - 1 ); - - a->gc = (struct gaim_connection *) u; /* Bit hackish :-/ */ a->reconnect = 0; - - a->prpl->login( u ); + a->prpl->login( a ); } void account_off( irc_t *irc, account_t *a ) diff --git a/irc.c b/irc.c index 60769735..d93fbe44 100644 --- a/irc.c +++ b/irc.c @@ -924,19 +924,19 @@ void irc_kick( irc_t *irc, user_t *u, char *channel, user_t *kicker ) void irc_kill( irc_t *irc, user_t *u ) { char *nick, *s; - char reason[64]; + char reason[128]; if( u->gc && u->gc->flags & OPT_LOGGING_OUT ) { - if( u->gc->user->proto_opt[0][0] ) + if( u->gc->acc->server ) g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, - u->gc->user->proto_opt[0] ); + u->gc->acc->server ); else if( ( s = strchr( u->gc->username, '@' ) ) ) g_snprintf( reason, sizeof( reason ), "%s %s", irc->myhost, s + 1 ); else g_snprintf( reason, sizeof( reason ), "%s %s.%s", irc->myhost, - u->gc->prpl->name, irc->myhost ); + u->gc->acc->prpl->name, irc->myhost ); /* proto_opt might contain garbage after the : */ if( ( s = strchr( reason, ':' ) ) ) @@ -1012,13 +1012,13 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) } else if( g_strncasecmp( s + 1, "TYPING", 6 ) == 0 ) { - if( u && u->gc && u->gc->prpl->send_typing && strlen( s ) >= 10 ) + if( u && u->gc && u->gc->acc->prpl->send_typing && strlen( s ) >= 10 ) { time_t current_typing_notice = time( NULL ); if( current_typing_notice - u->last_typing_notice >= 5 ) { - u->gc->prpl->send_typing( u->gc, u->handle, s[8] == '1' ); + u->gc->acc->prpl->send_typing( u->gc, u->handle, s[8] == '1' ); u->last_typing_notice = current_typing_notice; } } @@ -1051,7 +1051,7 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags ) return 1; } } - else if( c && c->gc && c->gc->prpl ) + else if( c && c->gc && c->gc->acc && c->gc->acc->prpl ) { return( bim_chat_msg( c->gc, c->id, s ) ); } diff --git a/irc_commands.c b/irc_commands.c index a3fa0e6e..889de9da 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -149,10 +149,10 @@ static void irc_cmd_part( irc_t *irc, char **cmd ) irc_part( irc, u, c->channel ); - if( c->gc && c->gc->prpl ) + if( c->gc ) { c->joined = 0; - c->gc->prpl->chat_leave( c->gc, c->id ); + c->gc->acc->prpl->chat_leave( c->gc, c->id ); } } else @@ -172,11 +172,11 @@ static void irc_cmd_join( irc_t *irc, char **cmd ) { user_t *u = user_find( irc, cmd[1] + 1 ); - if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open ) + if( u && u->gc && u->gc->acc->prpl->chat_open ) { irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] ); - if( !u->gc->prpl->chat_open( u->gc, u->handle ) ) + if( !u->gc->acc->prpl->chat_open( u->gc, u->handle ) ) { irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick ); } @@ -204,9 +204,9 @@ static void irc_cmd_invite( irc_t *irc, char **cmd ) user_t *u = user_find( irc, nick ); if( u && c && ( u->gc == c->gc ) ) - if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite ) + if( c->gc && c->gc->acc->prpl->chat_invite ) { - c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle ); + c->gc->acc->prpl->chat_invite( c->gc, c->id, "", u->handle ); irc_reply( irc, 341, "%s %s", nick, channel ); return; } @@ -476,8 +476,8 @@ static void irc_cmd_whois( irc_t *irc, char **cmd ) irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname ); if( u->gc ) - irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username, - *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name ); + irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->acc->user, + *u->gc->acc->server ? u->gc->acc->server : "", u->gc->acc->prpl->name ); else irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO ); diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 029473fd..c8e8ceca 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -560,29 +560,29 @@ static gboolean gjab_connected_ssl(gpointer data, void *source, b_input_conditio static void gjab_start(gjconn gjc) { - struct aim_user *user; + account_t *acc; int port = -1, ssl = 0; char *server = NULL, *s; if (!gjc || gjc->state != JCONN_STATE_OFF) return; - user = GJ_GC(gjc)->user; - if (*user->proto_opt[0]) { + acc = GJ_GC(gjc)->acc; + if (acc->server) { /* If there's a dot, assume there's a hostname in the beginning */ - if (strchr(user->proto_opt[0], '.')) { - server = g_strdup(user->proto_opt[0]); + if (strchr(acc->server, '.')) { + server = g_strdup(acc->server); if ((s = strchr(server, ':'))) *s = 0; } /* After the hostname, there can be a port number */ - s = strchr(user->proto_opt[0], ':'); + s = strchr(acc->server, ':'); if (s && isdigit(s[1])) sscanf(s + 1, "%d", &port); /* And if there's the string ssl, the user wants an SSL-connection */ - if (strstr(user->proto_opt[0], ":ssl") || g_strcasecmp(user->proto_opt[0], "ssl") == 0) + if (strstr(acc->server, ":ssl") || g_strcasecmp(acc->server, "ssl") == 0) ssl = 1; } @@ -615,7 +615,7 @@ static void gjab_start(gjconn gjc) g_free(server); - if (!user->gc || (gjc->fd < 0)) { + if (!acc->gc || (gjc->fd < 0)) { STATE_EVT(JCONN_STATE_OFF) return; } @@ -1515,18 +1515,18 @@ static void jabber_handlestate(gjconn gjc, int state) return; } -static void jabber_login(struct aim_user *user) +static void jabber_login(account_t *acc) { - struct gaim_connection *gc = new_gaim_conn(user); + struct gaim_connection *gc = new_gaim_conn(acc); struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); - char *loginname = create_valid_jid(user->username, DEFAULT_SERVER, "BitlBee"); + char *loginname = create_valid_jid(acc->user, DEFAULT_SERVER, "BitlBee"); jd->hash = g_hash_table_new(g_str_hash, g_str_equal); jd->chats = NULL; /* we have no chats yet */ set_login_progress(gc, 1, _("Connecting")); - if (!(jd->gjc = gjab_new(loginname, user->password, gc))) { + if (!(jd->gjc = gjab_new(loginname, acc->pass, gc))) { g_free(loginname); hide_login_progress(gc, _("Unable to connect")); signoff(gc); diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 6393f31d..b00354c9 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -26,9 +26,9 @@ #include "nogaim.h" #include "msn.h" -static void msn_login( struct aim_user *acct ) +static void msn_login( account_t *acc ) { - struct gaim_connection *gc = new_gaim_conn( acct ); + struct gaim_connection *gc = new_gaim_conn( acc ); struct msn_data *md = g_new0( struct msn_data, 1 ); set_login_progress( gc, 1, "Connecting" ); @@ -36,7 +36,7 @@ static void msn_login( struct aim_user *acct ) gc->proto_data = md; md->fd = -1; - if( strchr( acct->username, '@' ) == NULL ) + if( strchr( acc->user, '@' ) == NULL ) { hide_login_progress( gc, "Invalid account name" ); signoff( gc ); diff --git a/protocols/nogaim.c b/protocols/nogaim.c index f94d936d..8346f5fa 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -144,33 +144,21 @@ GSList *get_connections() { return connections; } /* multi.c */ -struct gaim_connection *new_gaim_conn( struct aim_user *user ) +struct gaim_connection *new_gaim_conn( account_t *acc ) { struct gaim_connection *gc; - account_t *a; gc = g_new0( struct gaim_connection, 1 ); - gc->prpl = user->prpl; - g_snprintf( gc->username, sizeof( gc->username ), "%s", user->username ); - g_snprintf( gc->password, sizeof( gc->password ), "%s", user->password ); - /* [MD] BUGFIX: don't set gc->irc to the global IRC, but use the one from the struct aim_user. - * This fixes daemon mode breakage where IRC doesn't point to the currently active connection. - */ - gc->irc = user->irc; - - connections = g_slist_append( connections, gc ); + /* Maybe we should get rid of this memory waste later. ;-) */ + g_snprintf( gc->username, sizeof( gc->username ), "%s", acc->user ); + g_snprintf( gc->password, sizeof( gc->password ), "%s", acc->pass ); - user->gc = gc; - gc->user = user; + gc->irc = acc->irc; + gc->acc = acc; + acc->gc = gc; - // Find the account_t so we can set its gc pointer - for( a = gc->irc->accounts; a; a = a->next ) - if( ( struct aim_user * ) a->gc == user ) - { - a->gc = gc; - break; - } + connections = g_slist_append( connections, gc ); return( gc ); } @@ -188,7 +176,6 @@ void destroy_gaim_conn( struct gaim_connection *gc ) } connections = g_slist_remove( connections, gc ); - g_free( gc->user ); g_free( gc ); } @@ -225,14 +212,14 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... ) /* Try to find a different connection on the same protocol. */ for( a = gc->irc->accounts; a; a = a->next ) - if( a->prpl == gc->prpl && a->gc != gc ) + if( a->prpl == gc->acc->prpl && a->gc != gc ) break; /* If we found one, include the screenname in the message. */ if( a ) - irc_usermsg( gc->irc, "%s(%s) - %s", gc->prpl->name, gc->username, text ); + irc_usermsg( gc->irc, "%s(%s) - %s", gc->acc->prpl->name, gc->username, text ); else - irc_usermsg( gc->irc, "%s - %s", gc->prpl->name, text ); + irc_usermsg( gc->irc, "%s - %s", gc->acc->prpl->name, text ); g_free( text ); } @@ -241,8 +228,8 @@ static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond ) { struct gaim_connection *gc = d; - if( gc->prpl && gc->prpl->keepalive ) - gc->prpl->keepalive( gc ); + if( gc->acc->prpl->keepalive ) + gc->acc->prpl->keepalive( gc ); return TRUE; } @@ -298,7 +285,7 @@ void signoff( struct gaim_connection *gc ) gc->flags |= OPT_LOGGING_OUT; gc->keepalive = 0; - gc->prpl->close( gc ); + gc->acc->prpl->close( gc ); b_event_remove( gc->inpa ); while( u ) @@ -378,7 +365,7 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea } memset( nick, 0, MAX_NICK_LENGTH + 1 ); - strcpy( nick, nick_get( gc->irc, handle, gc->prpl, realname ) ); + strcpy( nick, nick_get( gc->irc, handle, gc->acc->prpl, realname ) ); u = user_add( gc->irc, nick ); @@ -390,15 +377,15 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea u->host = g_strdup( s + 1 ); u->user = g_strndup( handle, s - handle ); } - else if( gc->user->proto_opt[0] && *gc->user->proto_opt[0] ) + else if( *gc->acc->server ) { char *colon; - if( ( colon = strchr( gc->user->proto_opt[0], ':' ) ) ) - u->host = g_strndup( gc->user->proto_opt[0], - colon - gc->user->proto_opt[0] ); + if( ( colon = strchr( gc->acc->server, ':' ) ) ) + u->host = g_strndup( gc->acc->server, + colon - gc->acc->server ); else - u->host = g_strdup( gc->user->proto_opt[0] ); + u->host = g_strdup( gc->acc->server ); u->user = g_strdup( handle ); @@ -409,7 +396,7 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea } else { - u->host = g_strdup( gc->user->prpl->name ); + u->host = g_strdup( gc->acc->prpl->name ); u->user = g_strdup( handle ); } @@ -479,7 +466,7 @@ void show_got_added_no( gpointer w, struct show_got_added_data *data ) void show_got_added_yes( gpointer w, struct show_got_added_data *data ) { - data->gc->prpl->add_buddy( data->gc, data->handle ); + data->gc->acc->prpl->add_buddy( data->gc, data->handle ); add_buddy( data->gc, NULL, data->handle, data->handle ); return show_got_added_no( w, data ); @@ -558,11 +545,11 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in remove_chat_buddy_silent( c, handle ); } - if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "oscar") || !strcmp(gc->prpl->name, "icq")) ) + if( ( type & UC_UNAVAILABLE ) && ( strcmp( gc->acc->prpl->name, "oscar" ) == 0 || strcmp( gc->acc->prpl->name, "icq" ) == 0 ) ) { u->away = g_strdup( "Away" ); } - else if( ( type & UC_UNAVAILABLE ) && ( !strcmp(gc->prpl->name, "jabber") ) ) + else if( ( type & UC_UNAVAILABLE ) && ( strcmp( gc->acc->prpl->name, "jabber" ) == 0 ) ) { if( type & UC_DND ) u->away = g_strdup( "Do Not Disturb" ); @@ -571,9 +558,9 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in else // if( type & UC_AWAY ) u->away = g_strdup( "Away" ); } - else if( ( type & UC_UNAVAILABLE ) && gc->prpl->get_status_string ) + else if( ( type & UC_UNAVAILABLE ) && gc->acc->prpl->get_status_string ) { - u->away = g_strdup( gc->prpl->get_status_string( gc, type ) ); + u->away = g_strdup( gc->acc->prpl->get_status_string( gc, type ) ); } else u->away = NULL; @@ -732,7 +719,7 @@ void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whispe user_t *u; /* Gaim sends own messages through this too. IRC doesn't want this, so kill them */ - if( g_strcasecmp( who, gc->user->username ) == 0 ) + if( g_strcasecmp( who, gc->username ) == 0 ) return; u = user_findhandle( gc, who ); @@ -790,7 +777,7 @@ void add_chat_buddy( struct conversation *b, char *handle ) serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); /* It might be yourself! */ - if( b->gc->prpl->cmp_buddynames( handle, b->gc->user->username ) == 0 ) + if( b->gc->acc->prpl->cmp_buddynames( handle, b->gc->username ) == 0 ) { u = user_find( b->gc->irc, b->gc->irc->nick ); if( !b->joined ) @@ -824,7 +811,7 @@ void remove_chat_buddy( struct conversation *b, char *handle, char *reason ) serv_got_crap( b->gc, "User %s removed from conversation %d (%s)", handle, b->id, reason ? reason : "" ); /* It might be yourself! */ - if( g_strcasecmp( handle, b->gc->user->username ) == 0 ) + if( g_strcasecmp( handle, b->gc->username ) == 0 ) { u = user_find( b->gc->irc, b->gc->irc->nick ); b->joined = 0; @@ -958,7 +945,7 @@ int bim_buddy_msg( struct gaim_connection *gc, char *handle, char *msg, int flag msg = buf; } - st = gc->prpl->send_im( gc, handle, msg, strlen( msg ), flags ); + st = gc->acc->prpl->send_im( gc, handle, msg, strlen( msg ), flags ); g_free( buf ); return st; @@ -975,7 +962,7 @@ int bim_chat_msg( struct gaim_connection *gc, int id, char *msg ) msg = buf; } - st = gc->prpl->chat_send( gc, id, msg ); + st = gc->acc->prpl->chat_send( gc, id, msg ); g_free( buf ); return st; @@ -989,7 +976,7 @@ int bim_set_away( struct gaim_connection *gc, char *away ) char *s; if( !away ) away = ""; - ms = m = gc->prpl->away_states( gc ); + ms = m = gc->acc->prpl->away_states( gc ); while( m ) { @@ -1010,19 +997,19 @@ int bim_set_away( struct gaim_connection *gc, char *away ) if( m ) { - gc->prpl->set_away( gc, m->data, *away ? away : NULL ); + gc->acc->prpl->set_away( gc, m->data, *away ? away : NULL ); } else { s = bim_away_alias_find( ms, away ); if( s ) { - gc->prpl->set_away( gc, s, away ); + gc->acc->prpl->set_away( gc, s, away ); if( set_getint( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "Setting away state to %s", s ); } else - gc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); + gc->acc->prpl->set_away( gc, GAIM_AWAY_CUSTOM, away ); } g_list_free( ms ); @@ -1074,46 +1061,46 @@ static char *bim_away_alias_find( GList *gcm, char *away ) void bim_add_allow( struct gaim_connection *gc, char *handle ) { - if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) + if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL ) { gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) ); } - gc->prpl->add_permit( gc, handle ); + gc->acc->prpl->add_permit( gc, handle ); } void bim_rem_allow( struct gaim_connection *gc, char *handle ) { GSList *l; - if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) + if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) ) { g_free( l->data ); gc->permit = g_slist_delete_link( gc->permit, l ); } - gc->prpl->rem_permit( gc, handle ); + gc->acc->prpl->rem_permit( gc, handle ); } void bim_add_block( struct gaim_connection *gc, char *handle ) { - if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) == NULL ) + if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL ) { gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) ); } - gc->prpl->add_deny( gc, handle ); + gc->acc->prpl->add_deny( gc, handle ); } void bim_rem_block( struct gaim_connection *gc, char *handle ) { GSList *l; - if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->prpl->cmp_buddynames ) ) ) + if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) ) { g_free( l->data ); gc->deny = g_slist_delete_link( gc->deny, l ); } - gc->prpl->rem_deny( gc, handle ); + gc->acc->prpl->rem_deny( gc, handle ); } diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 4d71da24..8c6519c1 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -38,6 +38,7 @@ #define _NOGAIM_H #include "bitlbee.h" +#include "account.h" #include "proxy.h" #include "md5.h" #include "sha.h" @@ -62,7 +63,7 @@ /* ok. now the fun begins. first we create a connection structure */ struct gaim_connection { - struct prpl *prpl; + account_t *acc; guint32 flags; /* each connection then can have its own protocol-specific data */ @@ -78,8 +79,6 @@ struct gaim_connection GSList *deny; int permdeny; - struct aim_user *user; - char username[64]; char displayname[128]; char password[32]; @@ -125,26 +124,11 @@ struct buddy { struct gaim_connection *gc; /* the connection it belongs to */ }; -struct aim_user { - char username[64]; - char alias[SELF_ALIAS_LEN]; - char password[32]; - char user_info[2048]; - int options; - struct prpl *prpl; - /* prpls can use this to save information about the user, - * like which server to connect to, etc */ - char proto_opt[7][256]; - - struct gaim_connection *gc; - irc_t *irc; -}; - struct prpl { int options; const char *name; - void (* login) (struct aim_user *); + void (* login) (account_t *); void (* keepalive) (struct gaim_connection *); void (* close) (struct gaim_connection *); @@ -211,7 +195,7 @@ gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond ); void cancel_auto_reconnect( struct account *a ); /* multi.c */ -G_MODULE_EXPORT struct gaim_connection *new_gaim_conn( struct aim_user *user ); +G_MODULE_EXPORT struct gaim_connection *new_gaim_conn( account_t *acc ); G_MODULE_EXPORT void destroy_gaim_conn( struct gaim_connection *gc ); G_MODULE_EXPORT void set_login_progress( struct gaim_connection *gc, int step, char *msg ); G_MODULE_EXPORT void hide_login_progress( struct gaim_connection *gc, char *msg ); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 7c76533a..d55ce3f2 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -355,18 +355,18 @@ static gboolean oscar_login_connect(gpointer data, gint source, b_input_conditio return FALSE; } -static void oscar_login(struct aim_user *user) { +static void oscar_login(account_t *acc) { aim_session_t *sess; aim_conn_t *conn; char buf[256]; - struct gaim_connection *gc = new_gaim_conn(user); + struct gaim_connection *gc = new_gaim_conn(acc); struct oscar_data *odata = gc->proto_data = g_new0(struct oscar_data, 1); - if (isdigit(*user->username)) { + if (isdigit(acc->user[0])) { odata->icq = TRUE; /* This is odd but it's necessary for a proper do_import and do_export. We don't do those anymore, but let's stick with it, just in case - it accidentally fixes something else too... */ + it accidentally fixes something else too... */ gc->password[8] = 0; } else { gc->flags |= OPT_CONN_HTML; @@ -389,9 +389,9 @@ static void oscar_login(struct aim_user *user) { return; } - if (g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.icq.com") != 0 && - g_strcasecmp(user->proto_opt[USEROPT_AUTH], "login.oscar.aol.com") != 0) { - serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",user->proto_opt[USEROPT_AUTH]); + if (g_strcasecmp(acc->server, "login.icq.com") != 0 && + g_strcasecmp(acc->server, "login.oscar.aol.com") != 0) { + serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",acc->server); } g_snprintf(buf, sizeof(buf), _("Signon: %s"), gc->username); @@ -401,11 +401,7 @@ static void oscar_login(struct aim_user *user) { aim_conn_addhandler(sess, conn, 0x0017, 0x0003, gaim_parse_auth_resp, 0); conn->status |= AIM_CONN_STATUS_INPROGRESS; - conn->fd = proxy_connect(user->proto_opt[USEROPT_AUTH][0] ? - user->proto_opt[USEROPT_AUTH] : AIM_DEFAULT_LOGIN_SERVER, - user->proto_opt[USEROPT_AUTHPORT][0] ? - atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT, - oscar_login_connect, gc); + conn->fd = proxy_connect(acc->server, AIM_LOGIN_PORT, oscar_login_connect, gc); if (conn->fd < 0) { hide_login_progress(gc, _("Couldn't connect to host")); signoff(gc); @@ -484,14 +480,11 @@ static int gaim_parse_auth_resp(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct aim_authresp_info *info; int i; char *host; int port; - struct aim_user *user; aim_conn_t *bosconn; struct gaim_connection *gc = sess->aux_data; struct oscar_data *od = gc->proto_data; - user = gc->user; - port = user->proto_opt[USEROPT_AUTHPORT][0] ? - atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT, + port = AIM_LOGIN_PORT; va_start(ap, fr); info = va_arg(ap, struct aim_authresp_info *); @@ -870,19 +863,16 @@ static int gaim_handle_redirect(aim_session_t *sess, aim_frame_t *fr, ...) { va_list ap; struct aim_redirect_data *redir; struct gaim_connection *gc = sess->aux_data; - struct aim_user *user = gc->user; aim_conn_t *tstconn; int i; char *host; int port; - port = user->proto_opt[USEROPT_AUTHPORT][0] ? - atoi(user->proto_opt[USEROPT_AUTHPORT]) : AIM_LOGIN_PORT, - va_start(ap, fr); redir = va_arg(ap, struct aim_redirect_data *); va_end(ap); + port = AIM_LOGIN_PORT; for (i = 0; i < (int)strlen(redir->ip); i++) { if (redir->ip[i] == ':') { port = atoi(&(redir->ip[i+1])); @@ -1722,8 +1712,11 @@ static int gaim_parse_locaterights(aim_session_t *sess, aim_frame_t *fr, ...) odata->rights.maxsiglen = odata->rights.maxawaymsglen = (guint)maxsiglen; + /* FIXME: It seems we're not really using this, and it broke now that + struct aim_user is dead. aim_bos_setprofile(sess, fr->conn, gc->user->user_info, NULL, gaim_caps); - + */ + return 1; } diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 79c0febb..c21779ba 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -120,16 +120,16 @@ static char *byahoo_strip( char *in ) return( g_strndup( in, len ) ); } -static void byahoo_login( struct aim_user *user ) +static void byahoo_login( account_t *acc ) { - struct gaim_connection *gc = new_gaim_conn( user ); + struct gaim_connection *gc = new_gaim_conn( acc ); struct byahoo_data *yd = gc->proto_data = g_new0( struct byahoo_data, 1 ); yd->logged_in = FALSE; yd->current_status = YAHOO_STATUS_AVAILABLE; set_login_progress( gc, 1, "Connecting" ); - yd->y2_id = yahoo_init( user->username, user->password ); + yd->y2_id = yahoo_init( acc->user, acc->pass ); yahoo_login( yd->y2_id, yd->current_status ); } @@ -424,7 +424,7 @@ static struct gaim_connection *byahoo_get_gc_by_id( int id ) gc = l->data; yd = gc->proto_data; - if( !strcmp(gc->prpl->name, "yahoo") && yd->y2_id == id ) + if( strcmp( gc->acc->prpl->name, "yahoo" ) == 0 && yd->y2_id == id ) return( gc ); } diff --git a/root_commands.c b/root_commands.c index 815d618b..3bd80e5e 100644 --- a/root_commands.c +++ b/root_commands.c @@ -399,14 +399,14 @@ static void cmd_add( irc_t *irc, char **cmd ) } else { - nick_set( irc, cmd[2], a->gc->prpl, cmd[3] ); + nick_set( irc, cmd[2], a->gc->acc->prpl, cmd[3] ); } } /* By making this optional, you can talk to people without having to add them to your *real* (server-side) contact list. */ if( add_for_real ) - a->gc->prpl->add_buddy( a->gc, cmd[2] ); + a->gc->acc->prpl->add_buddy( a->gc, cmd[2] ); add_buddy( a->gc, NULL, cmd[2], cmd[2] ); @@ -440,13 +440,13 @@ static void cmd_info( irc_t *irc, char **cmd ) return; } - if( !gc->prpl->get_info ) + if( !gc->acc->prpl->get_info ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } else { - gc->prpl->get_info( gc, cmd[2] ); + gc->acc->prpl->get_info( gc, cmd[2] ); } } @@ -481,7 +481,7 @@ static void cmd_rename( irc_t *irc, char **cmd ) } else if( u->send_handler == buddy_send_handler ) { - nick_set( irc, u->handle, u->gc->prpl, cmd[2] ); + nick_set( irc, u->handle, u->gc->acc->prpl, cmd[2] ); } irc_usermsg( irc, "Nick successfully changed" ); @@ -500,7 +500,7 @@ static void cmd_remove( irc_t *irc, char **cmd ) } s = g_strdup( u->handle ); - u->gc->prpl->remove_buddy( u->gc, u->handle, NULL ); + u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL ); user_del( irc, cmd[1] ); nick_del( irc, cmd[1] ); @@ -557,7 +557,7 @@ static void cmd_block( irc_t *irc, char **cmd ) return; } - if( !gc->prpl->add_deny || !gc->prpl->rem_permit ) + if( !gc->acc->prpl->add_deny || !gc->acc->prpl->rem_permit ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } @@ -616,7 +616,7 @@ static void cmd_allow( irc_t *irc, char **cmd ) return; } - if( !gc->prpl->rem_deny || !gc->prpl->add_permit ) + if( !gc->acc->prpl->rem_deny || !gc->acc->prpl->add_permit ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } @@ -732,7 +732,7 @@ static void cmd_blist( irc_t *irc, char **cmd ) { if( online == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->acc->prpl->name ); irc_usermsg( irc, format, u->nick, s, "Online" ); } @@ -743,7 +743,7 @@ static void cmd_blist( irc_t *irc, char **cmd ) { if( away == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->acc->prpl->name ); irc_usermsg( irc, format, u->nick, s, u->away ); } n_away ++; @@ -753,7 +753,7 @@ static void cmd_blist( irc_t *irc, char **cmd ) { if( offline == 1 ) { - g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name ); + g_snprintf( s, sizeof( s ) - 1, "%s@%s (%s)", u->user, u->host, u->gc->acc->prpl->name ); irc_usermsg( irc, format, u->nick, s, "Offline" ); } n_offline ++; @@ -778,7 +778,7 @@ static void cmd_nick( irc_t *irc, char **cmd ) { irc_usermsg( irc, "Your name is `%s'" , a->gc->displayname ? a->gc->displayname : "NULL" ); } - else if ( !a->gc->prpl->set_info ) + else if ( !a->prpl->set_info ) { irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] ); } @@ -786,7 +786,7 @@ static void cmd_nick( irc_t *irc, char **cmd ) { irc_usermsg( irc, "Setting your name to `%s'", cmd[2] ); - a->gc->prpl->set_info( a->gc, cmd[2] ); + a->prpl->set_info( a->gc, cmd[2] ); } } @@ -805,7 +805,7 @@ static void cmd_qlist( irc_t *irc, char **cmd ) for( num = 0; q; q = q->next, num ++ ) if( q->gc ) /* Not necessary yet, but it might come later */ - irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->prpl->name, q->gc->username, q->question ); + irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->acc->prpl->name, q->gc->username, q->question ); else irc_usermsg( irc, "%d, BitlBee: %s", num, q->question ); } @@ -833,10 +833,11 @@ static void cmd_import_buddies( irc_t *irc, char **cmd ) { user_t *u; + /* FIXME: Hmmm, this is actually pretty dangerous code... REMOVEME? :-) */ for( u = irc->users; u; u = u->next ) if( u->gc == gc ) { - u->gc->prpl->remove_buddy( u->gc, u->handle, NULL ); + u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL ); user_del( irc, u->nick ); } @@ -851,9 +852,9 @@ static void cmd_import_buddies( irc_t *irc, char **cmd ) for( n = gc->irc->nicks; n; n = n->next ) { - if( n->proto == gc->prpl && !user_findhandle( gc, n->handle ) ) + if( n->proto == gc->acc->prpl && !user_findhandle( gc, n->handle ) ) { - gc->prpl->add_buddy( gc, n->handle ); + gc->acc->prpl->add_buddy( gc, n->handle ); add_buddy( gc, NULL, n->handle, NULL ); } } diff --git a/user.c b/user.c index 30228c70..cb70ab68 100644 --- a/user.c +++ b/user.c @@ -146,7 +146,7 @@ user_t *user_findhandle( struct gaim_connection *gc, char *handle ) while( u ) { - if( u->gc == gc && u->handle && gc->prpl->cmp_buddynames ( u->handle, handle ) == 0 ) + if( u->gc == gc && u->handle && gc->acc->prpl->cmp_buddynames ( u->handle, handle ) == 0 ) break; u = u->next; } -- cgit v1.2.3 From 5100caa16bb707d89f1873aca99b5f87abc1dd56 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 1 Jul 2006 17:52:05 +0200 Subject: Added "account set" command. --- account.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ account.h | 5 +++++ lib/misc.c | 34 ++++++++++++++++++++++++++++ lib/misc.h | 3 +++ lib/rc4.c | 2 +- root_commands.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- set.c | 18 ++++++++++----- set.h | 4 +++- storage_xml.c | 65 ++++++++++++++++++++++++++++------------------------- 9 files changed, 220 insertions(+), 40 deletions(-) diff --git a/account.c b/account.c index ced62e25..4e399e8a 100644 --- a/account.c +++ b/account.c @@ -27,9 +27,12 @@ #include "bitlbee.h" #include "account.h" +char *set_eval_account( set_t *set, char *value ); + account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) { account_t *a; + set_t *s; if( irc->accounts ) { @@ -47,9 +50,63 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) a->auto_connect = 1; a->irc = irc; + s = set_add( &a->set, "auto_connect", NULL, set_eval_account, a ); + s->flags |= ACC_SET_NOSAVE; + + s = set_add( &a->set, "password", NULL, set_eval_account, a ); + s->flags |= ACC_SET_NOSAVE; + + s = set_add( &a->set, "server", NULL, set_eval_account, a ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; + + s = set_add( &a->set, "username", NULL, set_eval_account, a ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; + set_setstr( &a->set, "username", user ); + return( a ); } +char *set_eval_account( set_t *set, char *value ) +{ + account_t *acc = set->data; + + /* Double-check: We refuse to edit on-line accounts. */ + if( acc->gc ) + return NULL; + + if( strcmp( set->key, "username" ) == 0 ) + { + g_free( acc->user ); + acc->user = g_strdup( value ); + return value; + } + else if( strcmp( set->key, "password" ) == 0 ) + { + g_free( acc->pass ); + acc->pass = g_strdup( value ); + return NULL; /* password shouldn't be visible in plaintext! */ + } + else if( strcmp( set->key, "server" ) == 0 ) + { + g_free( acc->server ); + if( *value ) + acc->server = g_strdup( value ); + else + acc->server = NULL; + return value; + } + else if( strcmp( set->key, "auto_connect" ) == 0 ) + { + if( !is_bool( value ) ) + return NULL; + + acc->auto_connect = bool2int( value ); + return value; + } + + return NULL; +} + account_t *account_get( irc_t *irc, char *id ) { account_t *a, *ret = NULL; @@ -129,6 +186,9 @@ void account_del( irc_t *irc, account_t *acc ) irc->accounts = a->next; } + while( a->set ) + set_del( &a->set, a->set->key ); + g_free( a->user ); g_free( a->pass ); if( a->server ) g_free( a->server ); diff --git a/account.h b/account.h index 40efb101..9fed399e 100644 --- a/account.h +++ b/account.h @@ -36,6 +36,8 @@ typedef struct account int auto_connect; int reconnect; + set_t *set; + struct irc *irc; struct gaim_connection *gc; struct account *next; @@ -47,4 +49,7 @@ void account_del( irc_t *irc, account_t *acc ); void account_on( irc_t *irc, account_t *a ); void account_off( irc_t *irc, account_t *a ); +#define ACC_SET_NOSAVE 1 +#define ACC_SET_OFFLINE_ONLY 2 + #endif diff --git a/lib/misc.c b/lib/misc.c index 784d80d6..17599946 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -485,3 +485,37 @@ void random_bytes( unsigned char *buf, int count ) buf[i] = rand() & 0xff; } } + +int is_bool( char *value ) +{ + if( *value == 0 ) + return 0; + + if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) + return 1; + if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) + return 1; + + while( *value ) + if( !isdigit( *value ) ) + return 0; + else + value ++; + + return 1; +} + +int bool2int( char *value ) +{ + int i; + + if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) + return 1; + if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) + return 0; + + if( sscanf( value, "%d", &i ) == 1 ) + return i; + + return 0; +} diff --git a/lib/misc.h b/lib/misc.h index 57ff3e37..b021e642 100644 --- a/lib/misc.h +++ b/lib/misc.h @@ -50,4 +50,7 @@ G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); +G_MODULE_EXPORT int is_bool( char *value ); +G_MODULE_EXPORT int bool2int( char *value ); + #endif diff --git a/lib/rc4.c b/lib/rc4.c index 86b74ef5..5e334507 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -164,7 +164,7 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char if( clear_len < 0 ) { - *clear = g_strdup( "" ); + *clear = (unsigned char*) g_strdup( "" ); return 0; } diff --git a/root_commands.c b/root_commands.c index 3bd80e5e..b975b0f4 100644 --- a/root_commands.c +++ b/root_commands.c @@ -231,9 +231,8 @@ static void cmd_account( irc_t *irc, char **cmd ) } a = account_add( irc, prpl, cmd[3], cmd[4] ); - if( cmd[5] ) - a->server = g_strdup( cmd[5] ); + set_setstr( &a->set, "server", cmd[5] ); irc_usermsg( irc, "Account successfully added" ); } @@ -357,6 +356,68 @@ static void cmd_account( irc_t *irc, char **cmd ) return; } } + else if( g_strcasecmp( cmd[1], "set" ) == 0 ) + { + char *acc_handle, *set_name = NULL, *tmp; + + if( !cmd[2] ) + { + irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); + return; + } + + acc_handle = g_strdup( cmd[2] ); + if( ( tmp = strchr( acc_handle, '/' ) ) ) + { + *tmp = 0; + set_name = tmp + 1; + } + a = account_get( irc, acc_handle ); + + if( a == NULL ) + { + irc_usermsg( irc, "Invalid account" ); + return; + } + + if( cmd[3] ) + { + set_t *s = set_find( &a->set, set_name ); + + if( a->gc && s && s->flags & ACC_SET_OFFLINE_ONLY ) + { + irc_usermsg( irc, "This setting can only be changed when the account is off-line" ); + return; + } + + set_setstr( &a->set, set_name, cmd[3] ); + + if( ( strcmp( cmd[3], "=" ) ) == 0 && cmd[4] ) + irc_usermsg( irc, "Warning: Correct syntax: \002account set \002 (without =)" ); + } + if( set_name ) /* else 'forgotten' on purpose.. Must show new value after changing */ + { + char *s = set_getstr( &a->set, set_name ); + if( s ) + irc_usermsg( irc, "%s = `%s'", set_name, s ); + else + irc_usermsg( irc, "%s is empty", set_name ); + } + else + { + set_t *s = a->set; + while( s ) + { + if( s->value || s->def ) + irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def ); + else + irc_usermsg( irc, "%s is empty", s->key ); + s = s->next; + } + } + + g_free( acc_handle ); + } else { irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] ); @@ -681,6 +742,8 @@ static void cmd_set( irc_t *irc, char **cmd ) char *s = set_getstr( &irc->set, cmd[1] ); if( s ) irc_usermsg( irc, "%s = `%s'", cmd[1], s ); + else + irc_usermsg( irc, "%s is empty", cmd[1] ); } else { @@ -689,6 +752,8 @@ static void cmd_set( irc_t *irc, char **cmd ) { if( s->value || s->def ) irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def ); + else + irc_usermsg( irc, "%s is empty", s->key ); s = s->next; } } diff --git a/set.c b/set.c index b511a358..4620264f 100644 --- a/set.c +++ b/set.c @@ -100,6 +100,16 @@ int set_getint( set_t **head, char *key ) return i; } +int set_getbool( set_t **head, char *key ) +{ + char *s = set_getstr( head, key ); + + if( !s ) + return 0; + + return bool2int( s ); +} + int set_setstr( set_t **head, char *key, char *value ) { set_t *s = set_find( head, key ); @@ -165,7 +175,7 @@ char *set_eval_int( set_t *set, char *value ) char *s; for( s = value; *s; s ++ ) - if( *s < '0' || *s > '9' ) + if( !isdigit( *s ) ) return NULL; return value; @@ -173,11 +183,7 @@ char *set_eval_int( set_t *set, char *value ) char *set_eval_bool( set_t *set, char *value ) { - if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) - return( value ); - if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) - return( value ); - return( set_eval_int( set, value ) ); + return is_bool( value ) ? value : NULL; } char *set_eval_to_char( set_t *set, char *value ) diff --git a/set.h b/set.h index 15e97b5d..4731f80a 100644 --- a/set.h +++ b/set.h @@ -31,6 +31,8 @@ typedef struct set char *value; char *def; /* Default */ + int flags; + /* Eval: Returns NULL if the value is incorrect or exactly the passed value variable. When returning a corrected value, set_setstr() should be able to free() the returned string! */ @@ -39,7 +41,7 @@ typedef struct set } set_t; set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ); -G_MODULE_EXPORT set_t *set_find( set_t **head, char *key ); +set_t *set_find( set_t **head, char *key ); G_MODULE_EXPORT char *set_getstr( set_t **head, char *key ); G_MODULE_EXPORT int set_getint( set_t **head, char *key ); int set_setstr( set_t **head, char *key, char *value ); diff --git a/storage_xml.c b/storage_xml.c index e0ffc481..701d5144 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -156,11 +156,9 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na { xd->current_account = account_add( irc, prpl, handle, password ); if( server ) - xd->current_account->server = g_strdup( server ); + set_setstr( &xd->current_account->set, "server", server ); if( autoconnect ) - /* Return value doesn't matter, since account_add() already sets - a default! */ - sscanf( autoconnect, "%d", &xd->current_account->auto_connect ); + set_setstr( &xd->current_account->set, "auto_connect", autoconnect ); } else { @@ -175,22 +173,19 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na } else if( g_strcasecmp( element_name, "setting" ) == 0 ) { - if( xd->current_account == NULL ) + char *setting; + + if( xd->current_setting ) { - char *setting; - - if( xd->current_setting ) - { - g_free( xd->current_setting ); - xd->current_setting = NULL; - } - - if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) - xd->current_setting = g_strdup( setting ); - else - g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, - "Missing attributes for %s element", element_name ); + g_free( xd->current_setting ); + xd->current_setting = NULL; } + + if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) + xd->current_setting = g_strdup( setting ); + else + g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Missing attributes for %s element", element_name ); } else if( g_strcasecmp( element_name, "buddy" ) == 0 ) { @@ -242,10 +237,10 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le the password, or if we didn't get the chance to check it yet. */ } - else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && - xd->current_setting && xd->current_account == NULL ) + else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting ) { - set_setstr( &irc->set, xd->current_setting, (char*) text ); + set_setstr( xd->current_account ? &xd->current_account->set : &irc->set, + xd->current_setting, (char*) text ); g_free( xd->current_setting ); xd->current_setting = NULL; } @@ -347,12 +342,17 @@ static storage_status_t xml_check_pass( const char *my_nick, const char *passwor return xml_load_real( my_nick, password, NULL, XML_PASS_CHECK_ONLY ); } -static int xml_printf( int fd, char *fmt, ... ) +static int xml_printf( int fd, int indent, char *fmt, ... ) { va_list params; char *out; + char tabs[9] = "\t\t\t\t\t\t\t\t"; int len; + /* Maybe not very clean, but who needs more than 8 levels of indentation anyway? */ + if( write( fd, tabs, indent <= 8 ? indent : 8 ) != indent ) + return 0; + va_start( params, fmt ); out = g_markup_vprintf_escaped( fmt, params ); va_end( params ); @@ -403,14 +403,14 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) /* Save the hash in base64-encoded form. */ pass_buf = base64_encode( (char*) pass_md5, 21 ); - if( !xml_printf( fd, "\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) + if( !xml_printf( fd, 0, "\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) goto write_error; g_free( pass_buf ); for( set = irc->set; set; set = set->next ) if( set->value && set->def ) - if( !xml_printf( fd, "\t%s\n", set->key, set->value ) ) + if( !xml_printf( fd, 1, "%s\n", set->key, set->value ) ) goto write_error; for( acc = irc->accounts; acc; acc = acc->next ) @@ -422,28 +422,33 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) pass_b64 = base64_encode( pass_rc4, pass_len ); g_free( pass_rc4 ); - if( !xml_printf( fd, "\tprpl->name, acc->user, pass_b64, acc->auto_connect ) ) + if( !xml_printf( fd, 1, "prpl->name, acc->user, pass_b64, acc->auto_connect ) ) { g_free( pass_b64 ); goto write_error; } g_free( pass_b64 ); - if( acc->server && acc->server[0] && !xml_printf( fd, " server=\"%s\"", acc->server ) ) + if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) ) goto write_error; - if( !xml_printf( fd, ">\n" ) ) + if( !xml_printf( fd, 0, ">\n" ) ) goto write_error; + for( set = acc->set; set; set = set->next ) + if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) ) + if( !xml_printf( fd, 2, "%s\n", set->key, set->value ) ) + goto write_error; + for( nick = irc->nicks; nick; nick = nick->next ) if( nick->proto == acc->prpl ) - if( !xml_printf( fd, "\t\t\n", nick->handle, nick->nick ) ) + if( !xml_printf( fd, 2, "\n", nick->handle, nick->nick ) ) goto write_error; - if( !xml_printf( fd, "\t\n" ) ) + if( !xml_printf( fd, 1, "\n" ) ) goto write_error; } - if( !xml_printf( fd, "\n" ) ) + if( !xml_printf( fd, 0, "\n" ) ) goto write_error; close( fd ); -- cgit v1.2.3 From 96863f65118767e968469e82ba6b02006e36b81c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 2 Jul 2006 11:49:31 +0200 Subject: Added protocol-specific settings, made the server setting specific to only OSCAR and Jabber. --- account.c | 12 +++---- account.h | 2 ++ protocols/jabber/jabber.c | 89 ++++++++++++++++++++++++++++++++--------------- protocols/nogaim.h | 1 + protocols/oscar/oscar.c | 15 ++++++++ 5 files changed, 84 insertions(+), 35 deletions(-) diff --git a/account.c b/account.c index 186565dd..1f2ec165 100644 --- a/account.c +++ b/account.c @@ -27,8 +27,6 @@ #include "bitlbee.h" #include "account.h" -char *set_eval_account( set_t *set, char *value ); - account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) { account_t *a; @@ -50,19 +48,21 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) a->auto_connect = 1; a->irc = irc; - s = set_add( &a->set, "auto_connect", NULL, set_eval_account, a ); + s = set_add( &a->set, "auto_connect", "true", set_eval_account, a ); s->flags |= ACC_SET_NOSAVE; s = set_add( &a->set, "password", NULL, set_eval_account, a ); s->flags |= ACC_SET_NOSAVE; - s = set_add( &a->set, "server", NULL, set_eval_account, a ); - s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; - s = set_add( &a->set, "username", NULL, set_eval_account, a ); s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; set_setstr( &a->set, "username", user ); + /* This function adds some more settings (and might want to do more + things that have to be done now, although I can't think of anything. */ + if( prpl->acc_init ) + prpl->acc_init( a ); + return( a ); } diff --git a/account.h b/account.h index 9fed399e..adb63f9e 100644 --- a/account.h +++ b/account.h @@ -49,6 +49,8 @@ void account_del( irc_t *irc, account_t *acc ); void account_on( irc_t *irc, account_t *a ); void account_off( irc_t *irc, account_t *a ); +char *set_eval_account( set_t *set, char *value ); + #define ACC_SET_NOSAVE 1 #define ACC_SET_OFFLINE_ONLY 2 diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index c8e8ceca..e7f4534e 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -562,35 +562,17 @@ static void gjab_start(gjconn gjc) { account_t *acc; int port = -1, ssl = 0; - char *server = NULL, *s; + char *server = NULL; if (!gjc || gjc->state != JCONN_STATE_OFF) return; acc = GJ_GC(gjc)->acc; - if (acc->server) { - /* If there's a dot, assume there's a hostname in the beginning */ - if (strchr(acc->server, '.')) { - server = g_strdup(acc->server); - if ((s = strchr(server, ':'))) - *s = 0; - } - - /* After the hostname, there can be a port number */ - s = strchr(acc->server, ':'); - if (s && isdigit(s[1])) - sscanf(s + 1, "%d", &port); - - /* And if there's the string ssl, the user wants an SSL-connection */ - if (strstr(acc->server, ":ssl") || g_strcasecmp(acc->server, "ssl") == 0) - ssl = 1; - } + server = acc->server; + port = set_getint(&acc->set, "port"); + ssl = set_getbool(&acc->set, "ssl"); - if (port == -1 && !ssl) - port = DEFAULT_PORT; - else if (port == -1 && ssl) - port = DEFAULT_PORT_SSL; - else if (port < JABBER_PORT_MIN || port > JABBER_PORT_MAX) { + if (port < JABBER_PORT_MIN || port > JABBER_PORT_MAX) { serv_got_crap(GJ_GC(gjc), "For security reasons, the Jabber port number must be in the %d-%d range.", JABBER_PORT_MIN, JABBER_PORT_MAX); STATE_EVT(JCONN_STATE_OFF) return; @@ -613,8 +595,6 @@ static void gjab_start(gjconn gjc) gjc->fd = proxy_connect(server, port, gjab_connected, GJ_GC(gjc)); } - g_free(server); - if (!acc->gc || (gjc->fd < 0)) { STATE_EVT(JCONN_STATE_OFF) return; @@ -1515,12 +1495,62 @@ static void jabber_handlestate(gjconn gjc, int state) return; } -static void jabber_login(account_t *acc) +static void jabber_acc_init(account_t *acc) { - struct gaim_connection *gc = new_gaim_conn(acc); - struct jabber_data *jd = gc->proto_data = g_new0(struct jabber_data, 1); - char *loginname = create_valid_jid(acc->user, DEFAULT_SERVER, "BitlBee"); + set_t *s; + + s = set_add( &acc->set, "port", "5222", set_eval_int, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; + + s = set_add( &acc->set, "resource", "BitlBee", NULL, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; + + s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; + + s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; +} +static void jabber_login(account_t *acc) +{ + struct gaim_connection *gc; + struct jabber_data *jd; + char *resource, *loginname; + + /* Time to move some data/things from the old syntax to the new one: */ + if (acc->server) { + char *s, *tmp_server; + int port; + + if (g_strcasecmp(acc->server, "ssl") == 0) { + set_setstr(&acc->set, "server", ""); + set_setint(&acc->set, "port", DEFAULT_PORT_SSL); + set_setstr(&acc->set, "ssl", "true"); + + g_free(acc->server); + acc->server = NULL; + } else if ((s = strchr(acc->server, ':'))) { + if (strstr(acc->server, ":ssl")) { + set_setint(&acc->set, "port", DEFAULT_PORT_SSL); + set_setstr(&acc->set, "ssl", "true"); + } + if (isdigit(s[1])) { + if (sscanf(s + 1, "%d", &port) == 1) + set_setint(&acc->set, "port", port); + } + tmp_server = g_strndup(acc->server, s - acc->server); + set_setstr(&acc->set, "server", tmp_server); + g_free(tmp_server); + } + } + + gc = new_gaim_conn(acc); + jd = gc->proto_data = g_new0(struct jabber_data, 1); + + resource = set_getstr(&acc->set, "resource"); + loginname = create_valid_jid(acc->user, DEFAULT_SERVER, resource); + jd->hash = g_hash_table_new(g_str_hash, g_str_equal); jd->chats = NULL; /* we have no chats yet */ @@ -2336,6 +2366,7 @@ void jabber_init() ret->name = "jabber"; ret->away_states = jabber_away_states; + ret->acc_init = jabber_acc_init; ret->login = jabber_login; ret->close = jabber_close; ret->send_im = jabber_send_im; diff --git a/protocols/nogaim.h b/protocols/nogaim.h index 8c6519c1..c0a867d6 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -128,6 +128,7 @@ struct prpl { int options; const char *name; + void (* acc_init) (account_t *); void (* login) (account_t *); void (* keepalive) (struct gaim_connection *); void (* close) (struct gaim_connection *); diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index d55ce3f2..28239812 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -355,6 +355,14 @@ static gboolean oscar_login_connect(gpointer data, gint source, b_input_conditio return FALSE; } +static void oscar_acc_init(account_t *acc) +{ + set_t *s; + + s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; +} + static void oscar_login(account_t *acc) { aim_session_t *sess; aim_conn_t *conn; @@ -389,6 +397,12 @@ static void oscar_login(account_t *acc) { return; } + if (acc->server == NULL) { + hide_login_progress(gc, "No servername specified"); + signoff(gc); + return; + } + if (g_strcasecmp(acc->server, "login.icq.com") != 0 && g_strcasecmp(acc->server, "login.oscar.aol.com") != 0) { serv_got_crap(gc, "Warning: Unknown OSCAR server: `%s'. Please review your configuration if the connection fails.",acc->server); @@ -2648,6 +2662,7 @@ void oscar_init() ret->name = "oscar"; ret->away_states = oscar_away_states; ret->login = oscar_login; + ret->acc_init = oscar_acc_init; ret->close = oscar_close; ret->send_im = oscar_send_im; ret->get_info = oscar_get_info; -- cgit v1.2.3 From 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 3 Jul 2006 01:20:27 +0200 Subject: Added display_name setting for MSN connections. (Should replace the nick command later.) --- account.h | 1 + protocols/msn/msn.c | 90 +++++++++++++++++++++++++++++++++++------------------ protocols/msn/ns.c | 16 ++++++++++ root_commands.c | 7 ++++- 4 files changed, 83 insertions(+), 31 deletions(-) diff --git a/account.h b/account.h index adb63f9e..9cf6987d 100644 --- a/account.h +++ b/account.h @@ -53,5 +53,6 @@ char *set_eval_account( set_t *set, char *value ); #define ACC_SET_NOSAVE 1 #define ACC_SET_OFFLINE_ONLY 2 +#define ACC_SET_ONLINE_ONLY 4 #endif diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index b00354c9..790b372a 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -26,6 +26,16 @@ #include "nogaim.h" #include "msn.h" +static char *msn_set_display_name( set_t *set, char *value ); + +static void msn_acc_init( account_t *acc ) +{ + set_t *s; + + s = set_add( &acc->set, "display_name", NULL, msn_set_display_name, acc ); + s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY; +} + static void msn_login( account_t *acc ) { struct gaim_connection *gc = new_gaim_conn( acc ); @@ -209,36 +219,7 @@ static void msn_set_away( struct gaim_connection *gc, char *state, char *message static void msn_set_info( struct gaim_connection *gc, char *info ) { - int i; - char buf[1024], *fn, *s; - struct msn_data *md = gc->proto_data; - - if( strlen( info ) > 129 ) - { - do_error_dialog( gc, "Maximum name length exceeded", "MSN" ); - return; - } - - /* Of course we could use http_encode() here, but when we encode - every character, the server is less likely to complain about the - chosen name. However, the MSN server doesn't seem to like escaped - non-ASCII chars, so we keep those unescaped. */ - s = fn = g_new0( char, strlen( info ) * 3 + 1 ); - for( i = 0; info[i]; i ++ ) - if( info[i] & 128 ) - { - *s = info[i]; - s ++; - } - else - { - g_snprintf( s, 4, "%%%02X", info[i] ); - s += 3; - } - - g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn ); - msn_write( gc, buf, strlen( buf ) ); - g_free( fn ); + msn_set_display_name( set_find( &gc->acc->set, "display_name" ), info ); } static void msn_get_info(struct gaim_connection *gc, char *who) @@ -377,11 +358,60 @@ static int msn_send_typing( struct gaim_connection *gc, char *who, int typing ) return( 1 ); } +static char *msn_set_display_name( set_t *set, char *value ) +{ + account_t *acc = set->data; + struct gaim_connection *gc = acc->gc; + struct msn_data *md; + char buf[1024], *fn, *s; + int i; + + /* Double-check. */ + if( gc == NULL ) + return NULL; + + md = gc->proto_data; + + if( strlen( value ) > 129 ) + { + serv_got_crap( gc, "Maximum name length exceeded" ); + return NULL; + } + + /* Of course we could use http_encode() here, but when we encode + every character, the server is less likely to complain about the + chosen name. However, the MSN server doesn't seem to like escaped + non-ASCII chars, so we keep those unescaped. */ + s = fn = g_new0( char, strlen( value ) * 3 + 1 ); + for( i = 0; value[i]; i ++ ) + if( value[i] & 128 ) + { + *s = value[i]; + s ++; + } + else + { + g_snprintf( s, 4, "%%%02X", value[i] ); + s += 3; + } + + g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn ); + msn_write( gc, buf, strlen( buf ) ); + g_free( fn ); + + /* Returning NULL would be better, because the server still has to + confirm the name change. However, it looks a bit confusing to the + user. */ + return value; +} + void msn_init() { struct prpl *ret = g_new0(struct prpl, 1); + ret->name = "msn"; ret->login = msn_login; + ret->acc_init = msn_acc_init; ret->close = msn_close; ret->send_im = msn_send_im; ret->away_states = msn_away_states; diff --git a/protocols/msn/ns.c b/protocols/msn/ns.c index e4c2b68c..9774f3e2 100644 --- a/protocols/msn/ns.c +++ b/protocols/msn/ns.c @@ -222,11 +222,19 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) } else if( num_parts == 7 && strcmp( cmd[2], "OK" ) == 0 ) { + set_t *s; + http_decode( cmd[4] ); strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); gc->displayname[sizeof(gc->displayname)-1] = 0; + if( ( s = set_find( &gc->acc->set, "display_name" ) ) ) + { + g_free( s->value ); + s->value = g_strdup( cmd[4] ); + } + set_login_progress( gc, 1, "Authenticated, getting buddy list" ); g_snprintf( buf, sizeof( buf ), "SYN %d 0\r\n", ++md->trId ); @@ -516,9 +524,17 @@ static int msn_ns_command( gpointer data, char **cmd, int num_parts ) if( g_strcasecmp( cmd[3], gc->username ) == 0 ) { + set_t *s; + http_decode( cmd[4] ); strncpy( gc->displayname, cmd[4], sizeof( gc->displayname ) ); gc->displayname[sizeof(gc->displayname)-1] = 0; + + if( ( s = set_find( &gc->acc->set, "display_name" ) ) ) + { + g_free( s->value ); + s->value = g_strdup( cmd[4] ); + } } else { diff --git a/root_commands.c b/root_commands.c index b975b0f4..42e113ed 100644 --- a/root_commands.c +++ b/root_commands.c @@ -386,7 +386,12 @@ static void cmd_account( irc_t *irc, char **cmd ) if( a->gc && s && s->flags & ACC_SET_OFFLINE_ONLY ) { - irc_usermsg( irc, "This setting can only be changed when the account is off-line" ); + irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); + return; + } + else if( !a->gc && s && s->flags & ACC_SET_ONLINE_ONLY ) + { + irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); return; } -- cgit v1.2.3 From 5b52a4895e5a59ff6509f7771f4d8665737688c3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 3 Jul 2006 23:22:45 +0200 Subject: Implemented per-account nick lists instead of per-protocol nick lists. nick_t is dead, instead nicks are just saves in a per-account_t GLib hash table. While doing this, the import_buddies command finally died and text_save() disappeared, because the old file format can't handle most of the new features in this branch anyway. Still have to implement support for the new nick lists in text_load()! --- account.c | 6 +- account.h | 1 + bitlbee.h | 1 + irc.c | 43 ++--------- irc.h | 2 +- irc_commands.c | 3 +- nick.c | 111 ++++++++++++----------------- nick.h | 14 +--- protocols/jabber/jabber.c | 2 +- protocols/msn/msn.c | 2 +- protocols/nogaim.c | 14 ++-- protocols/nogaim.h | 2 +- protocols/oscar/oscar.c | 3 +- protocols/yahoo/yahoo.c | 3 +- root_commands.c | 59 +-------------- storage_text.c | 178 +--------------------------------------------- storage_xml.c | 23 ++++-- user.c | 26 ++++--- 18 files changed, 118 insertions(+), 375 deletions(-) diff --git a/account.c b/account.c index 1f2ec165..28c33d3b 100644 --- a/account.c +++ b/account.c @@ -58,6 +58,8 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; set_setstr( &a->set, "username", user ); + a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free ); + /* This function adds some more settings (and might want to do more things that have to be done now, although I can't think of anything. */ if( prpl->acc_init ) @@ -125,7 +127,7 @@ account_t *account_get( irc_t *irc, char *id ) { for( a = irc->accounts; a; a = a->next ) if( a->prpl == proto && - a->prpl->cmp_buddynames( handle, a->user ) == 0 ) + a->prpl->handle_cmp( handle, a->user ) == 0 ) ret = a; } @@ -189,6 +191,8 @@ void account_del( irc_t *irc, account_t *acc ) while( a->set ) set_del( &a->set, a->set->key ); + g_hash_table_destroy( a->nicks ); + g_free( a->user ); g_free( a->pass ); if( a->server ) g_free( a->server ); diff --git a/account.h b/account.h index 9cf6987d..83f47a89 100644 --- a/account.h +++ b/account.h @@ -37,6 +37,7 @@ typedef struct account int reconnect; set_t *set; + GHashTable *nicks; struct irc *irc; struct gaim_connection *gc; diff --git a/bitlbee.h b/bitlbee.h index 1462316f..f068aeac 100644 --- a/bitlbee.h +++ b/bitlbee.h @@ -123,6 +123,7 @@ extern char *CONF_FILE; #include "nogaim.h" #include "commands.h" #include "account.h" +#include "nick.h" #include "conf.h" #include "log.h" #include "ini.h" diff --git a/irc.c b/irc.c index bac91198..fe55a02c 100644 --- a/irc.c +++ b/irc.c @@ -203,11 +203,9 @@ 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) { - account_t *account, *accounttmp; + account_t *account; user_t *user, *usertmp; - nick_t *nick, *nicktmp; help_t *helpnode, *helpnodetmp; - set_t *setnode, *setnodetmp; log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); @@ -251,17 +249,11 @@ void irc_free(irc_t * irc) while (irc->queries != NULL) query_del(irc, irc->queries); - if (irc->accounts != NULL) { - account = irc->accounts; - while (account != NULL) { - g_free(account->user); - g_free(account->pass); - g_free(account->server); - accounttmp = account; - account = account->next; - g_free(accounttmp); - } - } + while (irc->accounts) + account_del(irc, irc->accounts); + + while (irc->set) + set_del(&irc->set, irc->set->key); if (irc->users != NULL) { user = irc->users; @@ -286,17 +278,6 @@ 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->nicks != NULL) { - nick = irc->nicks; - while (nick != NULL) { - g_free(nick->nick); - g_free(nick->handle); - - nicktmp = nick; - nick = nick->next; - g_free(nicktmp); - } - } if (irc->help != NULL) { helpnode = irc->help; while (helpnode != NULL) { @@ -307,18 +288,6 @@ void irc_free(irc_t * irc) g_free(helpnodetmp); } } - if (irc->set != NULL) { - setnode = irc->set; - while (setnode != NULL) { - g_free(setnode->key); - g_free(setnode->def); - g_free(setnode->value); - - setnodetmp = setnode; - setnode = setnode->next; - g_free(setnodetmp); - } - } g_free(irc); if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON ) diff --git a/irc.h b/irc.h index ad52f42f..5b770180 100644 --- a/irc.h +++ b/irc.h @@ -97,7 +97,7 @@ typedef struct irc } irc_t; #include "user.h" -#include "nick.h" +// #include "nick.h" extern GSList *irc_connection_list; diff --git a/irc_commands.c b/irc_commands.c index 889de9da..47d9e8cb 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -477,7 +477,8 @@ static void irc_cmd_whois( irc_t *irc, char **cmd ) if( u->gc ) irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->acc->user, - *u->gc->acc->server ? u->gc->acc->server : "", u->gc->acc->prpl->name ); + u->gc->acc->server && *u->gc->acc->server ? u->gc->acc->server : "", + u->gc->acc->prpl->name ); else irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO ); diff --git a/nick.c b/nick.c index 56d6d378..14794bf3 100644 --- a/nick.c +++ b/nick.c @@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2004 Wilmer van der Gaast and others * + * Copyright 2002-2006 Wilmer van der Gaast and others * \********************************************************************/ /* Some stuff to fetch, save and handle nicknames for your buddies */ @@ -26,50 +26,48 @@ #define BITLBEE_CORE #include "bitlbee.h" -void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick ) +/* Store handles in lower case and strip spaces, because AIM is braindead. */ +static char *clean_handle( const char *orig ) { - nick_t *m = NULL, *n = irc->nicks; + char *new = g_malloc( strlen( orig ) + 1 ); + int i = 0; - while( n ) - { - if( ( g_strcasecmp( n->handle, handle ) == 0 ) && n->proto == proto ) - { - g_free( n->nick ); - n->nick = nick_dup( nick ); - nick_strip( n->nick ); - - return; - } - n = ( m = n )->next; // :-P + do { + if (*orig != ' ') + new[i++] = tolower( *orig ); } + while (*(orig++)); - if( m ) - n = m->next = g_new0( nick_t, 1 ); - else - n = irc->nicks = g_new0( nick_t, 1 ); + return new; +} + +void nick_set( account_t *acc, const char *handle, const char *nick ) +{ + char *store_handle, *store_nick = g_malloc( MAX_NICK_LENGTH + 1 ); - n->handle = g_strdup( handle ); - n->proto = proto; - n->nick = nick_dup( nick ); + store_handle = clean_handle( handle ); + strncpy( store_nick, nick, MAX_NICK_LENGTH ); + nick_strip( store_nick ); - nick_strip( n->nick ); + g_hash_table_replace( acc->nicks, store_handle, store_nick ); } -char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname ) +char *nick_get( account_t *acc, const char *handle, const char *realname ) { static char nick[MAX_NICK_LENGTH+1]; - nick_t *n = irc->nicks; + char *store_handle, *found_nick; int inf_protection = 256; memset( nick, 0, MAX_NICK_LENGTH + 1 ); - while( n && !*nick ) - if( ( n->proto == proto ) && ( g_strcasecmp( n->handle, handle ) == 0 ) ) - strcpy( nick, n->nick ); - else - n = n->next; - - if( !n ) + store_handle = clean_handle( handle ); + /* Find out if we stored a nick for this person already. If not, try + to generate a sane nick automatically. */ + if( ( found_nick = g_hash_table_lookup( acc->nicks, store_handle ) ) ) + { + strncpy( nick, found_nick, MAX_NICK_LENGTH ); + } + else { char *s; @@ -85,11 +83,14 @@ char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char * g_snprintf( nick, MAX_NICK_LENGTH, "%s", realname ); nick_strip( nick ); - if( set_getint( &irc->set, "lcnicks" ) ) + if( set_getbool( &acc->irc->set, "lcnicks" ) ) nick_lc( nick ); } + g_free( store_handle ); - while( !nick_ok( nick ) || user_find( irc, nick ) ) + /* Now, find out if the nick is already in use at the moment, and make + subtle changes to make it unique. */ + while( !nick_ok( nick ) || user_find( acc->irc, nick ) ) { if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) ) { @@ -105,19 +106,19 @@ char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char * { int i; - irc_usermsg( irc, "WARNING: Almost had an infinite loop in nick_get()! " - "This used to be a fatal BitlBee bug, but we tried to fix it. " - "This message should *never* appear anymore. " - "If it does, please *do* send us a bug report! " - "Please send all the following lines in your report:" ); + irc_usermsg( acc->irc, "WARNING: Almost had an infinite loop in nick_get()! " + "This used to be a fatal BitlBee bug, but we tried to fix it. " + "This message should *never* appear anymore. " + "If it does, please *do* send us a bug report! " + "Please send all the following lines in your report:" ); - irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle ); + irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle ); for( i = 0; i < MAX_NICK_LENGTH; i ++ ) - irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] ); + irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] ); - irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. " - "Good luck, and please don't forget to paste the lines up here " - "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" ); + irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. " + "Good luck, and please don't forget to paste the lines up here " + "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" ); g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() ); @@ -125,30 +126,12 @@ char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char * } } - return( nick ); + return nick; } -void nick_del( irc_t *irc, const char *nick ) +void nick_del( account_t *acc, const char *handle ) { - nick_t *l = NULL, *n = irc->nicks; - - while( n ) - { - if( g_strcasecmp( n->nick, nick ) == 0 ) - { - if( l ) - l->next = n->next; - else - irc->nicks = n->next; - - g_free( n->handle ); - g_free( n->nick ); - g_free( n ); - - break; - } - n = (l=n)->next; - } + g_hash_table_remove( acc->nicks, handle ); } diff --git a/nick.h b/nick.h index 9ab1ef1e..5274cb13 100644 --- a/nick.h +++ b/nick.h @@ -23,17 +23,9 @@ Suite 330, Boston, MA 02111-1307 USA */ -typedef struct __NICK -{ - char *handle; - struct prpl *proto; - char *nick; - struct __NICK *next; -} nick_t; - -void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick ); -char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname ); -void nick_del( irc_t *irc, const char *nick ); +void nick_set( account_t *acc, const char *handle, const char *nick ); +char *nick_get( account_t *acc, const char *handle, const char *realname ); +void nick_del( account_t *acc, const char *handle ); void nick_strip( char *nick ); int nick_ok( const char *nick ); diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index e7f4534e..7147a78c 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -2379,7 +2379,7 @@ void jabber_init() ret->keepalive = jabber_keepalive; ret->alias_buddy = jabber_roster_update; ret->group_buddy = jabber_group_change; - ret->cmp_buddynames = g_strcasecmp; + ret->handle_cmp = g_strcasecmp; register_protocol (ret); } diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 790b372a..db4563dc 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -431,7 +431,7 @@ void msn_init() ret->add_deny = msn_add_deny; ret->rem_deny = msn_rem_deny; ret->send_typing = msn_send_typing; - ret->cmp_buddynames = g_strcasecmp; + ret->handle_cmp = g_strcasecmp; register_protocol(ret); } diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 8346f5fa..54965b84 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -365,7 +365,7 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea } memset( nick, 0, MAX_NICK_LENGTH + 1 ); - strcpy( nick, nick_get( gc->irc, handle, gc->acc->prpl, realname ) ); + strcpy( nick, nick_get( gc->acc, handle, realname ) ); u = user_add( gc->irc, nick ); @@ -377,7 +377,7 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea u->host = g_strdup( s + 1 ); u->user = g_strndup( handle, s - handle ); } - else if( *gc->acc->server ) + else if( gc->acc->server ) { char *colon; @@ -777,7 +777,7 @@ void add_chat_buddy( struct conversation *b, char *handle ) serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); /* It might be yourself! */ - if( b->gc->acc->prpl->cmp_buddynames( handle, b->gc->username ) == 0 ) + if( b->gc->acc->prpl->handle_cmp( handle, b->gc->username ) == 0 ) { u = user_find( b->gc->irc, b->gc->irc->nick ); if( !b->joined ) @@ -1061,7 +1061,7 @@ static char *bim_away_alias_find( GList *gcm, char *away ) void bim_add_allow( struct gaim_connection *gc, char *handle ) { - if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL ) + if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL ) { gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) ); } @@ -1073,7 +1073,7 @@ void bim_rem_allow( struct gaim_connection *gc, char *handle ) { GSList *l; - if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) ) + if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) ) { g_free( l->data ); gc->permit = g_slist_delete_link( gc->permit, l ); @@ -1084,7 +1084,7 @@ void bim_rem_allow( struct gaim_connection *gc, char *handle ) void bim_add_block( struct gaim_connection *gc, char *handle ) { - if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL ) + if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL ) { gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) ); } @@ -1096,7 +1096,7 @@ void bim_rem_block( struct gaim_connection *gc, char *handle ) { GSList *l; - if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) ) + if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) ) { g_free( l->data ); gc->deny = g_slist_delete_link( gc->deny, l ); diff --git a/protocols/nogaim.h b/protocols/nogaim.h index c0a867d6..bae4489f 100644 --- a/protocols/nogaim.h +++ b/protocols/nogaim.h @@ -164,7 +164,7 @@ struct prpl { GList *(* away_states)(struct gaim_connection *gc); /* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */ - int (* cmp_buddynames) (const char *who1, const char *who2); + int (* handle_cmp) (const char *who1, const char *who2); }; #define UC_UNAVAILABLE 1 diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index 28239812..f65332dc 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2680,9 +2680,10 @@ void oscar_init() ret->rem_deny = oscar_rem_deny; ret->set_permit_deny = oscar_set_permit_deny; ret->keepalive = oscar_keepalive; - ret->cmp_buddynames = aim_sncmp; ret->get_status_string = oscar_get_status_string; ret->send_typing = oscar_send_typing; + + ret->handle_cmp = aim_sncmp; register_protocol(ret); } diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index c21779ba..23c6f813 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -408,7 +408,8 @@ void byahoo_init( ) ret->chat_invite = byahoo_chat_invite; ret->chat_leave = byahoo_chat_leave; ret->chat_open = byahoo_chat_open; - ret->cmp_buddynames = g_strcasecmp; + + ret->handle_cmp = g_strcasecmp; register_protocol(ret); } diff --git a/root_commands.c b/root_commands.c index 42e113ed..2cf67134 100644 --- a/root_commands.c +++ b/root_commands.c @@ -465,7 +465,7 @@ static void cmd_add( irc_t *irc, char **cmd ) } else { - nick_set( irc, cmd[2], a->gc->acc->prpl, cmd[3] ); + nick_set( a, cmd[2], cmd[3] ); } } @@ -547,7 +547,7 @@ static void cmd_rename( irc_t *irc, char **cmd ) } else if( u->send_handler == buddy_send_handler ) { - nick_set( irc, u->handle, u->gc->acc->prpl, cmd[2] ); + nick_set( u->gc->acc, u->handle, cmd[2] ); } irc_usermsg( irc, "Nick successfully changed" ); @@ -568,7 +568,7 @@ static void cmd_remove( irc_t *irc, char **cmd ) u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL ); user_del( irc, cmd[1] ); - nick_del( irc, cmd[1] ); + nick_del( u->gc->acc, u->handle ); irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] ); g_free( s ); @@ -880,58 +880,6 @@ static void cmd_qlist( irc_t *irc, char **cmd ) irc_usermsg( irc, "%d, BitlBee: %s", num, q->question ); } -static void cmd_import_buddies( irc_t *irc, char **cmd ) -{ - struct gaim_connection *gc; - account_t *a; - nick_t *n; - - if( !( a = account_get( irc, cmd[1] ) ) ) - { - irc_usermsg( irc, "Invalid account" ); - return; - } - else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) ) - { - irc_usermsg( irc, "That account is not on-line" ); - return; - } - - if( cmd[2] ) - { - if( g_strcasecmp( cmd[2], "clear" ) == 0 ) - { - user_t *u; - - /* FIXME: Hmmm, this is actually pretty dangerous code... REMOVEME? :-) */ - for( u = irc->users; u; u = u->next ) - if( u->gc == gc ) - { - u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL ); - user_del( irc, u->nick ); - } - - irc_usermsg( irc, "Old buddy list cleared." ); - } - else - { - irc_usermsg( irc, "Invalid argument: %s", cmd[2] ); - return; - } - } - - for( n = gc->irc->nicks; n; n = n->next ) - { - if( n->proto == gc->acc->prpl && !user_findhandle( gc, n->handle ) ) - { - gc->acc->prpl->add_buddy( gc, n->handle ); - add_buddy( gc, NULL, n->handle, NULL ); - } - } - - irc_usermsg( irc, "Sent all add requests. Please wait for a while, the server needs some time to handle all the adds." ); -} - const command_t commands[] = { { "help", 0, cmd_help, 0 }, { "identify", 1, cmd_identify, 0 }, @@ -950,7 +898,6 @@ const command_t commands[] = { { "no", 0, cmd_yesno, 0 }, { "blist", 0, cmd_blist, 0 }, { "nick", 1, cmd_nick, 0 }, - { "import_buddies", 1, cmd_import_buddies, 0 }, { "qlist", 0, cmd_qlist, 0 }, { NULL } }; diff --git a/storage_text.c b/storage_text.c index 06d278aa..ac197685 100644 --- a/storage_text.c +++ b/storage_text.c @@ -112,186 +112,13 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i continue; http_decode( s ); - nick_set( irc, s, prpl, nick ); + // FIXME!!!! nick_set( irc, s, prpl, nick ); } fclose( fp ); return STORAGE_OK; } -static storage_status_t text_save( irc_t *irc, int overwrite ) -{ - char s[512]; - char path[512], new_path[512]; - char *line; - nick_t *n; - set_t *set; - mode_t ou = umask( 0077 ); - account_t *a; - FILE *fp; - char *hash; - - if (!overwrite) { - g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); - if (access( path, F_OK ) != -1) - return STORAGE_ALREADY_EXISTS; - - g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); - if (access( path, F_OK ) != -1) - return STORAGE_ALREADY_EXISTS; - } - - /*\ - * [SH] Nothing should be saved if no password is set, because the - * password is not set if it was wrong, or if one is not identified - * yet. This means that a malicious user could easily overwrite - * files owned by someone else: - * a Bad Thing, methinks - \*/ - - /* [WVG] No? Really? */ - - /*\ - * [SH] Okay, okay, it wasn't really Wilmer who said that, it was - * me. I just thought it was funny. - \*/ - - hash = hashpass( irc->password ); - if( hash == NULL ) - { - irc_usermsg( irc, "Please register yourself if you want to save your settings." ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" ); - fp = fopen( path, "w" ); - if( !fp ) return STORAGE_OTHER_ERROR; - for( n = irc->nicks; n; n = n->next ) - { - strcpy( s, n->handle ); - s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */ - http_encode( s ); - g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick ); - if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - if( fclose( fp ) != 0 ) - { - irc_usermsg( irc, "fclose() reported an error. Disk full?" ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" ); - if( unlink( new_path ) != 0 ) - { - if( errno != ENOENT ) - { - irc_usermsg( irc, "Error while removing old .nicks file" ); - return STORAGE_OTHER_ERROR; - } - } - if( rename( path, new_path ) != 0 ) - { - irc_usermsg( irc, "Error while renaming new .nicks file" ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" ); - fp = fopen( path, "w" ); - if( !fp ) return STORAGE_OTHER_ERROR; - if( fprintf( fp, "%s", hash ) != strlen( hash ) ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - g_free( hash ); - - for( a = irc->accounts; a; a = a->next ) - { - if( !strcmp(a->prpl->name, "oscar") ) - g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server ); - else - g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"", - a->prpl->name, a->user, a->pass, a->server ? a->server : "" ); - - line = obfucrypt( s, irc->password ); - if( *line ) - { - if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - g_free( line ); - } - - for( set = irc->set; set; set = set->next ) - { - if( set->value && set->def ) - { - g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value ); - line = obfucrypt( s, irc->password ); - if( *line ) - { - if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - g_free( line ); - } - } - - if( strcmp( irc->mynick, ROOT_NICK ) != 0 ) - { - g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick ); - line = obfucrypt( s, irc->password ); - if( *line ) - { - if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 ) - { - irc_usermsg( irc, "fprintf() wrote too little. Disk full?" ); - fclose( fp ); - return STORAGE_OTHER_ERROR; - } - } - g_free( line ); - } - if( fclose( fp ) != 0 ) - { - irc_usermsg( irc, "fclose() reported an error. Disk full?" ); - return STORAGE_OTHER_ERROR; - } - - g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" ); - if( unlink( new_path ) != 0 ) - { - if( errno != ENOENT ) - { - irc_usermsg( irc, "Error while removing old .accounts file" ); - return STORAGE_OTHER_ERROR; - } - } - if( rename( path, new_path ) != 0 ) - { - irc_usermsg( irc, "Error while renaming new .accounts file" ); - return STORAGE_OTHER_ERROR; - } - - umask( ou ); - - return STORAGE_OK; -} - static storage_status_t text_check_pass( const char *nick, const char *password ) { char s[512]; @@ -336,6 +163,5 @@ storage_t storage_text = { .init = text_init, .check_pass = text_check_pass, .remove = text_remove, - .load = text_load, - .save = text_save + .load = text_load }; diff --git a/storage_xml.c b/storage_xml.c index 701d5144..b01f35d6 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -196,7 +196,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na if( xd->current_account && handle && nick ) { - nick_set( irc, handle, xd->current_account->prpl, nick ); + nick_set( xd->current_account, handle, nick ); } else { @@ -364,11 +364,12 @@ static int xml_printf( int fd, int indent, char *fmt, ... ) return len == 0; } +static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ); + static storage_status_t xml_save( irc_t *irc, int overwrite ) { char path[512], *path2, *pass_buf = NULL; set_t *set; - nick_t *nick; account_t *acc; int fd; md5_byte_t pass_md5[21]; @@ -439,10 +440,15 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) if( !xml_printf( fd, 2, "%s\n", set->key, set->value ) ) goto write_error; - for( nick = irc->nicks; nick; nick = nick->next ) - if( nick->proto == acc->prpl ) - if( !xml_printf( fd, 2, "\n", nick->handle, nick->nick ) ) - goto write_error; + /* This probably looks pretty strange. g_hash_table_foreach + is quite a PITA already (but it can't get much better in + C without using #define, I'm afraid), and since it + doesn't seem to be possible to abort the foreach on write + errors, so instead let's use the _find function and + return TRUE on write errors. Which means, if we found + something, there was an error. :-) */ + if( g_hash_table_find( acc->nicks, xml_save_nick, (gpointer) fd ) ) + goto write_error; if( !xml_printf( fd, 1, "\n" ) ) goto write_error; @@ -477,6 +483,11 @@ write_error: return STORAGE_OTHER_ERROR; } +static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data ) +{ + return !xml_printf( (int) data, 2, "\n", key, value ); +} + static storage_status_t xml_remove( const char *nick, const char *password ) { char s[512]; diff --git a/user.c b/user.c index cb70ab68..0892a23c 100644 --- a/user.c +++ b/user.c @@ -142,16 +142,22 @@ user_t *user_find( irc_t *irc, char *nick ) user_t *user_findhandle( struct gaim_connection *gc, char *handle ) { - user_t *u = gc->irc->users; - - while( u ) - { - if( u->gc == gc && u->handle && gc->acc->prpl->cmp_buddynames ( u->handle, handle ) == 0 ) - break; - u = u->next; - } - - return( u ); + user_t *u; + char *nick; + + /* First, let's try a hash lookup. If it works, it's probably faster. */ + if( ( nick = g_hash_table_lookup( gc->acc->nicks, handle ) ) && + ( u = user_find( gc->irc, nick ) ) && + ( gc->acc->prpl->handle_cmp( handle, u->handle ) == 0 ) ) + return u; + + /* However, it doesn't always work, so in that case we'll have to dig + through the whole userlist. :-( */ + for( u = gc->irc->users; u; u = u->next ) + if( u->gc == gc && u->handle && gc->acc->prpl->handle_cmp( u->handle, handle ) == 0 ) + return u; + + return NULL; } void user_rename( irc_t *irc, char *oldnick, char *newnick ) -- cgit v1.2.3 From 7e3592e96b27ec8375e4b28354bcf9ed4cf5943b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 5 Jul 2006 20:34:31 +0200 Subject: Fixed text_load(), added detection of primary storage backends without save support (which shouldn't be allowed) and added a call to nick_lc() to xml_save() so at least nicks should now be case-insensitive. --- storage.c | 2 +- storage_text.c | 57 +++++++++++++++++++++++---------------------------------- storage_xml.c | 5 ++++- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/storage.c b/storage.c index 807d5bb4..06044f80 100644 --- a/storage.c +++ b/storage.c @@ -69,7 +69,7 @@ GList *storage_init(const char *primary, char **migrate) register_storage_backend(&storage_xml); storage = storage_init_single(primary); - if (storage == NULL) + if (storage == NULL && storage->save == NULL) return NULL; ret = g_list_append(ret, storage); diff --git a/storage_text.c b/storage_text.c index ac197685..acc9eefe 100644 --- a/storage_text.c +++ b/storage_text.c @@ -27,32 +27,6 @@ #include "bitlbee.h" #include "crypting.h" -/* DO NOT USE THIS FUNCTION IN NEW CODE. This - * function is here merely because the save/load code still uses - * ids rather than names */ -static struct prpl *find_protocol_by_id(int id) -{ - switch (id) { - case 0: case 1: case 3: return find_protocol("oscar"); - case 4: return find_protocol("msn"); - case 2: return find_protocol("yahoo"); - case 8: return find_protocol("jabber"); - default: break; - } - return NULL; -} - -static int find_protocol_id(const char *name) -{ - if (!strcmp(name, "oscar")) return 1; - if (!strcmp(name, "msn")) return 4; - if (!strcmp(name, "yahoo")) return 2; - if (!strcmp(name, "jabber")) return 8; - - return -1; -} - - static void text_init (void) { if( access( global.conf->configdir, F_OK ) != 0 ) @@ -69,6 +43,7 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i char nick[MAX_NICK_LENGTH+1]; FILE *fp; user_t *ru = user_find( irc, ROOT_NICK ); + account_t *acc, *acc_lookup[9]; if( irc->status & USTATUS_IDENTIFIED ) return( 1 ); @@ -79,7 +54,7 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i fscanf( fp, "%32[^\n]s", s ); - if (checkpass (password, s) != 0) + if( checkpass( password, s ) != 0 ) { fclose( fp ); return STORAGE_INVALID_PASSWORD; @@ -99,20 +74,34 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i } fclose( fp ); + /* Build a list with the first listed account of every protocol + number. So if the user had nicks defined for a second account on + the same IM network, those nicks will be added to the wrong + account, and the user should rename those buddies again. But at + least from now on things will be saved properly. */ + memset( acc_lookup, 0, sizeof( acc_lookup ) ); + for( acc = irc->accounts; acc; acc = acc->next ) + { + if( acc_lookup[0] == NULL && strcmp( acc->prpl->name, "oscar" ) == 0 ) + acc_lookup[0] = acc_lookup[1] = acc_lookup[3] = acc; + else if( acc_lookup[2] == NULL && strcmp( acc->prpl->name, "yahoo" ) == 0 ) + acc_lookup[2] = acc; + else if( acc_lookup[4] == NULL && strcmp( acc->prpl->name, "msn" ) == 0 ) + acc_lookup[4] = acc; + else if( acc_lookup[8] == NULL && strcmp( acc->prpl->name, "jabber" ) == 0 ) + acc_lookup[8] = acc; + } + g_snprintf( s, 511, "%s%s%s", global.conf->configdir, my_nick, ".nicks" ); fp = fopen( s, "r" ); if( !fp ) return STORAGE_NO_SUCH_USER; while( fscanf( fp, "%s %d %s", s, &proto, nick ) > 0 ) { - struct prpl *prpl; - - prpl = find_protocol_by_id(proto); - - if (!prpl) + if( ( acc = acc_lookup[proto] ) == NULL ) continue; - + http_decode( s ); - // FIXME!!!! nick_set( irc, s, prpl, nick ); + nick_set( acc, s, nick ); } fclose( fp ); diff --git a/storage_xml.c b/storage_xml.c index b01f35d6..2585b475 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -381,7 +381,10 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_OTHER_ERROR; } - g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, irc->nick, ".xml" ); + path2 = g_strdup( irc->nick ); + nick_lc( path2 ); + g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" ); + g_free( path2 ); if( !overwrite && access( path, F_OK ) != -1 ) return STORAGE_ALREADY_EXISTS; -- cgit v1.2.3 From a93e3c822a697562c2e05906059922ed28f51ca5 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 9 Jul 2006 12:54:45 +0200 Subject: Fixed irc_names() (forgot to add @s for user/root in the new version). --- irc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/irc.c b/irc.c index 816b69d9..1a7579b8 100644 --- a/irc.c +++ b/irc.c @@ -651,6 +651,7 @@ void irc_names( irc_t *irc, char *channel ) user_t *u; char namelist[385] = ""; struct conversation *c = NULL; + char *ops = set_getstr( irc, "ops" ); /* RFCs say there is no error reply allowed on NAMES, so when the channel is invalid, just give an empty reply. */ @@ -667,6 +668,9 @@ void irc_names( irc_t *irc, char *channel ) if( u->gc && !u->away && set_getint( irc, "away_devoice" ) ) strcat( namelist, "+" ); + else if( ( strcmp( u->nick, irc->mynick ) == 0 && ( strcmp( ops, "root" ) == 0 || strcmp( ops, "both" ) == 0 ) ) || + ( strcmp( u->nick, irc->nick ) == 0 && ( strcmp( ops, "user" ) == 0 || strcmp( ops, "both" ) == 0 ) ) ) + strcat( namelist, "@" ); strcat( namelist, u->nick ); strcat( namelist, " " ); @@ -675,7 +679,6 @@ void irc_names( irc_t *irc, char *channel ) else if( ( c = conv_findchannel( channel ) ) ) { GList *l; - char *ops = set_getstr( irc, "ops" ); /* root and the user aren't in the channel userlist but should show up in /NAMES, so list them first: */ -- cgit v1.2.3 From b0a33a50735d93e1414a2e6c2007884d756429a3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 11 Jul 2006 11:28:44 +0200 Subject: Better handling of situations where IPv6 is not available at run-time. --- bitlbee.c | 46 ++++++++++++++++++++++++++++++++++------------ irc.c | 41 ++++++++++++++++++++++------------------- sock.h | 7 ------- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index 1d4e2b34..f3cc3d4a 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -35,20 +35,31 @@ static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition ); +#undef AF_INET6 +#define AF_INET6 666 + int bitlbee_daemon_init() { #ifdef IPV6 - struct sockaddr_in6 listen_addr; -#else - struct sockaddr_in listen_addr; + int use_ipv6 = 1; + struct sockaddr_in6 listen_addr6; #endif + struct sockaddr_in listen_addr; int i; FILE *fp; log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG ); log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG ); - global.listen_socket = socket( AF_INETx, SOCK_STREAM, 0 ); +#ifdef IPV6 + if( ( global.listen_socket = socket( AF_INET6, SOCK_STREAM, 0 ) ) == -1 ) + { + use_ipv6 = 0; +#endif + global.listen_socket = socket( AF_INET, SOCK_STREAM, 0 ); +#ifdef IPV6 + } +#endif if( global.listen_socket == -1 ) { log_error( "socket" ); @@ -60,13 +71,21 @@ int bitlbee_daemon_init() setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) ); #ifdef IPV6 - listen_addr.sin6_family = AF_INETx; - listen_addr.sin6_port = htons( global.conf->port ); - i = inet_pton( AF_INETx, ipv6_wrap( global.conf->iface ), &listen_addr.sin6_addr ); -#else - listen_addr.sin_family = AF_INETx; - listen_addr.sin_port = htons( global.conf->port ); - i = inet_pton( AF_INETx, global.conf->iface, &listen_addr.sin_addr ); + listen_addr6.sin6_family = AF_INET6; + listen_addr6.sin6_port = htons( global.conf->port ); + if( ( i = inet_pton( AF_INET6, ipv6_wrap( global.conf->iface ), &listen_addr6.sin6_addr ) ) != 1 ) + { + /* Forget about IPv6 in this function. */ + use_ipv6 = 0; +#endif + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons( global.conf->port ); + if( strcmp( global.conf->iface, "::" ) == 0 ) + i = inet_pton( AF_INET, "0.0.0.0", &listen_addr.sin_addr ); + else + i = inet_pton( AF_INET, global.conf->iface, &listen_addr.sin_addr ); +#ifdef IPV6 + } #endif if( i != 1 ) @@ -75,7 +94,10 @@ int bitlbee_daemon_init() return( -1 ); } - i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( listen_addr ) ); +#ifdef IPV6 + if( !use_ipv6 || ( i = bind( global.listen_socket, (struct sockaddr *) &listen_addr6, sizeof( listen_addr6 ) ) ) == -1 ) +#endif + i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( listen_addr ) ); if( i == -1 ) { log_error( "bind" ); diff --git a/irc.c b/irc.c index 1a7579b8..53ca7c4c 100644 --- a/irc.c +++ b/irc.c @@ -45,10 +45,10 @@ irc_t *irc_new( int fd ) unsigned int i; char buf[128]; #ifdef IPV6 - struct sockaddr_in6 sock[1]; -#else - struct sockaddr_in sock[1]; + struct sockaddr_in6 sock6[1]; + unsigned int i6; #endif + struct sockaddr_in sock[1]; irc = g_new0( irc_t, 1 ); @@ -68,45 +68,48 @@ irc_t *irc_new( int fd ) irc->channel = g_strdup( ROOT_CHAN ); i = sizeof( *sock ); +#ifdef IPV6 + i6 = sizeof( *sock6 ); +#endif if( global.conf->hostname ) irc->myhost = g_strdup( global.conf->hostname ); #ifdef IPV6 - else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx ) + else if( getsockname( irc->fd, (struct sockaddr*) sock6, &i6 ) == 0 && sock6->sin6_family == AF_INET6 ) { - if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) ) + if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) ) irc->myhost = g_strdup( peer->h_name ); - else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL ) + else if( inet_ntop( AF_INET6, &sock6->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL ) irc->myhost = g_strdup( ipv6_unwrap( buf ) ); } -#else - else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx ) +#endif + else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET ) { - if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) ) + if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) ) irc->myhost = g_strdup( peer->h_name ); - else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL ) + else if( inet_ntop( AF_INET, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL ) irc->myhost = g_strdup( buf ); } -#endif i = sizeof( *sock ); #ifdef IPV6 - if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx ) + i6 = sizeof( *sock6 ); + if( getpeername( irc->fd, (struct sockaddr*) sock6, &i6 ) == 0 && sock6->sin6_family == AF_INET6 ) { - if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) ) + if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) ) irc->host = g_strdup( peer->h_name ); - else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL ) + else if( inet_ntop( AF_INET6, &sock6->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL ) irc->host = g_strdup( ipv6_unwrap( buf ) ); } -#else - if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx ) + else +#endif + if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET ) { - if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) ) + if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) ) irc->host = g_strdup( peer->h_name ); - else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL ) + else if( inet_ntop( AF_INET, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL ) irc->host = g_strdup( buf ); } -#endif /* Rare, but possible. */ if( !irc->host ) irc->host = g_strdup( "localhost." ); diff --git a/sock.h b/sock.h index ff7034a6..c3c0428e 100644 --- a/sock.h +++ b/sock.h @@ -1,13 +1,6 @@ #include #include -/* To cut down on the ifdef stuff a little bit in other places */ -#ifdef IPV6 -#define AF_INETx AF_INET6 -#else -#define AF_INETx AF_INET -#endif - #ifndef _WIN32 #include #include -- cgit v1.2.3 From 639809488bb4ab59a4a4f15ef2d4cd34037a68a4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 12 Jul 2006 10:07:47 +0200 Subject: Removed #defines used to simulate systems without IPv6 support. --- bitlbee.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/bitlbee.c b/bitlbee.c index f3cc3d4a..85ae4621 100644 --- a/bitlbee.c +++ b/bitlbee.c @@ -35,9 +35,6 @@ static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition ); -#undef AF_INET6 -#define AF_INET6 666 - int bitlbee_daemon_init() { #ifdef IPV6 -- cgit v1.2.3 From 75a4b85ea060c5b63e9742ee9d1591bd618ba5c2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 14 Jul 2006 11:25:48 +0200 Subject: Fixed a memory leak, added a check for valid Jabber handles, and updated documentation (added information about "account set" and sorted the list of settings because it was a bit too random). --- doc/user-guide/commands.xml | 263 ++++++++++++++++++++++++++++---------------- doc/user-guide/help.xsl | 2 +- protocols/jabber/jabber.c | 7 ++ root_commands.c | 3 + 4 files changed, 177 insertions(+), 98 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 44a9882f..d28a8531 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -10,7 +10,7 @@ - Available actions: add, del, list, on, off. See help account <action> for more information. + Available actions: add, del, list, on, off and set. See help account <action> for more information. @@ -25,28 +25,28 @@ - account add jabber <handle> <password> [<servertag>] + account add jabber <handle@server.tld> <password> [<servertag>] - Note that the servertag argument is optional. You only have to use it if the part after the @ in your handle isn't the hostname of your Jabber server, or if you want to use SSL/connect to a non-standard port number. The format is simple: [<servername>[:<portnumber>][:ssl]]. For example, this is how you can connect to Google Talk: + Note that the servertag argument is optional. You only have to use it if the part after the @ in your handle isn't the hostname of your Jabber server, or if you want to use SSL/connect to a non-standard port number. The format is simple: [<servername>[:<portnumber>][:ssl]]. - - account add jabber example@gmail.com hobbelmeeuw talk.google.com:5223:ssl - Account successfully added - - - Note that Google talk is SSL-only, but officially reachable over both port 5222 and 5223. However, for some people only port 5222 works, for some people only 5223. This is something you'll have to try out. + Google Talk uses the Jabber protocol. Please note that Google talk is SSL-only, but officially reachable over both port 5222 and 5223. Usually BitlBee users have to connect via port 5223, for example like this: + + + account add jabber example@gmail.com hobbelmeeuw talk.google.com:5223:ssl + Account successfully added + - account add msn <handle> <password> + account add msn <handle@server.tld> <password> @@ -102,7 +102,7 @@ - This command will try to log into the specified account. If no account is specified, BitlBee will log into all the accounts. (Including accounts awaiting a reconnection) + This command will try to log into the specified account. If no account is specified, BitlBee will log into all the accounts that have the auto_connect flag set. @@ -117,7 +117,7 @@ - This command disconnects the connection for the specified account. If no account is specified, BitlBee will deactivate all active accounts. (Including accounts awaiting a reconnection) + This command disconnects the connection for the specified account. If no account is specified, BitlBee will deactivate all active accounts and cancel all pending reconnects. @@ -135,6 +135,26 @@ + + + account set <account id> + account set <account id>/<setting> + account set <account id>/<setting> <value> + + + + This account can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing account set <account id>. + + + + For more infomation about a setting, see help set <setting>. + + + + The account ID can be a number (see account list), the protocol name or (part of) the screenname, as long as it matches only one connection. + + + @@ -275,120 +295,145 @@ - - iso8859-1 - you can get a list of all possible values by doing 'iconv -l' in a shell + + True - 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. + With this option enabled, when you identify BitlBee will automatically connect to your accounts, with this disabled it will not do this. - + - 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 + This setting can also be changed for specific accounts using the account set command. (However, these values will be ignored if the global auto_connect setting is disabled!) - - - True + + False - - If value is true, messages from users will appear in separate query windows. If false, messages from users will appear in the control channel. + If an IM-connections breaks, you're supposed to bring it back up yourself. Having BitlBee do this automatically might not always be a good idea, for several reasons. If you want the connections to be restored automatically, you can enable this setting. - This setting is remembered (during one session) per-user, this setting only changes the default state. This option takes effect as soon as you reconnect. + See also the auto_reconnect_delay setting. + - - True + + 300 - If enabled causes BitlBee to save all current settings and account details when user disconnects. This is enabled by default, and these days there's not really a reason to have it disabled anymore. + Tell BitlBee after how many seconds it should attempt to bring an IM-connection back up after a crash. It's not a good idea to set this value very low, it will cause too much useless traffic when an IM-server is down for a few hours. + + + + See also the auto_reconnect setting. - + True - Determines what BitlBee should do with HTML in messages. Normally this is turned on and HTML will be stripped from messages, if BitlBee thinks there is HTML. - - - If BitlBee fails to detect this sometimes (most likely in AIM messages over an ICQ connection), you can set this setting to always, but this might sometimes accidentally strip non-HTML things too. + With this option enabled, the root user devoices people when they go away (just away, not offline) and gives the voice back when they come back. You might dislike the voice-floods you'll get if your contact list is huge, so this option can be disabled. - + False - Some debugging messages can be sent to the control channel if you wish. They're probably not really useful for you, unless you're doing some development on BitlBee. + By default, when you send a message to someone, BitlBee forwards this message to the user immediately. When you paste a large number of lines, the lines will be sent in separate messages, which might not be very nice to read. If you enable this setting, BitlBee will buffer your messages and wait for more data. + + + + Using the buddy_sendbuffer_delay setting you can specify the number of seconds BitlBee should wait for more data before the complete message is sent. + + + + Please note that if you remove a buddy from your list (or if the connection to that user drops) and there's still data in the buffer, this data will be lost. BitlBee will not try to send the message to the user in those cases. - - ": " + + 200 - It's customary that messages meant for one specific person on an IRC channel are prepended by his/her alias followed by a colon ':'. BitlBee does this by default. If you prefer a different character, you can set it using set to_char. + Tell BitlBee after how many (mili)seconds a buffered message should be sent. Values greater than 5 will be interpreted as miliseconds, 5 and lower as seconds. - Please note that this setting is only used for incoming messages. For outgoing messages you can use ':' (colon) or ',' to separate the destination nick from the message, and this is not configurable. + See also the buddy_sendbuffer setting. - - False + + iso8859-1 + you can get a list of all possible values by doing 'iconv -l' in a shell - 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. ;-) + 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. + + + + 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 + - - both - both, root, user, none + + False - Some people prefer themself and root to have operator status in &bitlbee, other people don't. You can change these states using this setting. + Some debugging messages can be sent to the control channel if you wish. They're probably not really useful for you, unless you're doing some development on BitlBee. + + + + + root + root, last + - The value "both" means both user and root get ops. "root" means, well, just root. "user" means just the user. "none" means nobody will get operator status. + With this value set to root, lines written in the control channel without any nickname in front of them will be interpreted as commands. If you want BitlBee to send those lines to the last person you addressed in the control channel, set this to last. - - True - + - With this option enabled, the root user devoices people when they go away (just away, not offline) and gives the voice back when they come back. You might dislike the voice-floods you'll get if your contact list is huge, so this option can be disabled. + Currently only available for MSN connections. This setting allows you to read and change your "friendly name" for this connection. Since this is a server-side setting, it can't be changed when the account is off-line. + + False + + + With this option enabled, root will inform you when someone in your buddy list changes his/her "friendly name". + + + root root, add, add_private, add_channel, ignore @@ -416,134 +461,158 @@ - + True - With this option enabled, when you identify BitlBee will automatically connect to your accounts, with this disabled it will not do this. + Hereby you can change whether you want all lower case nick names or leave the case as it intended by your peer. + - - False + + both + both, root, user, none - If an IM-connections breaks, you're supposed to bring it back up yourself. Having BitlBee do this automatically might not always be a good idea, for several reasons. If you want the connections to be restored automatically, you can enable this setting. + Some people prefer themself and root to have operator status in &bitlbee, other people don't. You can change these states using this setting. - See also the auto_reconnect_delay setting. + The value "both" means both user and root get ops. "root" means, well, just root. "user" means just the user. "none" means nobody will get operator status. - - - 300 - + - - Tell BitlBee after how many seconds it should attempt to bring an IM-connection back up after a crash. It's not a good idea to set this value very low, it will cause too much useless traffic when an IM-server is down for a few hours. + Use this global setting to change your "NickServ" password. - + - See also the auto_reconnect setting. + This setting is also available for all IM accounts to change the password BitlBee uses to connect to the service. + + + + Note that BitlBee will always say this setting is empty. This doesn't mean there is no password, it just means that, for security reasons, BitlBee stores passwords somewhere else so they can't just be retrieved in plain text. - - - False - + + - - By default, when you send a message to someone, BitlBee forwards this message to the user immediately. When you paste a large number of lines, the lines will be sent in separate messages, which might not be very nice to read. If you enable this setting, BitlBee will buffer your messages and wait for more data. + Currently only available for Jabber connections. Specifies the port number to connect to. Usually this should be set to 5222, or 5223 for SSL-connections. + + + + + True + - Using the buddy_sendbuffer_delay setting you can specify the number of seconds BitlBee should wait for more data before the complete message is sent. + If value is true, messages from users will appear in separate query windows. If false, messages from users will appear in the control channel. - Please note that if you remove a buddy from your list (or if the connection to that user drops) and there's still data in the buffer, this data will be lost. BitlBee will not try to send the message to the user in those cases. + This setting is remembered (during one session) per-user, this setting only changes the default state. This option takes effect as soon as you reconnect. - - - 200 + + lifo + lifo, fifo - - Tell BitlBee after how many (mili)seconds a buffered message should be sent. Values greater than 5 will be interpreted as miliseconds, 5 and lower as seconds. + This changes the order in which the questions from root (usually authorization requests from buddies) should be answered. When set to lifo, BitlBee immediately displays all new questions and they should be answered in reverse order. When this is set to fifo, BitlBee displays the first question which comes in and caches all the others until you answer the first one. - See also the buddy_sendbuffer setting. + Although the fifo setting might sound more logical (and used to be the default behaviour in older BitlBee versions), it turned out not to be very convenient for many users when they missed the first question (and never received the next ones). + + + BitlBee + + + + Can be set for Jabber connections. You can use this to connect to your Jabber account from multiple clients at once, with every client using a different resource string. + + - - root - root, last + + True - With this value set to root, lines written in the control channel without any nickname in front of them will be interpreted as commands. If you want BitlBee to send those lines to the last person you addressed in the control channel, set this to last. + If enabled causes BitlBee to save all current settings and account details when user disconnects. This is enabled by default, and these days there's not really a reason to have it disabled anymore. + + + + + Can be set for Jabber- and OSCAR-connections. For OSCAR, this must be set to login.icq.com if it's an ICQ connection, or login.oscar.aol.com if it's an AIM connection. For Jabber, you have to set this if the servername isn't equal to the part after the @ in the Jabber handle. + + - + False - - With this option enabled, root will inform you when someone in your buddy list changes his/her "friendly name". - + + + Currently only available for Jabber connections. Set this to true if the server accepts SSL connections. + + - + + True + - Use this setting to change your "NickServ" password. + Determines what BitlBee should do with HTML in messages. Normally this is turned on and HTML will be stripped from messages, if BitlBee thinks there is HTML. + + + If BitlBee fails to detect this sometimes (most likely in AIM messages over an ICQ connection), you can set this setting to always, but this might sometimes accidentally strip non-HTML things too. - - lifo - lifo, fifo + + ": " - This changes the order in which the questions from root (usually authorization requests from buddies) should be answered. When set to lifo, BitlBee immediately displays all new questions and they should be answered in reverse order. When this is set to fifo, BitlBee displays the first question which comes in and caches all the others until you answer the first one. + It's customary that messages meant for one specific person on an IRC channel are prepended by his/her alias followed by a colon ':'. BitlBee does this by default. If you prefer a different character, you can set it using set to_char. - Although the fifo setting might sound more logical (and used to be the default behaviour in older BitlBee versions), it turned out not to be very convenient for many users when they missed the first question (and never received the next ones). + Please note that this setting is only used for incoming messages. For outgoing messages you can use ':' (colon) or ',' to separate the destination nick from the message, and this is not configurable. - - True + + False - Hereby you can change whether you want all lower case nick names or leave the case as it intended by your peer. + 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. ;-) - diff --git a/doc/user-guide/help.xsl b/doc/user-guide/help.xsl index 0eb1a88b..394530a7 100644 --- a/doc/user-guide/help.xsl +++ b/doc/user-guide/help.xsl @@ -6,7 +6,7 @@ - + diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c index 7147a78c..e765a475 100644 --- a/protocols/jabber/jabber.c +++ b/protocols/jabber/jabber.c @@ -1548,6 +1548,13 @@ static void jabber_login(account_t *acc) gc = new_gaim_conn(acc); jd = gc->proto_data = g_new0(struct jabber_data, 1); + if( strchr( acc->user, '@' ) == NULL ) + { + hide_login_progress( gc, "Invalid account name" ); + signoff( gc ); + return; + } + resource = set_getstr(&acc->set, "resource"); loginname = create_valid_jid(acc->user, DEFAULT_SERVER, resource); diff --git a/root_commands.c b/root_commands.c index 2cf67134..389266eb 100644 --- a/root_commands.c +++ b/root_commands.c @@ -376,6 +376,7 @@ static void cmd_account( irc_t *irc, char **cmd ) if( a == NULL ) { + g_free( acc_handle ); irc_usermsg( irc, "Invalid account" ); return; } @@ -386,11 +387,13 @@ static void cmd_account( irc_t *irc, char **cmd ) if( a->gc && s && s->flags & ACC_SET_OFFLINE_ONLY ) { + g_free( acc_handle ); irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" ); return; } else if( !a->gc && s && s->flags & ACC_SET_ONLINE_ONLY ) { + g_free( acc_handle ); irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" ); return; } -- cgit v1.2.3 From 00a52700d1dbab0736c7ace63c8be2f17b08b8f6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 14 Jul 2006 20:24:59 +0200 Subject: Added a per-connection auto_reconnect setting. --- account.c | 2 ++ protocols/nogaim.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/account.c b/account.c index 28c33d3b..86e35f76 100644 --- a/account.c +++ b/account.c @@ -51,6 +51,8 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) s = set_add( &a->set, "auto_connect", "true", set_eval_account, a ); s->flags |= ACC_SET_NOSAVE; + s = set_add( &a->set, "auto_reconnect", "true", set_eval_account, a ); + s = set_add( &a->set, "password", NULL, set_eval_account, a ); s->flags |= ACC_SET_NOSAVE; diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 54965b84..f0008385 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -310,7 +310,8 @@ void signoff( struct gaim_connection *gc ) { /* Uhm... This is very sick. */ } - else if( !gc->wants_to_die && set_getint( &irc->set, "auto_reconnect" ) ) + else if( !gc->wants_to_die && set_getbool( &irc->set, "auto_reconnect" ) && + set_getbool( &a->set, "auto_reconnect" ) ) { int delay = set_getint( &irc->set, "auto_reconnect_delay" ); -- cgit v1.2.3 From 89a180978d3e5d81300b82923e8a208ee085d754 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 14 Jul 2006 20:27:02 +0200 Subject: More documentation updates: Added a Scope: line for every setting (for per-account and global settings) and leaving out the Default: line when there is no default specified in XML (like with the display_name setting). --- doc/user-guide/Makefile | 2 +- doc/user-guide/commands.xml | 79 +++++++++++++++++++++++---------------------- doc/user-guide/help.xsl | 5 ++- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/doc/user-guide/Makefile b/doc/user-guide/Makefile index 98c4e99f..eb31fc0f 100644 --- a/doc/user-guide/Makefile +++ b/doc/user-guide/Makefile @@ -27,7 +27,7 @@ help.xml: commands.xml %.db.xml: %.xml docbook.xsl xsltproc --xinclude --output $@ docbook.xsl $< -help.txt: help.xml help.xsl +help.txt: help.xml help.xsl commands.xml misc.xml quickstart.xml xsltproc --stringparam extraparanewline "$(EXTRAPARANEWLINE)" --xinclude help.xsl $< | perl -0077 -pe 's/\n\n%/\n%/s; s/_b_/\002/g;' > $@ clean: diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index d28a8531..fd855360 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -295,8 +295,8 @@ - - True + + true @@ -309,8 +309,8 @@ - - False + + false @@ -320,11 +320,14 @@ See also the auto_reconnect_delay setting. - + + This setting can also be changed for specific accounts using the account set command. (However, these values will be ignored if the global auto_reconnect setting is disabled!) + + - + 300 @@ -338,8 +341,8 @@ - - True + + true @@ -348,8 +351,8 @@ - - False + + false @@ -366,7 +369,7 @@ - + 200 @@ -381,7 +384,7 @@ - + iso8859-1 you can get a list of all possible values by doing 'iconv -l' in a shell @@ -397,8 +400,8 @@ - - False + + false @@ -407,7 +410,7 @@ - + root root, last @@ -418,7 +421,7 @@ - + Currently only available for MSN connections. This setting allows you to read and change your "friendly name" for this connection. Since this is a server-side setting, it can't be changed when the account is off-line. @@ -426,15 +429,15 @@ - - False + + false With this option enabled, root will inform you when someone in your buddy list changes his/her "friendly name". - + root root, add, add_private, add_channel, ignore @@ -461,8 +464,8 @@ - - True + + true @@ -472,7 +475,7 @@ - + both both, root, user, none @@ -487,7 +490,7 @@ - + Use this global setting to change your "NickServ" password. @@ -503,7 +506,7 @@ - + Currently only available for Jabber connections. Specifies the port number to connect to. Usually this should be set to 5222, or 5223 for SSL-connections. @@ -511,8 +514,8 @@ - - True + + true @@ -525,7 +528,7 @@ - + lifo lifo, fifo @@ -540,7 +543,7 @@ - + BitlBee @@ -550,8 +553,8 @@ - - True + + true @@ -560,7 +563,7 @@ - + Can be set for Jabber- and OSCAR-connections. For OSCAR, this must be set to login.icq.com if it's an ICQ connection, or login.oscar.aol.com if it's an AIM connection. For Jabber, you have to set this if the servername isn't equal to the part after the @ in the Jabber handle. @@ -568,8 +571,8 @@ - - False + + false @@ -578,8 +581,8 @@ - - True + + true @@ -591,7 +594,7 @@ - + ": " @@ -605,8 +608,8 @@ - - False + + false diff --git a/doc/user-guide/help.xsl b/doc/user-guide/help.xsl index 394530a7..dec6a671 100644 --- a/doc/user-guide/help.xsl +++ b/doc/user-guide/help.xsl @@ -57,7 +57,10 @@ Processing setting '' ?set _b_Type:_b_ - _b_Default:_b_ + _b_Scope:_b_ + + _b_Default:_b_ + _b_Possible Values:_b_ -- cgit v1.2.3 From 04026d44c29f2b7d64f81bb2d2d061a7d111662f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 15 Jul 2006 19:26:13 +0200 Subject: Fixed a broken call to set_get() (CRASH), shut up a compiler warning in events_glib and now using the right evaluator for acc->"auto_reconnect". --- account.c | 2 +- irc.c | 2 +- lib/events_glib.c | 5 ++++- lib/events_libevent.c | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/account.c b/account.c index 86e35f76..95aa9b7c 100644 --- a/account.c +++ b/account.c @@ -51,7 +51,7 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass ) s = set_add( &a->set, "auto_connect", "true", set_eval_account, a ); s->flags |= ACC_SET_NOSAVE; - s = set_add( &a->set, "auto_reconnect", "true", set_eval_account, a ); + s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a ); s = set_add( &a->set, "password", NULL, set_eval_account, a ); s->flags |= ACC_SET_NOSAVE; diff --git a/irc.c b/irc.c index 9feb9f4e..fcb59c86 100644 --- a/irc.c +++ b/irc.c @@ -623,7 +623,7 @@ void irc_names( irc_t *irc, char *channel ) user_t *u; char namelist[385] = ""; struct conversation *c = NULL; - char *ops = set_getstr( irc, "ops" ); + char *ops = set_getstr( &irc->set, "ops" ); /* RFCs say there is no error reply allowed on NAMES, so when the channel is invalid, just give an empty reply. */ diff --git a/lib/events_glib.c b/lib/events_glib.c index 620720cd..38938380 100644 --- a/lib/events_glib.c +++ b/lib/events_glib.c @@ -121,7 +121,10 @@ gint b_input_add(gint source, b_input_condition condition, b_event_handler funct gint b_timeout_add(gint timeout, b_event_handler func, gpointer data) { - gint st = g_timeout_add(timeout, func, data); + /* GSourceFunc and the BitlBee event handler function aren't + really the same, but they're "compatible". ;-) It will do + for now, BitlBee only looks at the "data" argument. */ + gint st = g_timeout_add(timeout, (GSourceFunc) func, data); event_debug( "b_timeout_add( %d, %d, %d ) = %d\n", timeout, func, data, st ); diff --git a/lib/events_libevent.c b/lib/events_libevent.c index 1119c2ab..f2b4d15c 100644 --- a/lib/events_libevent.c +++ b/lib/events_libevent.c @@ -100,7 +100,7 @@ static void b_event_passthrough( int fd, short event, void *data ) event_debug( "b_event_passthrough( %d, %d, 0x%x ) (%d)\n", fd, event, (int) data, b_ev->id ); /* Since the called function might cancel this handler already - (which free()s b_ev, we have to remember the ID here. */ + (which free()s b_ev), we have to remember the ID here. */ id = b_ev->id; if( quitting ) -- cgit v1.2.3 From 0aaca60fdc1a6793b438ecc926bd937073d22685 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 19 Jul 2006 18:52:38 +0200 Subject: Added some (more) comments to .h files in lib/ and some minor fixes/cleanups. --- doc/user-guide/commands.xml | 4 ++++ irc.c | 1 - lib/events.h | 31 ++++++++++++++++++++++++++----- lib/http_client.h | 45 +++++++++++++++++++++++++++++++++++---------- lib/rc4.h | 2 ++ lib/ssl_client.h | 30 ++++++++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index fd855360..0016d190 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -745,6 +745,10 @@ 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. + diff --git a/irc.c b/irc.c index fcb59c86..0373f176 100644 --- a/irc.c +++ b/irc.c @@ -651,7 +651,6 @@ void irc_names( irc_t *irc, char *channel ) else if( ( c = conv_findchannel( channel ) ) ) { GList *l; - char *ops = set_getstr( &irc->set, "ops" ); /* root and the user aren't in the channel userlist but should show up in /NAMES, so list them first: */ diff --git a/lib/events.h b/lib/events.h index 781fca6a..0588547f 100644 --- a/lib/events.h +++ b/lib/events.h @@ -19,11 +19,17 @@ * */ -/* - * Split off the event handling things from proxy.[ch] (and adding timer - * stuff. This to allow BitlBee to use other libs than GLib for event - * handling. - */ +/* This stuff used to be in proxy.c too, but I split it off so BitlBee can + use other libraries (like libevent) to handle events. proxy.c is one very + nice piece of work from Gaim. It connects to a TCP server in the back- + ground and calls a callback function once the connection is ready to use. + This function (proxy_connect()) can be found in proxy.c. (It also + transparently handles HTTP/SOCKS proxies, when necessary.) + + This file offers some extra event handling toys, which will be handled + by GLib or libevent. The advantage of using libevent is that it can use + more advanced I/O polling functions like epoll() in recent Linux + kernels. This should improve BitlBee's scalability. */ #ifndef _EVENTS_H_ @@ -38,12 +44,15 @@ #include #include +/* The conditions you can pass to gaim_input_add()/that will be passed to + the given callback function. */ typedef enum { GAIM_INPUT_READ = 1 << 1, GAIM_INPUT_WRITE = 1 << 2 } b_input_condition; typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition cond); +/* For internal use. */ #define GAIM_READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) #define GAIM_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) #define GAIM_ERR_COND (G_IO_HUP | G_IO_ERR | G_IO_NVAL) @@ -51,14 +60,26 @@ typedef gboolean (*b_event_handler)(gpointer data, gint fd, b_input_condition co // #define event_debug( x... ) printf( x ) #define event_debug( x... ) +/* Call this once when the program starts. It'll initialize the event handler + library (if necessary) and then return immediately. */ G_MODULE_EXPORT void b_main_init(); + +/* This one enters the event loop. It shouldn't return until one of the event + handlers calls b_main_quit(). */ G_MODULE_EXPORT void b_main_run(); G_MODULE_EXPORT void b_main_quit(); + +/* Add event handlers (for I/O or a timeout). The event handler will be called + every time the event "happens", until your event handler returns FALSE (or + until you remove it using b_event_remove(). As usual, the data argument + can be used to pass your own data to the event handler. */ G_MODULE_EXPORT gint b_input_add(int fd, b_input_condition cond, b_event_handler func, gpointer data); G_MODULE_EXPORT gint b_timeout_add(gint timeout, b_event_handler func, gpointer data); G_MODULE_EXPORT void b_event_remove(gint id); +/* For now, closesocket() is only a function when using libevent. With GLib + it's a preprocessor macro. */ #ifdef EVENTS_LIBEVENT G_MODULE_EXPORT void closesocket(int fd); #endif diff --git a/lib/http_client.h b/lib/http_client.h index 50ee80cf..78d6dbd1 100644 --- a/lib/http_client.h +++ b/lib/http_client.h @@ -23,24 +23,48 @@ Suite 330, Boston, MA 02111-1307 USA */ -#include +/* http_client allows you to talk (asynchronously, again) to HTTP servers. + In the "background" it will send the whole query and wait for a complete + response to come back. Right now it's only used by the MSN Passport + authentication code, but it might be useful for other things too (for + example the AIM usericon patch uses this so icons can be stored on + webservers instead of the local filesystem). + + Didn't test this too much, but it seems to work well. Just don't look + at the code that handles HTTP 30x redirects. ;-) The function is + probably not very useful for downloading lots of data since it keeps + everything in a memory buffer until the download is completed (and + can't pass any data or whatever before then). It's very useful for + doing quick requests without blocking the whole program, though. */ +#include #include "ssl_client.h" struct http_request; +/* Your callback function should look like this: */ typedef void (*http_input_function)( struct http_request * ); +/* This structure will be filled in by the http_dorequest* functions, and + it will be passed to the callback function. Use the data field to add + your own data. */ struct http_request { - char *request; - int request_length; - int status_code; - char *status_string; + char *request; /* The request to send to the server. */ + int request_length; /* Its size. */ + int status_code; /* The numeric HTTP status code. (Or -1 + if something really went wrong) */ + char *status_string; /* The error text. */ char *reply_headers; char *reply_body; - int body_size; - int finished; + int body_size; /* The number of bytes in reply_body. */ + int finished; /* Set to non-0 if the request was completed + successfully. */ + + http_input_function func; + gpointer data; + + /* Please don't touch the things down here, you shouldn't need them. */ void *ssl; int fd; @@ -48,10 +72,11 @@ struct http_request int inpa; int bytes_written; int bytes_read; - - http_input_function func; - gpointer data; }; +/* The _url variant is probably more useful than the raw version. The raw + version is probably only useful if you want to do POST requests or if + you want to add some extra headers. As you can see, HTTPS connections + are also supported (using ssl_client). */ void *http_dorequest( char *host, int port, int ssl, char *request, http_input_function func, gpointer data ); void *http_dorequest_url( char *url_string, http_input_function func, gpointer data ); diff --git a/lib/rc4.h b/lib/rc4.h index 6c9ea6b9..2d4d3cc8 100644 --- a/lib/rc4.h +++ b/lib/rc4.h @@ -22,6 +22,8 @@ \***************************************************************************/ +/* See rc4.c for more information. */ + struct rc4_state { unsigned char S[256]; diff --git a/lib/ssl_client.h b/lib/ssl_client.h index 1a9c79e9..964caee4 100644 --- a/lib/ssl_client.h +++ b/lib/ssl_client.h @@ -23,20 +23,50 @@ Suite 330, Boston, MA 02111-1307 USA */ +/* ssl_client makes it easier to open SSL connections to servers. (It + doesn't offer SSL server functionality yet, but it could be useful + to add it later.) Different ssl_client modules are available, and + ssl_client tries to make them all behave the same. It's very simple + and basic, it just imitates the proxy_connect() function from the + Gaim libs and passes the socket to the program once the handshake + is completed. */ + #include #include "proxy.h" +/* Some generic error codes. Especially SSL_AGAIN is important if you + want to do asynchronous I/O. */ #define SSL_OK 0 #define SSL_NOHANDSHAKE 1 #define SSL_AGAIN 2 extern int ssl_errno; +/* This is what your callback function should look like. */ typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition); + +/* Connect to host:port, call the given function when the connection is + ready to be used for SSL traffic. This is all done asynchronously, no + blocking I/O! (Except for the DNS lookups, for now...) */ G_MODULE_EXPORT void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data ); + +/* Obviously you need special read/write functions to read data. */ 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 ); + +/* 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_ ); + +/* Get the fd for this connection, you will usually need it for event + handling. */ G_MODULE_EXPORT int ssl_getfd( void *conn ); + +/* This function returns GAIM_INPUT_READ/WRITE. With SSL connections it's + possible that something has to be read while actually were trying to + write something (think about key exchange/refresh/etc). So when an + SSL operation returned SSL_AGAIN, *always* use this function when + adding an event handler to the queue. (And it should perform exactly + the same action as the handler that just received the SSL_AGAIN.) */ G_MODULE_EXPORT b_input_condition ssl_getdirection( void *conn ); -- cgit v1.2.3 From 2811940d678bd9340055e08a0462c21e710d5714 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 27 Jul 2006 16:55:53 +0200 Subject: Copy-paste considered harmful + Fixed double handling of gc->permit/deny which actually broke the block/allow commands. --- protocols/msn/msn_util.c | 35 ----------------------------------- root_commands.c | 2 +- 2 files changed, 1 insertion(+), 36 deletions(-) diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index c3bd73cc..4e748099 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -53,19 +53,8 @@ int msn_logged_in( struct gaim_connection *gc ) int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char *realname_ ) { struct msn_data *md = gc->proto_data; - GSList *l, **lp = NULL; char buf[1024], *realname; - if( strcmp( list, "AL" ) == 0 ) - lp = &gc->permit; - else if( strcmp( list, "BL" ) == 0 ) - lp = &gc->deny; - - if( lp ) - for( l = *lp; l; l = l->next ) - if( g_strcasecmp( l->data, who ) == 0 ) - return( 1 ); - realname = g_new0( char, strlen( realname_ ) * 3 + 1 ); strcpy( realname, realname_ ); http_encode( realname ); @@ -75,9 +64,6 @@ int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char { g_free( realname ); - if( lp ) - *lp = g_slist_append( *lp, g_strdup( who ) ); - return( 1 ); } @@ -89,32 +75,11 @@ int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char int msn_buddy_list_remove( struct gaim_connection *gc, char *list, char *who ) { struct msn_data *md = gc->proto_data; - GSList *l = NULL, **lp = NULL; char buf[1024]; - if( strcmp( list, "AL" ) == 0 ) - lp = &gc->permit; - else if( strcmp( list, "BL" ) == 0 ) - lp = &gc->deny; - - if( lp ) - { - for( l = *lp; l; l = l->next ) - if( g_strcasecmp( l->data, who ) == 0 ) - break; - - if( !l ) - return( 1 ); - } - g_snprintf( buf, sizeof( buf ), "REM %d %s %s\r\n", ++md->trId, list, who ); if( msn_write( gc, buf, strlen( buf ) ) ) - { - if( lp ) - *lp = g_slist_remove( *lp, l->data ); - return( 1 ); - } return( 0 ); } diff --git a/root_commands.c b/root_commands.c index 3d3584b3..040d885c 100644 --- a/root_commands.c +++ b/root_commands.c @@ -579,7 +579,7 @@ static void cmd_allow( irc_t *irc, char **cmd ) format = "%-32.32s %-16.16s"; irc_usermsg( irc, format, "Handle", "Nickname" ); - for( l = a->gc->deny; l; l = l->next ) + for( l = a->gc->permit; l; l = l->next ) { user_t *u = user_findhandle( a->gc, l->data ); irc_usermsg( irc, format, l->data, u ? u->nick : "(none)" ); -- cgit v1.2.3 From a36b030d747a39fed8224e6350d56d55b2aec4e2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Thu, 27 Jul 2006 21:18:33 +0200 Subject: The Yahoo! module now properly sets away states instead of away messages. (So other BitlBees can read your Yahoo! away states better and others can see the proper icons again.) --- protocols/yahoo/yahoo.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c index 79c0febb..28735432 100644 --- a/protocols/yahoo/yahoo.c +++ b/protocols/yahoo/yahoo.c @@ -191,13 +191,18 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg gc->away = NULL; - if( msg ) + if( state && msg && g_strcasecmp( state, msg ) != 0 ) { yd->current_status = YAHOO_STATUS_CUSTOM; gc->away = ""; } - if( state ) + else if( state ) { + /* Set msg to NULL since (if it isn't NULL already) it's equal + to state. msg must be empty if we want to use an existing + away state. */ + msg = NULL; + gc->away = ""; if( g_strcasecmp( state, "Available" ) == 0 ) { @@ -234,10 +239,7 @@ static void byahoo_set_away( struct gaim_connection *gc, char *state, char *msg else yd->current_status = YAHOO_STATUS_AVAILABLE; - if( yd->current_status == YAHOO_STATUS_INVISIBLE ) - yahoo_set_away( yd->y2_id, yd->current_status, NULL, gc->away != NULL ); - else - yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL ); + yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL ); } static GList *byahoo_away_states( struct gaim_connection *gc ) -- cgit v1.2.3 From d3a672c0b70eb7b50dcd2908d6cd6928d4f7d874 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 4 Aug 2006 15:56:53 +0200 Subject: Added a per-account web_aware setting for ICQ connections. --- protocols/oscar/oscar.c | 5 +++++ protocols/oscar/service.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index f65332dc..d30ebbe8 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -361,6 +361,11 @@ static void oscar_acc_init(account_t *acc) s = set_add( &acc->set, "server", NULL, set_eval_account, acc ); s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; + + if (isdigit(acc->user[0])) { + s = set_add( &acc->set, "web_aware", "false", set_eval_bool, acc ); + s->flags |= ACC_SET_OFFLINE_ONLY; + } } static void oscar_login(account_t *acc) { diff --git a/protocols/oscar/service.c b/protocols/oscar/service.c index 4596974f..d55e0987 100644 --- a/protocols/oscar/service.c +++ b/protocols/oscar/service.c @@ -731,8 +731,12 @@ int aim_setextstatus(aim_session_t *sess, aim_conn_t *conn, guint32 status) aim_tlvlist_t *tl = NULL; guint32 data; int tlvlen; + struct gaim_connection *gc = sess ? sess->aux_data : NULL; data = AIM_ICQ_STATE_HIDEIP | status; /* yay for error checking ;^) */ + + if (gc && set_getbool(&gc->acc->set, "web_aware")) + data |= AIM_ICQ_STATE_WEBAWARE; tlvlen = aim_addtlvtochain32(&tl, 0x0006, data); -- cgit v1.2.3 From 846cec61f2b94be60c7bae7f4d0de8952e2d45fa Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 13 Aug 2006 21:08:38 +0200 Subject: Added help information for the web_aware setting. --- doc/user-guide/commands.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 0016d190..790e89f6 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -618,6 +618,20 @@ + + false + + + + ICQ allows people to see if you're on-line via a CGI-script. (http://status.icq.com/online.gif?icq=UIN) This can be nice to put on your website, but it seems that spammers also use it to see if you're online without having to add you to their contact list. So to prevent ICQ spamming, recent versions of BitlBee disable this feature by default. + + + + Unless you really intend to use this feature somewhere (on forums or maybe a website), it's probably better to keep this setting disabled. + + + + Rename (renick) a buddy rename <oldnick> <newnick> -- cgit v1.2.3 From d5ccd83c5235528df2481003502647b86b41fdc4 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 13 Aug 2006 21:15:23 +0200 Subject: Extra comments in set.h and now properly using set_getbool() instead of set_getint(). --- irc.c | 4 ++-- protocols/nogaim.c | 34 +++++++++++++++++----------------- protocols/oscar/oscar.c | 4 ---- protocols/oscar/rxhandlers.c | 4 ---- root_commands.c | 2 +- set.h | 36 +++++++++++++++++++++++++++++++++--- user.c | 2 +- 7 files changed, 54 insertions(+), 32 deletions(-) diff --git a/irc.c b/irc.c index 0373f176..87cc4c78 100644 --- a/irc.c +++ b/irc.c @@ -212,7 +212,7 @@ void irc_free(irc_t * irc) log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd ); - if( irc->status & USTATUS_IDENTIFIED && set_getint( &irc->set, "save_on_quit" ) ) + if( irc->status & USTATUS_IDENTIFIED && set_getbool( &irc->set, "save_on_quit" ) ) if( storage_save( irc, TRUE ) != STORAGE_OK ) irc_usermsg( irc, "Error while saving settings!" ); @@ -1057,7 +1057,7 @@ void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags ) { if( !u || !u->gc ) return; - if( set_getint( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 ) + if( set_getbool( &irc->set, "buddy_sendbuffer" ) && set_getint( &irc->set, "buddy_sendbuffer_delay" ) > 0 ) { int delay; diff --git a/protocols/nogaim.c b/protocols/nogaim.c index f0008385..47e2bda6 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -207,7 +207,7 @@ void serv_got_crap( struct gaim_connection *gc, char *format, ... ) va_end( params ); if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getint( &gc->irc->set, "strip_html" ) ) ) + ( ( gc->flags & OPT_CONN_HTML ) && set_getbool( &gc->irc->set, "strip_html" ) ) ) strip_html( text ); /* Try to find a different connection on the same protocol. */ @@ -352,12 +352,12 @@ void add_buddy( struct gaim_connection *gc, char *group, char *handle, char *rea char *s; irc_t *irc = gc->irc; - if( set_getint( &irc->set, "debug" ) && 0 ) /* This message is too useless */ + if( set_getbool( &irc->set, "debug" ) && 0 ) /* This message is too useless */ serv_got_crap( gc, "Receiving user add from handle: %s", handle ); if( user_findhandle( gc, handle ) ) { - if( set_getint( &irc->set, "debug" ) ) + if( set_getbool( &irc->set, "debug" ) ) serv_got_crap( gc, "User already exists, ignoring add request: %s", handle ); return; @@ -445,7 +445,7 @@ void serv_buddy_rename( struct gaim_connection *gc, char *handle, char *realname u->realname = g_strdup( realname ); - if( ( gc->flags & OPT_LOGGED_IN ) && set_getint( &gc->irc->set, "display_namechanges" ) ) + if( ( gc->flags & OPT_LOGGED_IN ) && set_getbool( &gc->irc->set, "display_namechanges" ) ) serv_got_crap( gc, "User `%s' changed name to `%s'", u->nick, u->realname ); } } @@ -508,7 +508,7 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in } else { - if( set_getint( &gc->irc->set, "debug" ) || g_strcasecmp( set_getstr( &gc->irc->set, "handle_unknown" ), "ignore" ) != 0 ) + if( set_getbool( &gc->irc->set, "debug" ) || g_strcasecmp( set_getstr( &gc->irc->set, "handle_unknown" ), "ignore" ) != 0 ) { serv_got_crap( gc, "serv_got_update() for handle %s:", handle ); serv_got_crap( gc, "loggedin = %d, type = %d", loggedin, type ); @@ -567,7 +567,7 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in u->away = NULL; /* LISPy... */ - if( ( set_getint( &gc->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ + if( ( set_getbool( &gc->irc->set, "away_devoice" ) ) && /* Don't do a thing when user doesn't want it */ ( u->online ) && /* Don't touch offline people */ ( ( ( u->online != oo ) && !u->away ) || /* Voice joining people */ ( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* (De)voice people changing state */ @@ -590,14 +590,14 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f if( g_strcasecmp( h, "ignore" ) == 0 ) { - if( set_getint( &irc->set, "debug" ) ) + if( set_getbool( &irc->set, "debug" ) ) serv_got_crap( gc, "Ignoring message from unknown handle %s", handle ); return; } else if( g_strncasecmp( h, "add", 3 ) == 0 ) { - int private = set_getint( &irc->set, "private" ); + int private = set_getbool( &irc->set, "private" ); if( h[3] ) { @@ -619,7 +619,7 @@ void serv_got_im( struct gaim_connection *gc, char *handle, char *msg, guint32 f } if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getint( &gc->irc->set, "strip_html" ) ) ) + ( ( gc->flags & OPT_CONN_HTML ) && set_getbool( &gc->irc->set, "strip_html" ) ) ) strip_html( msg ); while( strlen( msg ) > 425 ) @@ -659,7 +659,7 @@ void serv_got_typing( struct gaim_connection *gc, char *handle, int timeout, int { user_t *u; - if( !set_getint( &gc->irc->set, "typing_notice" ) ) + if( !set_getbool( &gc->irc->set, "typing_notice" ) ) return; if( ( u = user_findhandle( gc, handle ) ) ) { @@ -681,7 +681,7 @@ void serv_got_chat_left( struct gaim_connection *gc, int id ) struct conversation *c, *l = NULL; GList *ir; - if( set_getint( &gc->irc->set, "debug" ) ) + if( set_getbool( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "You were removed from conversation %d", (int) id ); for( c = gc->conversations; c && c->id != id; c = (l=c)->next ); @@ -727,7 +727,7 @@ void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whispe for( c = gc->conversations; c && c->id != id; c = c->next ); if( ( g_strcasecmp( set_getstr( &gc->irc->set, "strip_html" ), "always" ) == 0 ) || - ( ( gc->flags & OPT_CONN_HTML ) && set_getint( &gc->irc->set, "strip_html" ) ) ) + ( ( gc->flags & OPT_CONN_HTML ) && set_getbool( &gc->irc->set, "strip_html" ) ) ) strip_html( msg ); if( c && u ) @@ -760,7 +760,7 @@ struct conversation *serv_got_joined_chat( struct gaim_connection *gc, int id, c c->channel = g_strdup( s ); g_free( s ); - if( set_getint( &gc->irc->set, "debug" ) ) + if( set_getbool( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "Creating new conversation: (id=%d,handle=%s)", id, handle ); return( c ); @@ -774,7 +774,7 @@ void add_chat_buddy( struct conversation *b, char *handle ) user_t *u = user_findhandle( b->gc, handle ); int me = 0; - if( set_getint( &b->gc->irc->set, "debug" ) ) + if( set_getbool( &b->gc->irc->set, "debug" ) ) serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id ); /* It might be yourself! */ @@ -808,7 +808,7 @@ void remove_chat_buddy( struct conversation *b, char *handle, char *reason ) user_t *u; int me = 0; - if( set_getint( &b->gc->irc->set, "debug" ) ) + if( set_getbool( &b->gc->irc->set, "debug" ) ) serv_got_crap( b->gc, "User %s removed from conversation %d (%s)", handle, b->id, reason ? reason : "" ); /* It might be yourself! */ @@ -886,7 +886,7 @@ char *set_eval_away_devoice( set_t *set, char *value ) /* Horror.... */ - if( st != set_getint( &irc->set, "away_devoice" ) ) + if( st != set_getbool( &irc->set, "away_devoice" ) ) { char list[80] = ""; user_t *u = irc->users; @@ -1006,7 +1006,7 @@ int bim_set_away( struct gaim_connection *gc, char *away ) if( s ) { gc->acc->prpl->set_away( gc, s, away ); - if( set_getint( &gc->irc->set, "debug" ) ) + if( set_getbool( &gc->irc->set, "debug" ) ) serv_got_crap( gc, "Setting away state to %s", s ); } else diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index d30ebbe8..b8cf521b 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -1251,10 +1251,6 @@ static int gaim_parse_incoming_im(aim_session_t *sess, aim_frame_t *fr, ...) { channel = va_arg(ap, int); userinfo = va_arg(ap, aim_userinfo_t *); - if (set_getint(sess->aux_data, "debug")) { - serv_got_crap(sess->aux_data, "channel %i called", channel); - } - switch (channel) { case 1: { /* standard message */ struct aim_incomingim_ch1_args *args; diff --git a/protocols/oscar/rxhandlers.c b/protocols/oscar/rxhandlers.c index be8aba44..7014e693 100644 --- a/protocols/oscar/rxhandlers.c +++ b/protocols/oscar/rxhandlers.c @@ -112,10 +112,6 @@ static int consumesnac(aim_session_t *sess, aim_frame_t *rx) /* Following SNAC will be related */ } - if (set_getint(sess->aux_data, "debug")) { - serv_got_crap(sess->aux_data, "snac %x/%x received", snac.family, snac.subtype); - } - for (cur = (aim_module_t *)sess->modlistv; cur; cur = cur->next) { if (!(cur->flags & AIM_MODFLAG_MULTIFAMILY) && diff --git a/root_commands.c b/root_commands.c index 389266eb..13567e8a 100644 --- a/root_commands.c +++ b/root_commands.c @@ -143,7 +143,7 @@ static void cmd_identify( irc_t *irc, char **cmd ) case STORAGE_OK: irc_usermsg( irc, "Password accepted, settings and accounts loaded" ); irc_umode_set( irc, "+R", 1 ); - if( set_getint( &irc->set, "auto_connect" ) ) + if( set_getbool( &irc->set, "auto_connect" ) ) cmd_account( irc, account_on ); break; case STORAGE_OTHER_ERROR: diff --git a/set.h b/set.h index 48bc8145..14043c2f 100644 --- a/set.h +++ b/set.h @@ -23,15 +23,30 @@ Suite 330, Boston, MA 02111-1307 USA */ +/* This used to be specific to irc_t structures, but it's more generic now + (so it can also be used for account_t structs). It's pretty simple, but + so far pretty useful. + + In short, it just keeps a linked list of settings/variables and it also + remembers a default value for every setting. And to prevent the user + from setting invalid values, you can write an evaluator function for + every setting, which can check a new value and block it by returning + NULL, or replace it by returning a new value. See struct set.eval. */ + typedef struct set { - void *data; + void *data; /* Here you can save a pointer to the + object this settings belongs to. */ char *key; char *value; - char *def; /* Default */ + char *def; /* Default value. If the set_setstr() function + notices a new value is exactly the same as + the default, value gets set to NULL. So when + you read a setting, don't forget about this! */ - int flags; + int flags; /* See account.h, for example. set.c doesn't use + this (yet?). */ /* Eval: Returns NULL if the value is incorrect or exactly the passed value variable. When returning a corrected value, @@ -40,18 +55,33 @@ typedef struct set struct set *next; } set_t; +/* Should be pretty clear. */ set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ); + +/* Returns the raw set_t. Might be useful sometimes. */ set_t *set_find( set_t **head, char *key ); + +/* Returns a pointer to the string value of this setting. Don't modify the + returned string, and don't free() it! */ G_MODULE_EXPORT char *set_getstr( set_t **head, char *key ); + +/* Get an integer. Right now this also converts true/false/on/off/etc to + numbers, but this is for historical reasons, please use set_getbool() + for booleans instead. */ G_MODULE_EXPORT int set_getint( set_t **head, char *key ); G_MODULE_EXPORT int set_getbool( set_t **head, char *key ); + +/* set_setstr() strdup()s the given value, so after using this function + you can free() it, if you want. */ int set_setstr( set_t **head, char *key, char *value ); int set_setint( set_t **head, char *key, int value ); void set_del( set_t **head, char *key ); +/* Two very useful generic evaluators. */ char *set_eval_int( set_t *set, char *value ); 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 ); diff --git a/user.c b/user.c index 0892a23c..ff65fe66 100644 --- a/user.c +++ b/user.c @@ -66,7 +66,7 @@ user_t *user_add( irc_t *irc, char *nick ) } u->user = u->realname = u->host = u->nick = g_strdup( nick ); - u->is_private = set_getint( &irc->set, "private" ); + u->is_private = set_getbool( &irc->set, "private" ); key = g_strdup( nick ); nick_lc( key ); -- cgit v1.2.3 From 08cdb93834bcc1b67e4e7f44e8bc90b42c686658 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 14 Aug 2006 15:25:05 +0200 Subject: Updated the note about encryption in the README file. --- doc/README | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/doc/README b/doc/README index c82c9aeb..75988004 100644 --- a/doc/README +++ b/doc/README @@ -154,17 +154,27 @@ http://code.bitlbee.org/ A NOTE ON ENCRYPTION ==================== -BitlBee stores the accounts and settings (not your contact list though) in -some sort of encrypted/obfuscated format. - -*** THIS IS NOT A SAFE FORMAT! *** - -You should still make sure the rights to the configuration directory and -files are set so that only root and the BitlBee user can read/write them. - -This format is not to prevent malicicous users from running with your -passwords, but to prevent accidental glimpses of the administrators to cause -any harm. You have no choice but to trust root though. +There used to be a note here about the simple obfuscation method used to +make the passwords in the configuration files unreadable. However, BitlBee +now uses a better format (and real encryption (salted MD5 and RC4)) to store +the passwords. This means that people who somehow get their hands on your +configuration files can't easily extract your passwords from them anymore. + +However, once you log into the BitlBee server and send your password, an +intruder with tcpdump can still read your passwords. This can't really be +avoided, of course. The new format is a lot more reliable (because it can't +be cracked with just very basic crypto analysis anymore), but you still have +to be careful. The main extra protection offered by the new format is that +the files can only be cracked with some help from the user (by sending the +password at login time). + +So if you run a public server, it's most important that you don't give root +access to people who like to play with tcpdump. Also, it's a good idea to +delete all *.nicks/*.accounts files as soon as BitlBee converted them to the +new format (which happens as soon as the user logs in, it can't be done +automatically because it needs the password for that account). You won't +need them anymore (unless you want to switch back to an older BitlBee +version) and they only make it easier for others to crack your passwords. LEGAL @@ -191,5 +201,5 @@ also licensed under the GPL. BitlBee - An IRC to other chat networks gateway - Copyright (C) 2002-2005 Wilmer van der Gaast + Copyright (C) 2002-2006 Wilmer van der Gaast and others -- cgit v1.2.3 From d1f8759e5034dacb489123719ca86c5d802f154d Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 14 Aug 2006 21:32:43 +0200 Subject: Just a little typo in rc4.c --- lib/rc4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rc4.c b/lib/rc4.c index 5e334507..6223077a 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -45,7 +45,7 @@ #include "rc4.h" /* Add some seed to the password, to make sure we *never* use the same key. - This defines how many byes we use as a seed. */ + This defines how many bytes we use as a seed. */ #define RC4_IV_LEN 6 /* To defend against a "Fluhrer, Mantin and Shamir attack", it is recommended -- cgit v1.2.3 From 9829ae028dc1f0d8ab60cb18293234f2d4cc19b8 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 14 Aug 2006 22:17:54 +0200 Subject: Added information about the new file format to CHANGES. --- doc/CHANGES | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/CHANGES b/doc/CHANGES index 7b95e8cb..cd100741 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,3 +1,27 @@ +Version x.x: +- 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 + new format. It is recommended to delete the old files (BitlBee doesn't do + this automatically, it will just ignore them) since they won't be used + anymore (and since the old file format is a security risk). Some advantages + of this file format switch: + * Safer format, since the identify-password is now salted before generating + a checksum. This way one can't use MD5 reverse lookup databases to crack + passwords. Also, the IM-account passwords are encrypted using RC4 instead + of the simple obfuscation scheme which BitlBee used so far. + * Easier to extend than the previous format (at least the .nicks format was + horribly limited). + * Nicknames for buddies are now saved per-account instead of per-protocol. + So far having one buddy on multiple accounts of the same protocol was a + problem because the nicks generated for the two "instances" of this buddy + were very unpredictable. + NOTE: This also means that "account del" removes not just the account, + BUT ALSO ALL NICKNAMES! If you're changing IM accounts and don't want to + lose the nicknames, you can now use "account set" to change the username + and password for the existing connection. + * Per-account settings (see the new "account set" command). + Version 1.0: - Removed some crashy debugging code. - QUIT command now works before logging in. (Mainly an RFC-compliancy fix.) -- cgit v1.2.3 From 0383943c38ee308805798974bfccbd3327369c6a Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 25 Aug 2006 00:06:52 +0200 Subject: Added message on successful creation of accounts and fixed "set password" command. --- irc.c | 4 +++- root_commands.c | 1 + set.c | 2 +- set.h | 6 ++++-- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/irc.c b/irc.c index 87cc4c78..8f79b535 100644 --- a/irc.c +++ b/irc.c @@ -32,8 +32,10 @@ static gboolean irc_userping( gpointer _irc, int fd, b_input_condition cond ); GSList *irc_connection_list = NULL; -static char *passchange( irc_t *irc, void *set, char *value ) +static char *passchange( set_t *set, char *value ) { + irc_t *irc = set->data; + irc_setpass( irc, value ); irc_usermsg( irc, "Password successfully changed" ); return NULL; diff --git a/root_commands.c b/root_commands.c index 13567e8a..3097dc81 100644 --- a/root_commands.c +++ b/root_commands.c @@ -168,6 +168,7 @@ static void cmd_register( irc_t *irc, char **cmd ) break; case STORAGE_OK: + irc_usermsg( irc, "Account successfully created" ); irc->status |= USTATUS_IDENTIFIED; irc_umode_set( irc, "+R", 1 ); break; diff --git a/set.c b/set.c index 4620264f..6a45fd14 100644 --- a/set.c +++ b/set.c @@ -25,7 +25,7 @@ #define BITLBEE_CORE #include "bitlbee.h" -set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ) +set_t *set_add( set_t **head, char *key, char *def, set_eval eval, void *data ) { set_t *s = set_find( head, key ); diff --git a/set.h b/set.h index 14043c2f..37d2430f 100644 --- a/set.h +++ b/set.h @@ -33,6 +33,8 @@ every setting, which can check a new value and block it by returning NULL, or replace it by returning a new value. See struct set.eval. */ +typedef char *(*set_eval) ( struct set *set, char *value ); + typedef struct set { void *data; /* Here you can save a pointer to the @@ -51,12 +53,12 @@ typedef struct set /* Eval: Returns NULL if the value is incorrect or exactly the passed value variable. When returning a corrected value, set_setstr() should be able to free() the returned string! */ - char *(*eval) ( struct set *set, char *value ); + set_eval eval; struct set *next; } set_t; /* Should be pretty clear. */ -set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ); +set_t *set_add( set_t **head, char *key, char *def, set_eval eval, void *data ); /* Returns the raw set_t. Might be useful sometimes. */ set_t *set_find( set_t **head, char *key ); -- cgit v1.2.3 From 54794b8e01b5cce0675e9cfbd7282d011ebcb99e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 25 Aug 2006 14:34:36 +0200 Subject: Added msn_http_encode() so it can be used in msn_buddy_list_add() too. Most likely fixes #198. --- protocols/msn/msn.c | 20 ++------------------ protocols/msn/msn.h | 1 + protocols/msn/msn_util.c | 30 +++++++++++++++++++++++++++--- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index a8d85a66..0d2d7283 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -211,8 +211,7 @@ static void msn_set_away( struct gaim_connection *gc, char *state, char *message static void msn_set_info( struct gaim_connection *gc, char *info ) { - int i; - char buf[1024], *fn, *s; + char buf[1024], *fn; struct msn_data *md = gc->proto_data; if( strlen( info ) > 129 ) @@ -221,22 +220,7 @@ static void msn_set_info( struct gaim_connection *gc, char *info ) return; } - /* Of course we could use http_encode() here, but when we encode - every character, the server is less likely to complain about the - chosen name. However, the MSN server doesn't seem to like escaped - non-ASCII chars, so we keep those unescaped. */ - s = fn = g_new0( char, strlen( info ) * 3 + 1 ); - for( i = 0; info[i]; i ++ ) - if( info[i] & 128 ) - { - *s = info[i]; - s ++; - } - else - { - g_snprintf( s, 4, "%%%02X", info[i] ); - s += 3; - } + fn = msn_http_encode( info ); g_snprintf( buf, sizeof( buf ), "REA %d %s %s\r\n", ++md->trId, gc->username, fn ); msn_write( gc, buf, strlen( buf ) ); diff --git a/protocols/msn/msn.h b/protocols/msn/msn.h index dbbb6aa0..b4777d41 100644 --- a/protocols/msn/msn.h +++ b/protocols/msn/msn.h @@ -156,6 +156,7 @@ void msn_buddy_ask( struct gaim_connection *gc, char *handle, char *realname ); char *msn_findheader( char *text, char *header, int len ); char **msn_linesplit( char *line ); int msn_handler( struct msn_handler_data *h ); +char *msn_http_encode( const char *input ); /* tables.c */ const struct msn_away_state *msn_away_state_by_number( int number ); diff --git a/protocols/msn/msn_util.c b/protocols/msn/msn_util.c index 4e748099..ff4c148c 100644 --- a/protocols/msn/msn_util.c +++ b/protocols/msn/msn_util.c @@ -55,9 +55,7 @@ int msn_buddy_list_add( struct gaim_connection *gc, char *list, char *who, char struct msn_data *md = gc->proto_data; char buf[1024], *realname; - realname = g_new0( char, strlen( realname_ ) * 3 + 1 ); - strcpy( realname, realname_ ); - http_encode( realname ); + realname = msn_http_encode( realname_ ); g_snprintf( buf, sizeof( buf ), "ADD %d %s %s %s\r\n", ++md->trId, list, who, realname ); if( msn_write( gc, buf, strlen( buf ) ) ) @@ -314,3 +312,29 @@ int msn_handler( struct msn_handler_data *h ) return( 1 ); } + +/* The difference between this function and the normal http_encode() function + is that this one escapes every 7-bit ASCII character because this is said + to avoid some lame server-side checks when setting a real-name. Also, + non-ASCII characters are not escaped because MSN servers don't seem to + appreciate that! */ +char *msn_http_encode( const char *input ) +{ + char *ret, *s; + int i; + + ret = s = g_new0( char, strlen( input ) * 3 + 1 ); + for( i = 0; input[i]; i ++ ) + if( input[i] & 128 ) + { + *s = input[i]; + s ++; + } + else + { + g_snprintf( s, 4, "%%%02X", input[i] ); + s += 3; + } + + return ret; +} -- cgit v1.2.3 From 8320a7a0012f868e5878a5a9f52676a5fece02e1 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Sep 2006 17:30:35 +0200 Subject: Strings passed to xml_text aren't necessarily \0-terminated, so don't count on that anymore. --- storage_xml.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storage_xml.c b/storage_xml.c index 2585b475..52240a36 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -226,11 +226,15 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name } } -static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error ) +static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize text_len, gpointer data, GError **error ) { + char text[text_len+1]; struct xml_parsedata *xd = data; irc_t *irc = xd->irc; + strncpy( text, text_orig, text_len ); + text[text_len] = 0; + if( xd->pass_st < XML_PASS_OK ) { /* Let's not parse anything else if we only have to check -- cgit v1.2.3 From 51fdc4512cc77fd6b59b582f27887657d7c3721e Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 17 Sep 2006 17:56:16 +0200 Subject: add_cr() is not used anymore, and HTML entity handling got UTFized some time ago already, so no need for that FIXME comment. --- lib/misc.c | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/lib/misc.c b/lib/misc.c index 17599946..64666492 100644 --- a/lib/misc.c +++ b/lib/misc.c @@ -53,36 +53,6 @@ void strip_linefeed(gchar *text) g_free(text2); } -char *add_cr(char *text) -{ - char *ret = NULL; - int count = 0, j; - unsigned int i; - - if (text[0] == '\n') - count++; - for (i = 1; i < strlen(text); i++) - if (text[i] == '\n' && text[i - 1] != '\r') - count++; - - if (count == 0) - return g_strdup(text); - - ret = g_malloc0(strlen(text) + count + 1); - - i = 0; j = 0; - if (text[i] == '\n') - ret[j++] = '\r'; - ret[j++] = text[i++]; - for (; i < strlen(text); i++) { - if (text[i] == '\n' && text[i - 1] != '\r') - ret[j++] = '\r'; - ret[j++] = text[i]; - } - - return ret; -} - char *normalize(const char *s) { static char buf[BUF_LEN]; @@ -123,12 +93,10 @@ time_t get_time(int year, int month, int day, int hour, int min, int sec) typedef struct htmlentity { - char code[8]; - char is[4]; + char code[7]; + char is[3]; } htmlentity_t; -/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */ - static const htmlentity_t ent[] = { { "lt", "<" }, -- cgit v1.2.3 From 9544acba1fecb11b0b6a0e6260e302890d4c2337 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Wed, 20 Sep 2006 11:34:02 +0200 Subject: Using LGPL for generic parts, where possible. --- lib/rc4.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/rc4.c b/lib/rc4.c index 6223077a..f2c76f54 100644 --- a/lib/rc4.c +++ b/lib/rc4.c @@ -5,19 +5,19 @@ * * * Copyright 2006 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 as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * +* 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 program is distributed in the hope that it will be useful, * +* 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 General Public License for more details. * +* 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 General Public License along * -* with this program; if not, write to the Free Software Foundation, Inc., * -* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * +* 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 * * * \***************************************************************************/ -- cgit v1.2.3 From 695e39232324711816f1db8e25fdba59a0c6456f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 13 Oct 2006 23:44:54 +0200 Subject: Fixed some memory leaking in the MSN Passport code. --- protocols/msn/passport.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index dd1d9b6f..42b6ea73 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -58,6 +58,7 @@ static int passport_get_id_real( gpointer func, gpointer data, char *header ) rep = g_new0( struct passport_reply, 1 ); rep->data = data; rep->func = func; + rep->header = header; server = g_strdup( prd_cached ); dummy = strchr( server, '/' ); @@ -124,10 +125,14 @@ static void passport_get_id_ready( struct http_request *req ) static char *passport_create_header( char *cookie, char *email, char *pwd ) { - char *buffer = g_new0( char, 2048 ); + 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 ); @@ -136,20 +141,15 @@ static char *passport_create_header( char *cookie, char *email, char *pwd ) strcpy( pwd_enc, pwd ); http_encode( pwd_enc ); - currenttoken = strstr( cookie, "lc=" ); - if( currenttoken == NULL ) - return( NULL ); - - g_snprintf( buffer, 2048, - "Authorization: Passport1.4 OrgVerb=GET," - "OrgURL=http%%3A%%2F%%2Fmessenger%%2Emsn%%2Ecom," - "sign-in=%s,pwd=%s,%s", email_enc, pwd_enc, - currenttoken ); + 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 ); - return( buffer ); + return buffer; } static int passport_retrieve_dalogin( gpointer func, gpointer data, char *header ) -- cgit v1.2.3 From 3ef6410bab141e5c6ea465730a37289991c38f9f Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Oct 2006 11:26:06 +0200 Subject: Removed a reference to an already free()d variable from cmd_remove(). --- root_commands.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/root_commands.c b/root_commands.c index 3097dc81..64dc71b9 100644 --- a/root_commands.c +++ b/root_commands.c @@ -572,7 +572,7 @@ static void cmd_remove( irc_t *irc, char **cmd ) u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL ); user_del( irc, cmd[1] ); - nick_del( u->gc->acc, u->handle ); + nick_del( u->gc->acc, s ); irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] ); g_free( s ); -- cgit v1.2.3 From 2529faf12adfc414048dc41e949065855d0da945 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Oct 2006 16:02:27 +0200 Subject: Small documentation fix (closes #208). --- doc/user-guide/commands.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml index 790e89f6..a920cfae 100644 --- a/doc/user-guide/commands.xml +++ b/doc/user-guide/commands.xml @@ -432,9 +432,11 @@ false - - With this option enabled, root will inform you when someone in your buddy list changes his/her "friendly name". - + + + With this option enabled, root will inform you when someone in your buddy list changes his/her "friendly name". + + -- cgit v1.2.3 From 3dc9d46cc20d287c266fed97f92d298ed721f7b3 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Oct 2006 17:32:46 +0200 Subject: Fixed a very interesting memory leak in the OSCAR module. --- protocols/msn/msn.c | 1 - protocols/oscar/info.c | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index 46049108..f7e57707 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -366,7 +366,6 @@ static char *msn_set_display_name( set_t *set, char *value ) struct gaim_connection *gc = acc->gc; struct msn_data *md; char buf[1024], *fn; - int i; /* Double-check. */ if( gc == NULL ) diff --git a/protocols/oscar/info.c b/protocols/oscar/info.c index ffe29d1f..0f1bcfd2 100644 --- a/protocols/oscar/info.c +++ b/protocols/oscar/info.c @@ -260,6 +260,7 @@ guint32 aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len) if (!identified) { /*FIXME*/ + /*REMOVEME :-) g_strdup_printf("unknown capability: {%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", cap[0], cap[1], cap[2], cap[3], cap[4], cap[5], @@ -267,7 +268,7 @@ guint32 aim_getcap(aim_session_t *sess, aim_bstream_t *bs, int len) cap[8], cap[9], cap[10], cap[11], cap[12], cap[13], cap[14], cap[15]); - + */ } g_free(cap); -- cgit v1.2.3 From a3265629451475df75a3cd1fbe1805bbb71b2365 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Oct 2006 20:44:47 +0200 Subject: Fixing early free(). Memory management in the passport code is getting too messy, really... :-( --- protocols/msn/passport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/msn/passport.c b/protocols/msn/passport.c index 42b6ea73..9fe6a174 100644 --- a/protocols/msn/passport.c +++ b/protocols/msn/passport.c @@ -211,6 +211,7 @@ static void passport_retrieve_dalogin_ready( struct http_request *req ) if( passport_get_id_real( rep->func, rep->data, rep->header ) ) { + rep->header = NULL; destroy_reply( rep ); return; } -- cgit v1.2.3 From 5eec897b4d962e643e26574d1bffc22ffcaddac6 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 15 Oct 2006 21:53:42 +0200 Subject: set_eval_int() now allows negative integers. --- set.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/set.c b/set.c index 6a45fd14..d172a79f 100644 --- a/set.c +++ b/set.c @@ -174,6 +174,10 @@ char *set_eval_int( set_t *set, char *value ) { char *s; + /* Allow a minus at the first position. */ + if( *s == '-' ) + s ++; + for( s = value; *s; s ++ ) if( !isdigit( *s ) ) return NULL; -- cgit v1.2.3 From a5ac9f94c2dad85cb0f504172635982368db4d65 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Mon, 16 Oct 2006 00:25:59 +0200 Subject: Filled in the user changelog a bit more. --- doc/CHANGES | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/doc/CHANGES b/doc/CHANGES index cd100741..05ae81f6 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -1,4 +1,23 @@ Version x.x: +- 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 + don't get the stability problems BitlBee unfortunately still has in ordinary + (one-process) daemon mode. +- Added inter-process/connection communication. This made it possible to + implement some IRC operator features like WALLOPs, KILL, DIE, REHASH and + more. +- Added hooks for using libevent instead of GLib for event handling. This + should improve scalability, although this won't really be useful yet because + the one-process daemon mode is not reliable enough. +- BitlBee now makes the buddy quits when doing "account off" look like a + netsplit. Modern IRC clients show this in a different, more compact way. +- GLib 1.x compatibility was dropped. BitlBee now requires GLib 2.6 (FIXME) + or newer. This allows us to use more GLib features. By now GLib 1.x is so + old that supporting it isn't really 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. - 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 -- cgit v1.2.3 From 2a29eac1dd6c9d5d2ed5083efc1c185cfd750fd7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 21 Oct 2006 21:49:57 +0200 Subject: "Restructured" msn_login() a little bit. --- protocols/msn/msn.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c index f7e57707..f8686835 100644 --- a/protocols/msn/msn.c +++ b/protocols/msn/msn.c @@ -41,8 +41,6 @@ static void msn_login( account_t *acc ) struct gaim_connection *gc = new_gaim_conn( acc ); struct msn_data *md = g_new0( struct msn_data, 1 ); - set_login_progress( gc, 1, "Connecting" ); - gc->proto_data = md; md->fd = -1; @@ -53,19 +51,20 @@ static void msn_login( account_t *acc ) return; } + set_login_progress( gc, 1, "Connecting" ); + md->fd = proxy_connect( "messenger.hotmail.com", 1863, msn_ns_connected, gc ); if( md->fd < 0 ) { hide_login_progress( gc, "Could not connect to server" ); signoff( gc ); + return; } - else - { - md->gc = gc; - md->away_state = msn_away_state_list; - - msn_connections = g_slist_append( msn_connections, gc ); - } + + md->gc = gc; + md->away_state = msn_away_state_list; + + msn_connections = g_slist_append( msn_connections, gc ); } static void msn_close( struct gaim_connection *gc ) -- cgit v1.2.3 From 91bd910ec5ecf95953518246e3fd0adf1f43c1f7 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 21 Oct 2006 22:56:21 +0200 Subject: Fixed #139. (Wrong Gender description) --- protocols/oscar/oscar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c index b8cf521b..72078b3c 100644 --- a/protocols/oscar/oscar.c +++ b/protocols/oscar/oscar.c @@ -2296,7 +2296,7 @@ static int gaim_icqinfo(aim_session_t *sess, aim_frame_t *fr, ...) } } info_string_append(str, "\n", _("Mobile Phone"), info->mobile); - info_string_append(str, "\n", _("Gender"), info->gender==1 ? _("Female") : _("Male")); + info_string_append(str, "\n", _("Gender"), info->gender==1 ? _("Female") : info->gender==2 ? _("Male") : _("Unknown")); if (info->birthyear || info->birthmonth || info->birthday) { char date[30]; struct tm tm; -- cgit v1.2.3 From 208715962fcd1b806d42ef7edb47503eb296895b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Oct 2006 11:24:55 +0200 Subject: Away devoices are done by the server instead of by root now. This makes more sense with the "netsplit feature". (Because of less noisy joins.) --- protocols/nogaim.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/protocols/nogaim.c b/protocols/nogaim.c index 47e2bda6..0270d5a0 100644 --- a/protocols/nogaim.c +++ b/protocols/nogaim.c @@ -572,7 +572,7 @@ void serv_got_update( struct gaim_connection *gc, char *handle, int loggedin, in ( ( ( u->online != oo ) && !u->away ) || /* Voice joining people */ ( ( u->online == oo ) && ( oa == !u->away ) ) ) ) /* (De)voice people changing state */ { - irc_write( gc->irc, ":%s!%s@%s MODE %s %cv %s", gc->irc->mynick, gc->irc->mynick, gc->irc->myhost, + irc_write( gc->irc, ":%s MODE %s %cv %s", gc->irc->myhost, gc->irc->channel, u->away?'-':'+', u->nick ); } } @@ -906,8 +906,8 @@ char *set_eval_away_devoice( set_t *set, char *value ) if( ( strlen( list ) + strlen( u->nick ) ) >= 79 ) { for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0; - irc_write( irc, ":%s!%s@%s MODE %s %c%s%s", - irc->mynick, irc->mynick, irc->myhost, + irc_write( irc, ":%s MODE %s %c%s%s", + irc->myhost, irc->channel, pm, v, list ); *list = 0; @@ -922,7 +922,7 @@ char *set_eval_away_devoice( set_t *set, char *value ) /* $v = 'v' x $i */ for( i = 0; i < count; v[i++] = 'v' ); v[i] = 0; - irc_write( irc, ":%s!%s@%s MODE %s %c%s%s", irc->mynick, irc->mynick, irc->myhost, + irc_write( irc, ":%s MODE %s %c%s%s", irc->myhost, irc->channel, pm, v, list ); } -- cgit v1.2.3 From 670204fe6b883397208758d1e8e0c3ada699379c Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Oct 2006 14:43:40 +0200 Subject: Copied 1.0.x changelogs, disabled LDAP support in configure (because the code just doesn't work yet) and added GLib version detection. (GLib 2.4 and up *should* work.) --- configure | 17 +++++++++++++---- doc/CHANGES | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 7cc99b41..23bdd383 100755 --- a/configure +++ b/configure @@ -30,12 +30,14 @@ strip=1 ipv6=1 events=glib -ldap=auto +ldap=0 ssl=auto arch=`uname -s` cpu=`uname -m` +GLIB_MIN_VERSION=2.4 + echo BitlBee configure while [ -n "$1" ]; do @@ -174,13 +176,20 @@ if [ -z "$PKG_CONFIG" ]; then fi if $PKG_CONFIG --version > /dev/null 2>/dev/null && $PKG_CONFIG glib-2.0; then - cat<>Makefile.settings + if $PKG_CONFIG glib-2.0 --atleast-version=$GLIB_MIN_VERSION; then + cat<>Makefile.settings EFLAGS+=`$PKG_CONFIG --libs glib-2.0 gmodule-2.0` CFLAGS+=`$PKG_CONFIG --cflags glib-2.0 gmodule-2.0` EOF + else + echo + echo 'Found glib2 '`$PKG_CONFIG glib-2.0 --modversion`', but version '$GLIB_MIN_VERSION' or newer is required.' + exit 1 + fi else + echo echo 'Cannot find glib2 development libraries, aborting. (Install libglib2-dev?)' - exit 1; + exit 1 fi if [ "$events" = "libevent" ]; then @@ -289,7 +298,7 @@ elif [ "$ssl" = "openssl" ]; then ret=1 elif [ "$ssl" = "bogus" ]; then echo - echo 'Using bogus SSL code. This means some features have to be disabled.' + echo 'Using bogus SSL code. This means some features will not work properly.' ## Yes, you, at the console! How can you authenticate if you don't have any SSL!? if [ "$msn" = "1" ]; then diff --git a/doc/CHANGES b/doc/CHANGES index 05ae81f6..e9435216 100644 --- a/doc/CHANGES +++ b/doc/CHANGES @@ -12,9 +12,9 @@ Version x.x: the one-process daemon mode is not reliable enough. - BitlBee now makes the buddy quits when doing "account off" look like a netsplit. Modern IRC clients show this in a different, more compact way. -- GLib 1.x compatibility was dropped. BitlBee now requires GLib 2.6 (FIXME) - or newer. This allows us to use more GLib features. By now GLib 1.x is so - old that supporting it isn't really necessary anymore. +- GLib 1.x compatibility was dropped. BitlBee now requires GLib 2.4 or newer. + 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. @@ -41,6 +41,61 @@ Version x.x: and password for the existing connection. * Per-account settings (see the new "account set" command). +Version 1.0.3: +- Fixed ugliness in block/allow list commands (still not perfect though, the + list is empty or not up-to-date for most protocols). +- OSCAR module doesn't send the ICQ web-aware flag anymore, which seems to + get rid of a lot of ICQ spam. +- added show_got_added(), BitlBee asks you, after authorizing someone, if you + want to add him/her to your list too. +- add -tmp, mainly convenient if you want to talk to people who are not in + your list. +- Fixed ISON command, should work better with irssi now. +- Fixed compilation with tcc. +- Fixed xinetd-file. +- Misc. (crash)bug fixes, including one in the root command parsing that + caused mysterious error messages sometimes. + +Finished 24 Jun 2006 (Happy 4th birthday, BitlBee!) + +Version 1.0.2: +- Pieces of code cleanup, fixes for possible problems in error checking. +- Fixed an auto-reconnect cleanup problem that caused crashes in daemon mode. +- /AWAY in daemon mode now doesn't set the away state for every connection + anymore. +- Fixed a crash-bug on empty help subjects. +- Jabber now correctly sets the current away state when connecting. +- Added Invisible and Hidden to the away state alias list, invisible mode + should be pretty usable now. +- Fixed handling of iconv(): It's now done for everything that goes between + BitlBee and the IRC client, instead of doing it (almost) every time + something goes to or come from the IM-modules. Should've thought about + that before. :-) +- When cleaning up MSN switchboards with unsent msgs, it now also says which + contact those messages were meant for. +- You can now use the block and allow commands to see your current block/ + allow list. + +Finished 1 Apr 2006 + +Version 1.0.1: +- Support for AIM groupchats. +- Improved typing notification support for at least AIM. +- BitlBee sends a 005 reply when logging in, this informs modern IRC clients + of some of BitlBee's capabilities. This might also solve problems some + people were having with the new control channel name. +- MSN switchboards are now properly reset when talking to a person who is + offline. This fixes problems with messages to MSN people that sometimes + didn't arrive. +- Fixed one of the problems that made BitlBee show online Jabber people as + offline. +- Fixed problems with commas in MSN passwords. +- Added some consts for read-only data, which should make the BitlBee per- + process memory footprint a bit smaller. +- Other bits of code cleanup. + +Finished 14 Jan 2006 + Version 1.0: - Removed some crashy debugging code. - QUIT command now works before logging in. (Mainly an RFC-compliancy fix.) -- cgit v1.2.3 From 28eda862ffd1f59ac3cd214295c366ab939afd46 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Oct 2006 15:53:55 +0200 Subject: Fixed #181. (Using wrong (static) variable in error messages.) --- storage_text.c | 2 +- storage_xml.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/storage_text.c b/storage_text.c index acc9eefe..3a11facf 100644 --- a/storage_text.c +++ b/storage_text.c @@ -30,7 +30,7 @@ static void text_init (void) { if( access( global.conf->configdir, F_OK ) != 0 ) - log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG ); + log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", global.conf->configdir ); else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 ) log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); } diff --git a/storage_xml.c b/storage_xml.c index 52240a36..ba311120 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -262,7 +262,7 @@ GMarkupParser xml_parser = static void xml_init( void ) { if( access( global.conf->configdir, F_OK ) != 0 ) - log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", CONFIG ); + log_message( LOGLVL_WARNING, "The configuration directory %s does not exist. Configuration won't be saved.", global.conf->configdir ); else if( access( global.conf->configdir, R_OK ) != 0 || access( global.conf->configdir, W_OK ) != 0 ) log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to %s.", global.conf->configdir ); } -- cgit v1.2.3 From 6237ded20b3f3058f1ada9b6afeaa07fcba535eb Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sun, 22 Oct 2006 15:58:32 +0200 Subject: set_eval_int() was pretty broken... --- set.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/set.c b/set.c index d172a79f..8d872503 100644 --- a/set.c +++ b/set.c @@ -172,13 +172,13 @@ void set_del( set_t **head, char *key ) char *set_eval_int( set_t *set, char *value ) { - char *s; + char *s = value; /* Allow a minus at the first position. */ if( *s == '-' ) s ++; - for( s = value; *s; s ++ ) + for( ; *s; s ++ ) if( !isdigit( *s ) ) return NULL; -- cgit v1.2.3 From bbb6ffb4d2f4e02d3f856f731a83cb6b911bf659 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Tue, 31 Oct 2006 09:35:36 +0100 Subject: Disabling little optimization in irc.c because it can't be done safely in this part of the code for now. --- irc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/irc.c b/irc.c index 8f79b535..f9654034 100644 --- a/irc.c +++ b/irc.c @@ -584,8 +584,11 @@ void irc_vawrite( irc_t *irc, char *format, va_list params ) immediately. If it returns TRUE, it should be called again, so add the event to the queue. If it's FALSE, we emptied the buffer and saved ourselves some work in the event queue. */ - if( bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ) ) - irc->w_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_WRITE, bitlbee_io_current_client_write, irc ); + /* Really can't be done as long as the code doesn't do error checking very well: + if( bitlbee_io_current_client_write( irc, irc->fd, GAIM_INPUT_WRITE ) ) */ + + /* So just always do it via the event handler. */ + irc->w_watch_source_id = b_input_add( irc->fd, GAIM_INPUT_WRITE, bitlbee_io_current_client_write, irc ); } return; -- cgit v1.2.3 From dfc8a468020935a444397129eb5b2579e1001cf2 Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Fri, 24 Nov 2006 20:39:59 +0100 Subject: Bye bye lilo. I've never been a fan of yours, but let's not make fun of the dead... --- ipc.c | 6 +++--- irc_commands.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ipc.c b/ipc.c index 28aa07cb..d0d2dff3 100644 --- a/ipc.c +++ b/ipc.c @@ -98,7 +98,7 @@ static const command_t ipc_master_commands[] = { { "hello", 0, ipc_master_cmd_client, 0 }, { "die", 0, ipc_master_cmd_die, 0 }, { "wallops", 1, NULL, IPC_CMD_TO_CHILDREN }, - { "lilo", 1, NULL, IPC_CMD_TO_CHILDREN }, + { "wall", 1, NULL, IPC_CMD_TO_CHILDREN }, { "opermsg", 1, NULL, IPC_CMD_TO_CHILDREN }, { "rehash", 0, ipc_master_cmd_rehash, 0 }, { "kill", 2, NULL, IPC_CMD_TO_CHILDREN }, @@ -121,7 +121,7 @@ static void ipc_child_cmd_wallops( irc_t *irc, char **cmd ) irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] ); } -static void ipc_child_cmd_lilo( irc_t *irc, char **cmd ) +static void ipc_child_cmd_wall( irc_t *irc, char **cmd ) { if( !( irc->status & USTATUS_LOGGED_IN ) ) return; @@ -174,7 +174,7 @@ static void ipc_child_cmd_hello( irc_t *irc, char **cmd ) static const command_t ipc_child_commands[] = { { "die", 0, ipc_child_cmd_die, 0 }, { "wallops", 1, ipc_child_cmd_wallops, 0 }, - { "lilo", 1, ipc_child_cmd_lilo, 0 }, + { "wall", 1, ipc_child_cmd_wall, 0 }, { "opermsg", 1, ipc_child_cmd_opermsg, 0 }, { "rehash", 0, ipc_child_cmd_rehash, 0 }, { "kill", 2, ipc_child_cmd_kill, 0 }, diff --git a/irc_commands.c b/irc_commands.c index 47d9e8cb..b1045c93 100644 --- a/irc_commands.c +++ b/irc_commands.c @@ -592,7 +592,7 @@ static const command_t irc_commands[] = { { "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN }, { "die", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { "wallops", 1, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, - { "lilo", 1, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, + { "wall", 1, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { "rehash", 0, irc_cmd_rehash, IRC_CMD_OPER_ONLY }, { "restart", 0, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, { "kill", 2, NULL, IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER }, -- cgit v1.2.3 From 55078f59c8e9f52f1d10bed55511e5e58ec3e53b Mon Sep 17 00:00:00 2001 From: Wilmer van der Gaast Date: Sat, 25 Nov 2006 10:20:29 +0100 Subject: Forgot to pass O_CREAT to open() which can cause problems if there's a stale .xml~ file. --- storage_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage_xml.c b/storage_xml.c index ba311120..00fca425 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -394,7 +394,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite ) return STORAGE_ALREADY_EXISTS; strcat( path, "~" ); - if( ( fd = open( path, O_WRONLY | O_CREAT, 0600 ) ) < 0 ) + if( ( fd = open( path, O_WRONLY | O_CREAT | O_TRUNC, 0600 ) ) < 0 ) { irc_usermsg( irc, "Error while opening configuration file." ); return STORAGE_OTHER_ERROR; -- cgit v1.2.3