aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--account.c76
-rw-r--r--account.h6
-rw-r--r--bitlbee.c4
-rw-r--r--bitlbee.h2
-rw-r--r--conf.c7
-rwxr-xr-xconfigure186
-rw-r--r--doc/bitlbee.schema62
-rw-r--r--irc.c80
-rw-r--r--irc_commands.c18
-rw-r--r--lib/Makefile37
-rw-r--r--lib/base64.c153
-rw-r--r--lib/base64.h33
-rw-r--r--lib/events.h (renamed from protocols/events.h)0
-rw-r--r--lib/events_glib.c (renamed from protocols/events_glib.c)0
-rw-r--r--lib/events_libevent.c (renamed from protocols/events_libevent.c)0
-rw-r--r--lib/http_client.c (renamed from protocols/http_client.c)0
-rw-r--r--lib/http_client.h (renamed from protocols/http_client.h)0
-rw-r--r--lib/ini.c (renamed from ini.c)0
-rw-r--r--lib/ini.h (renamed from ini.h)0
-rw-r--r--lib/md5.c (renamed from protocols/md5.c)0
-rw-r--r--lib/md5.h (renamed from protocols/md5.h)0
-rw-r--r--lib/misc.c (renamed from util.c)165
-rw-r--r--lib/misc.h (renamed from util.h)14
-rw-r--r--lib/proxy.c (renamed from protocols/proxy.c)1
-rw-r--r--lib/proxy.h (renamed from protocols/proxy.h)0
-rw-r--r--lib/rc4.c189
-rw-r--r--lib/rc4.h34
-rw-r--r--lib/sha.c (renamed from protocols/sha.c)0
-rw-r--r--lib/sha.h (renamed from protocols/sha.h)0
-rw-r--r--lib/ssl_bogus.c (renamed from protocols/ssl_bogus.c)0
-rw-r--r--lib/ssl_client.h (renamed from protocols/ssl_client.h)0
-rw-r--r--lib/ssl_gnutls.c (renamed from protocols/ssl_gnutls.c)0
-rw-r--r--lib/ssl_nss.c (renamed from protocols/ssl_nss.c)0
-rw-r--r--lib/ssl_openssl.c (renamed from protocols/ssl_openssl.c)0
-rw-r--r--lib/url.c (renamed from url.c)0
-rw-r--r--lib/url.h (renamed from url.h)0
-rw-r--r--nick.c2
-rw-r--r--protocols/Makefile2
-rw-r--r--protocols/jabber/jabber.c24
-rw-r--r--protocols/msn/msn.c6
-rw-r--r--protocols/nogaim.c153
-rw-r--r--protocols/nogaim.h26
-rw-r--r--protocols/oscar/oscar.c35
-rw-r--r--protocols/yahoo/libyahoo2.c30
-rw-r--r--protocols/yahoo/yahoo.c8
-rw-r--r--query.c4
-rw-r--r--root_commands.c120
-rw-r--r--set.c143
-rw-r--r--set.h43
-rw-r--r--storage.c13
-rw-r--r--storage.h4
-rw-r--r--storage_ldap.c177
-rw-r--r--storage_text.c6
-rw-r--r--storage_xml.c503
-rw-r--r--unix.c14
-rw-r--r--user.c4
57 files changed, 1870 insertions, 520 deletions
diff --git a/Makefile b/Makefile
index 6f1d2d4a..54e03401 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 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_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
+subdirs = protocols lib
# Expansion of variables
subdirobjs = $(foreach dir,$(subdirs),$(dir)/$(dir).o)
@@ -41,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/account.c b/account.c
index 168d18c0..186565dd 100644
--- a/account.c
+++ b/account.c
@@ -27,14 +27,17 @@
#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 )
{
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
{
@@ -44,11 +47,66 @@ 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;
+ 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( set->flags & ACC_SET_OFFLINE_ONLY && 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;
@@ -128,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 );
@@ -141,8 +202,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 */
@@ -151,17 +210,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/account.h b/account.h
index 37cd8814..9fed399e 100644
--- a/account.h
+++ b/account.h
@@ -33,8 +33,11 @@ typedef struct account
char *pass;
char *server;
+ int auto_connect;
int reconnect;
+ set_t *set;
+
struct irc *irc;
struct gaim_connection *gc;
struct account *next;
@@ -46,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/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/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 7538825d..13f150a7 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;
@@ -54,7 +54,8 @@ 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->migrate_storage = g_strsplit( "text", ",", -1 );
conf->runmode = RUNMODE_INETD;
conf->authmode = AUTHMODE_OPEN;
conf->auth_pass = NULL;
@@ -321,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/configure b/configure
index a3c16e75..7cc99b41 100755
--- a/configure
+++ b/configure
@@ -30,6 +30,7 @@ strip=1
ipv6=1
events=glib
+ldap=auto
ssl=auto
arch=`uname -s`
@@ -66,6 +67,8 @@ Option Description Default
--ipv6=0/1 IPv6 socket support $ipv6
+--ldap=0/1/auto LDAP support $ldap
+
--events=... Event handler (glib, libevent) $events
--ssl=... SSL library to use (gnutls, nss, openssl, bogus, auto)
$ssl
@@ -140,21 +143,23 @@ 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
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
@@ -231,66 +236,106 @@ 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;
+detect_ldap()
+{
+ TMPFILE=`mktemp`
+ if $CC -o $TMPFILE -shared -lldap 2>/dev/null >/dev/null; then
+ cat<<EOF>>Makefile.settings
+EFLAGS+=-lldap
+CFLAGS+=
+EOF
+ ldap=1
+ rm -f $TMPFILE
+ ret=1
else
- echo
- echo 'ERROR: Unknown SSL library specified.'
- exit 1;
+ ldap=0
+ ret=0
fi
-
+}
+
+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 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
+
+ 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)'
- echo 'SSL_CLIENT=ssl_'$ssl'.o' >> Makefile.settings
+ 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 "#undef WITH_LDAP" >> config.h
+elif [ "$ldap" = 1 ]; then
+ echo "#define WITH_LDAP 1" >> config.h
+ 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
@@ -303,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.'
@@ -383,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
@@ -418,28 +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;
+ echo ' Building with these protocols:' $protocols
else
- echo ' Building without IM-protocol support. We wish you a lot of fun...';
+ echo ' Building without IM-protocol support. We wish you a lot of fun...'
fi
diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema
new file mode 100644
index 00000000..3322e057
--- /dev/null
+++ b/doc/bitlbee.schema
@@ -0,0 +1,62 @@
+## LDAP Schema file for BitlBee
+## Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
+##
+## We need the following object classes and related attributes:
+##
+## 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
+
+## - userid
+## - userPassword
+## - setting (multiple values)
+## depends: top, account
+
+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 )
+
+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 )
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.3 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
+
+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 ) )
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.2 NAME 'bitlBeeSetting' SUP top STRUCTURAL
+ DESC 'BitlBee Configuration Setting'
+ MUST ( bitlBeeSettingName )
+ MAY ( bitlBeeSettingValue ) )
+
+objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeBuddy' SUP top STRUCTURAL
+ DESC 'BitlBee Nick Mapping'
+ MUST ( bitlBeeBuddyHandle )
+ MAY ( ircNick ) )
diff --git a/irc.c b/irc.c
index 816b69d9..bac91198 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 )
@@ -119,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 );
@@ -210,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!" );
@@ -328,11 +329,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;
}
@@ -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 )
*namelist = 0;
}
- if( u->gc && !u->away && set_getint( irc, "away_devoice" ) )
+ if( u->gc && !u->away && set_getbool( &irc->set, "away_devoice" ) )
strcat( namelist, "+" );
strcat( namelist, u->nick );
@@ -675,7 +675,7 @@ void irc_names( irc_t *irc, char *channel )
else if( ( c = conv_findchannel( channel ) ) )
{
GList *l;
- char *ops = set_getstr( irc, "ops" );
+ 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: */
@@ -923,19 +923,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, ':' ) ) )
@@ -1011,13 +1011,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;
}
}
@@ -1050,7 +1050,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 ) );
}
@@ -1082,7 +1082,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;
@@ -1109,7 +1109,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;
@@ -1174,7 +1174,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..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;
}
@@ -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;
@@ -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/lib/Makefile b/lib/Makefile
new file mode 100644
index 00000000..6408c5ba
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,37 @@
+###########################
+## Makefile for BitlBee ##
+## ##
+## Copyright 2006 Lintux ##
+###########################
+
+### DEFINITIONS
+
+-include ../Makefile.settings
+
+# [SH] Program variables
+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
+
+# [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/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 <wilmer@gaast.net> *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License 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 <glib.h>
+#include <string.h>
+#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 <wilmer@gaast.net> *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License 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 <glib.h>
+#include <gmodule.h>
+
+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/protocols/events.h b/lib/events.h
index 781fca6a..781fca6a 100644
--- a/protocols/events.h
+++ b/lib/events.h
diff --git a/protocols/events_glib.c b/lib/events_glib.c
index 620720cd..620720cd 100644
--- a/protocols/events_glib.c
+++ b/lib/events_glib.c
diff --git a/protocols/events_libevent.c b/lib/events_libevent.c
index 1119c2ab..1119c2ab 100644
--- a/protocols/events_libevent.c
+++ b/lib/events_libevent.c
diff --git a/protocols/http_client.c b/lib/http_client.c
index b00fcf98..b00fcf98 100644
--- a/protocols/http_client.c
+++ b/lib/http_client.c
diff --git a/protocols/http_client.h b/lib/http_client.h
index 50ee80cf..50ee80cf 100644
--- a/protocols/http_client.h
+++ b/lib/http_client.h
diff --git a/ini.c b/lib/ini.c
index c63a132e..c63a132e 100644
--- a/ini.c
+++ b/lib/ini.c
diff --git a/ini.h b/lib/ini.h
index 5eab472b..5eab472b 100644
--- a/ini.h
+++ b/lib/ini.h
diff --git a/protocols/md5.c b/lib/md5.c
index e6273585..e6273585 100644
--- a/protocols/md5.c
+++ b/lib/md5.c
diff --git a/protocols/md5.h b/lib/md5.h
index f24f2ff1..f24f2ff1 100644
--- a/protocols/md5.h
+++ b/lib/md5.h
diff --git a/util.c b/lib/misc.c
index dfa0906b..17599946 100644
--- a/util.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 <markster@marko.net>
* (and possibly other members of the Gaim team)
- * Copyright 2002-2005 Wilmer van der Gaast <wilmer@gaast.net>
+ * Copyright 2002-2006 Wilmer van der Gaast <wilmer@gaast.net>
*/
/*
@@ -83,63 +83,6 @@ 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++;
- }
- 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;
- }
- return out;
-}
-
char *normalize(const char *s)
{
static char buf[BUF_LEN];
@@ -478,17 +421,101 @@ 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 );
+ 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;
+ }
+}
- cd = g_iconv_open( "UTF-8", value );
- if( cd == (GIConv) -1 )
- return( NULL );
+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;
+}
- g_iconv_close( cd );
- return( value );
+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/util.h b/lib/misc.h
index 8e13d9dd..b021e642 100644
--- a/util.h
+++ b/lib/misc.h
@@ -23,13 +23,15 @@
Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef _UTIL_H
-#define _UTIL_H
+#ifndef _MISC_H
+#define _MISC_H
+
+#include <gmodule.h>
+#include <time.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 char *normalize( const char *s );
G_MODULE_EXPORT void info_string_append( GString *str, char *newline, char *name, char *value );
@@ -45,6 +47,10 @@ 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 );
+
+G_MODULE_EXPORT int is_bool( char *value );
+G_MODULE_EXPORT int bool2int( char *value );
#endif
diff --git a/protocols/proxy.c b/lib/proxy.c
index 70a2158d..7911b06f 100644
--- a/protocols/proxy.c
+++ b/lib/proxy.c
@@ -40,6 +40,7 @@
#include <errno.h>
#include "nogaim.h"
#include "proxy.h"
+#include "base64.h"
char proxyhost[128] = "";
int proxyport = 0;
diff --git a/protocols/proxy.h b/lib/proxy.h
index 680790a5..680790a5 100644
--- a/protocols/proxy.h
+++ b/lib/proxy.h
diff --git a/lib/rc4.c b/lib/rc4.c
new file mode 100644
index 00000000..5e334507
--- /dev/null
+++ b/lib/rc4.c
@@ -0,0 +1,189 @@
+/***************************************************************************\
+* *
+* BitlBee - An IRC to IM gateway *
+* Simple (but secure) RC4 implementation for safer password storage. *
+* *
+* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License 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 <glib.h>
+#include <gmodule.h>
+#include <stdlib.h>
+#include <string.h>
+#include "misc.h"
+#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 );
+
+ /* 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 );
+ 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;
+
+ if( clear_len < 0 )
+ {
+ *clear = (unsigned char*) g_strdup( "" );
+ return 0;
+ }
+
+ /* 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..6c9ea6b9
--- /dev/null
+++ b/lib/rc4.h
@@ -0,0 +1,34 @@
+/***************************************************************************\
+* *
+* BitlBee - An IRC to IM gateway *
+* Simple (but secure) RC4 implementation for safer password storage. *
+* *
+* Copyright 2006 Wilmer van der Gaast <wilmer@gaast.net> *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License 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/protocols/sha.c b/lib/sha.c
index 895505a1..895505a1 100644
--- a/protocols/sha.c
+++ b/lib/sha.c
diff --git a/protocols/sha.h b/lib/sha.h
index e8152b1b..e8152b1b 100644
--- a/protocols/sha.h
+++ b/lib/sha.h
diff --git a/protocols/ssl_bogus.c b/lib/ssl_bogus.c
index 00aaa7c4..00aaa7c4 100644
--- a/protocols/ssl_bogus.c
+++ b/lib/ssl_bogus.c
diff --git a/protocols/ssl_client.h b/lib/ssl_client.h
index 1a9c79e9..1a9c79e9 100644
--- a/protocols/ssl_client.h
+++ b/lib/ssl_client.h
diff --git a/protocols/ssl_gnutls.c b/lib/ssl_gnutls.c
index 3ebe1756..3ebe1756 100644
--- a/protocols/ssl_gnutls.c
+++ b/lib/ssl_gnutls.c
diff --git a/protocols/ssl_nss.c b/lib/ssl_nss.c
index 218b3a80..218b3a80 100644
--- a/protocols/ssl_nss.c
+++ b/lib/ssl_nss.c
diff --git a/protocols/ssl_openssl.c b/lib/ssl_openssl.c
index b6f6c520..b6f6c520 100644
--- a/protocols/ssl_openssl.c
+++ b/lib/ssl_openssl.c
diff --git a/url.c b/lib/url.c
index e4deac78..e4deac78 100644
--- a/url.c
+++ b/lib/url.c
diff --git a/url.h b/lib/url.h
index e9e1ecfe..e9e1ecfe 100644
--- a/url.h
+++ b/lib/url.h
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/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/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 78b51b53..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 );
}
@@ -219,20 +206,20 @@ 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. */
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;
}
@@ -296,8 +283,9 @@ void signoff( struct gaim_connection *gc )
b_event_remove( gc->keepalive );
gc->flags |= OPT_LOGGING_OUT;
+
gc->keepalive = 0;
- gc->prpl->close( gc );
+ gc->acc->prpl->close( gc );
b_event_remove( gc->inpa );
while( u )
@@ -322,9 +310,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 );
@@ -363,12 +351,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;
@@ -377,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 );
@@ -389,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 );
@@ -408,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 );
}
@@ -456,7 +444,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 );
}
}
@@ -478,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 );
@@ -512,14 +500,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 );
@@ -557,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" );
@@ -570,15 +558,15 @@ 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;
/* 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 */
@@ -597,18 +585,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] )
{
@@ -629,8 +617,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 )
@@ -670,7 +658,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 ) ) ) {
@@ -692,7 +680,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 );
@@ -731,14 +719,14 @@ 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 );
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 )
@@ -771,7 +759,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 );
@@ -785,11 +773,11 @@ 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! */
- 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 )
@@ -819,11 +807,11 @@ 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! */
- 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;
@@ -881,8 +869,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 ) )
@@ -896,7 +885,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;
@@ -936,7 +925,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 ) );
}
@@ -956,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;
@@ -973,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;
@@ -987,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 )
{
@@ -1008,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 );
- if( set_getint( gc->irc, "debug" ) )
+ 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 );
@@ -1072,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 2080465c..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 *);
@@ -205,13 +189,13 @@ 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 );
/* 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... </bitlbee> */
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/libyahoo2.c b/protocols/yahoo/libyahoo2.c
index c691f18b..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;
@@ -694,34 +696,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';
+ 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/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/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 3d3584b3..b975b0f4 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:
@@ -138,11 +141,14 @@ 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 );
+ if( set_getint( &irc->set, "auto_connect" ) )
+ cmd_account( irc, account_on );
break;
+ case STORAGE_OTHER_ERROR:
default:
- irc_usermsg( irc, "Something very weird happened" );
+ irc_usermsg( irc, "Unknown error while loading configuration" );
break;
}
}
@@ -225,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" );
}
@@ -305,7 +310,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
@@ -351,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 <variable> <value>\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] );
@@ -393,14 +460,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] );
@@ -434,13 +501,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] );
}
}
@@ -475,7 +542,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" );
@@ -494,7 +561,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] );
@@ -551,7 +618,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] );
}
@@ -610,7 +677,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] );
}
@@ -665,16 +732,18 @@ 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 <variable> <value>\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 );
+ else
+ irc_usermsg( irc, "%s is empty", cmd[1] );
}
else
{
@@ -683,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;
}
}
@@ -726,7 +797,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" );
}
@@ -737,7 +808,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 ++;
@@ -747,7 +818,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 ++;
@@ -772,7 +843,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] );
}
@@ -780,7 +851,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] );
}
}
@@ -799,7 +870,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 );
}
@@ -827,10 +898,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 );
}
@@ -845,9 +917,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/set.c b/set.c
index 60912e10..4620264f 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,56 @@ 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;
+}
+
+int set_getbool( set_t **head, char *key )
+{
+ char *s = set_getstr( head, key );
- return( i );
+ if( !s )
+ return 0;
+
+ return bool2int( s );
}
-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 +127,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 +161,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 +170,23 @@ 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 ++ )
- if( *s < '0' || *s > '9' )
- return( NULL );
+ for( s = value; *s; s ++ )
+ if( !isdigit( *s ) )
+ 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 is_bool( value ) ? value : NULL;
}
-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,36 +195,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( 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..48bc8145 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,33 @@
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 );
+ 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! */
+ 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 );
-
-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 );
-
-
+set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data );
+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 );
+G_MODULE_EXPORT int set_getbool( 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( set_t *set, char *value );
+char *set_eval_bool( 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.c b/storage.c
index b766c9e3..807d5bb4 100644
--- a/storage.c
+++ b/storage.c
@@ -6,6 +6,8 @@
/* Support for multiple storage backends */
+/* Copyright (C) 2005 Jelmer Vernooij <jelmer@samba.org> */
+
/*
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
@@ -28,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)
{
@@ -40,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;
@@ -62,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_ldap.c b/storage_ldap.c
new file mode 100644
index 00000000..4bc99de5
--- /dev/null
+++ b/storage_ldap.c
@@ -0,0 +1,177 @@
+ /********************************************************************\
+ * 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 <jelmer@samba.org> */
+
+/*
+ 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 <ldap.h>
+
+#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) {
+ log_message( LOGLVL_WARNING, "Unable to connect to LDAP server at %s", BB_LDAP_HOST );
+ 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:
+ log_message( LOGLVL_WARNING, "Unable to authenticate %s: %s", mydn, ldap_err2string(ret) );
+ status = STORAGE_OTHER_ERROR;
+ break;
+ }
+
+ g_free(mydn);
+
+ return status;
+}
+
+static storage_status_t sldap_load ( const char *my_nick, const char* password, irc_t *irc )
+{
+ LDAPMessage *res, *msg;
+ LDAP *ld;
+ int ret, i;
+ 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_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);
+
+ for (msg = ldap_first_entry(ld, res); msg; msg = ldap_next_entry(ld, msg)) {
+ }
+
+ /* FIXME: Store in irc_t */
+
+ ldap_unbind_s(ld);
+
+ 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) {
+ 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",
+ .check_pass = sldap_check_pass,
+ .remove = sldap_remove,
+ .load = sldap_load,
+ .save = sldap_save
+};
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
new file mode 100644
index 00000000..701d5144
--- /dev/null
+++ b/storage_xml.c
@@ -0,0 +1,503 @@
+ /********************************************************************\
+ * 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"
+#include "base64.h"
+#include "rc4.h"
+#include "md5.h"
+
+typedef enum
+{
+ XML_PASS_CHECK_ONLY = -1,
+ XML_PASS_UNKNOWN = 0,
+ XML_PASS_WRONG,
+ XML_PASS_OK
+} xml_pass_st;
+
+/* To make it easier later when extending the format: */
+#define XML_FORMAT_VERSION 1
+
+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 )
+{
+ int i;
+
+ for( i = 0; attr_names[i]; i ++ )
+ if( g_strcasecmp( attr_names[i], key ) == 0 )
+ 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 = 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" );
+ 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;
+
+ md5_init( &md5_state );
+ md5_append( &md5_state, (md5_byte_t*) xd->given_pass, strlen( xd->given_pass ) );
+ md5_append( &md5_state, (md5_byte_t*) pass_dec + 16, 5 ); /* Hmmm, salt! */
+ md5_finish( &md5_state, pass_md5 );
+
+ for( i = 0; i < 16; i ++ )
+ {
+ if( pass_dec[i] != pass_md5[i] )
+ {
+ xd->pass_st = XML_PASS_WRONG;
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Password mismatch" );
+ break;
+ }
+ }
+
+ /* If we reached the end of the loop, it was a match! */
+ if( i == 16 )
+ {
+ if( xd->pass_st != XML_PASS_CHECK_ONLY )
+ xd->pass_st = XML_PASS_OK;
+ }
+ }
+
+ g_free( pass_dec );
+ }
+ 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, *server, *password = NULL, *autoconnect;
+ char *pass_b64 = NULL, *pass_rc4 = NULL;
+ int pass_len;
+ struct prpl *prpl = NULL;
+
+ handle = xml_attr( attr_names, attr_values, "handle" );
+ 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" );
+
+ protocol = xml_attr( attr_names, attr_values, "protocol" );
+ if( protocol )
+ prpl = find_protocol( 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 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 )
+ set_setstr( &xd->current_account->set, "server", server );
+ if( autoconnect )
+ set_setstr( &xd->current_account->set, "auto_connect", autoconnect );
+ }
+ 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 )
+ {
+ 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 )
+ {
+ 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
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
+ "Unkown element: %s", element_name );
+ }
+}
+
+static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error )
+{
+ struct xml_parsedata *xd = data;
+
+ if( g_strcasecmp( element_name, "setting" ) == 0 && xd->current_setting )
+ {
+ g_free( xd->current_setting );
+ xd->current_setting = NULL;
+ }
+ else if( g_strcasecmp( element_name, "account" ) == 0 )
+ {
+ xd->current_account = NULL;
+ }
+}
+
+static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_len, gpointer data, GError **error )
+{
+ struct xml_parsedata *xd = data;
+ irc_t *irc = xd->irc;
+
+ if( xd->pass_st < XML_PASS_OK )
+ {
+ /* Let's not parse anything else if we only have to check
+ 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 )
+ {
+ 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;
+ }
+}
+
+GMarkupParser xml_parser =
+{
+ xml_start_element,
+ xml_end_element,
+ xml_text,
+ NULL,
+ NULL
+};
+
+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_real( const char *my_nick, const char *password, irc_t *irc, xml_pass_st action )
+{
+ GMarkupParseContext *ctx;
+ struct xml_parsedata *xd;
+ char *fn, buf[512];
+ GError *gerr = NULL;
+ int fd, st;
+
+ 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" );
+ if( ( fd = open( fn, O_RDONLY ) ) < 0 )
+ {
+ xml_destroy_xd( xd );
+ g_free( fn );
+ return STORAGE_NO_SUCH_USER;
+ }
+ g_free( fn );
+
+ ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd );
+
+ while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 )
+ {
+ 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 );
+
+ if( pass_st == XML_PASS_WRONG )
+ {
+ 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 );
+
+ if( action == XML_PASS_CHECK_ONLY )
+ return STORAGE_OK;
+
+ irc->status |= USTATUS_IDENTIFIED;
+
+ 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, 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 );
+
+ len = strlen( out );
+ len -= write( fd, out, len );
+ g_free( out );
+
+ return len == 0;
+}
+
+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];
+ 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" );
+
+ if( !overwrite && access( path, F_OK ) != -1 )
+ return STORAGE_ALREADY_EXISTS;
+
+ strcat( path, "~" );
+ if( ( fd = open( path, O_WRONLY | O_CREAT, 0600 ) ) < 0 )
+ {
+ irc_usermsg( irc, "Error while opening configuration file." );
+ 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. */
+ 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. */
+ md5_finish( &md5_state, pass_md5 );
+ /* Save the hash in base64-encoded form. */
+ pass_buf = base64_encode( (char*) pass_md5, 21 );
+
+ if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\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, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
+ goto write_error;
+
+ for( acc = irc->accounts; acc; acc = acc->next )
+ {
+ 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 );
+ g_free( pass_rc4 );
+
+ if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->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, 0, " server=\"%s\"", acc->server ) )
+ goto write_error;
+ 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, "<setting name=\"%s\">%s</setting>\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, "<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) )
+ goto write_error;
+
+ if( !xml_printf( fd, 1, "</account>\n" ) )
+ goto write_error;
+ }
+
+ if( !xml_printf( fd, 0, "</user>\n" ) )
+ goto write_error;
+
+ close( fd );
+
+ path2 = g_strndup( path, strlen( path ) - 1 );
+ if( rename( path, path2 ) != 0 )
+ {
+ irc_usermsg( irc, "Error while renaming temporary configuration file." );
+
+ g_free( path2 );
+ unlink( path );
+
+ return STORAGE_OTHER_ERROR;
+ }
+
+ g_free( path2 );
+
+ return STORAGE_OK;
+
+write_error:
+ g_free( pass_buf );
+
+ irc_usermsg( irc, "Write error. Disk full?" );
+ close( fd );
+
+ 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,
+ .load = xml_load,
+ .save = xml_save
+};
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 );
diff --git a/user.c b/user.c
index 5f0952f5..cb70ab68 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 );
@@ -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;
}