diff options
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | account.c | 76 | ||||
| -rw-r--r-- | account.h | 6 | ||||
| -rw-r--r-- | bitlbee.c | 4 | ||||
| -rw-r--r-- | bitlbee.h | 2 | ||||
| -rw-r--r-- | conf.c | 7 | ||||
| -rwxr-xr-x | configure | 186 | ||||
| -rw-r--r-- | doc/bitlbee.schema | 62 | ||||
| -rw-r--r-- | irc.c | 80 | ||||
| -rw-r--r-- | irc_commands.c | 18 | ||||
| -rw-r--r-- | lib/Makefile | 37 | ||||
| -rw-r--r-- | lib/base64.c | 153 | ||||
| -rw-r--r-- | lib/base64.h | 33 | ||||
| -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.c | 189 | ||||
| -rw-r--r-- | lib/rc4.h | 34 | ||||
| -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.c | 2 | ||||
| -rw-r--r-- | protocols/Makefile | 2 | ||||
| -rw-r--r-- | protocols/jabber/jabber.c | 24 | ||||
| -rw-r--r-- | protocols/msn/msn.c | 6 | ||||
| -rw-r--r-- | protocols/nogaim.c | 153 | ||||
| -rw-r--r-- | protocols/nogaim.h | 26 | ||||
| -rw-r--r-- | protocols/oscar/oscar.c | 35 | ||||
| -rw-r--r-- | protocols/yahoo/libyahoo2.c | 30 | ||||
| -rw-r--r-- | protocols/yahoo/yahoo.c | 8 | ||||
| -rw-r--r-- | query.c | 4 | ||||
| -rw-r--r-- | root_commands.c | 120 | ||||
| -rw-r--r-- | set.c | 143 | ||||
| -rw-r--r-- | set.h | 43 | ||||
| -rw-r--r-- | storage.c | 13 | ||||
| -rw-r--r-- | storage.h | 4 | ||||
| -rw-r--r-- | storage_ldap.c | 177 | ||||
| -rw-r--r-- | storage_text.c | 6 | ||||
| -rw-r--r-- | storage_xml.c | 503 | ||||
| -rw-r--r-- | unix.c | 14 | ||||
| -rw-r--r-- | user.c | 4 | 
57 files changed, 1870 insertions, 520 deletions
| @@ -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: @@ -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 ) @@ -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 @@ -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 ); @@ -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 { @@ -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 )  			{ @@ -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 ) ) @@ -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/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 @@ -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;  } @@ -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 @@ -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 );  	} @@ -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 );  		}  	} @@ -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; +} @@ -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 ); @@ -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; @@ -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 +}; @@ -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 ); @@ -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;  	} | 
