diff options
| -rw-r--r-- | account.c | 60 | ||||
| -rw-r--r-- | account.h | 5 | ||||
| -rw-r--r-- | lib/misc.c | 34 | ||||
| -rw-r--r-- | lib/misc.h | 3 | ||||
| -rw-r--r-- | lib/rc4.c | 2 | ||||
| -rw-r--r-- | root_commands.c | 69 | ||||
| -rw-r--r-- | set.c | 18 | ||||
| -rw-r--r-- | set.h | 4 | ||||
| -rw-r--r-- | storage_xml.c | 65 | 
9 files changed, 220 insertions, 40 deletions
| @@ -27,9 +27,12 @@  #include "bitlbee.h"  #include "account.h" +char *set_eval_account( set_t *set, char *value ); +  account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )  {  	account_t *a; +	set_t *s;  	if( irc->accounts )  	{ @@ -47,9 +50,63 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )  	a->auto_connect = 1;  	a->irc = irc; +	s = set_add( &a->set, "auto_connect", NULL, set_eval_account, a ); +	s->flags |= ACC_SET_NOSAVE; +	 +	s = set_add( &a->set, "password", NULL, set_eval_account, a ); +	s->flags |= ACC_SET_NOSAVE; +	 +	s = set_add( &a->set, "server", NULL, set_eval_account, a ); +	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; +	 +	s = set_add( &a->set, "username", NULL, set_eval_account, a ); +	s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY; +	set_setstr( &a->set, "username", user ); +	  	return( a );  } +char *set_eval_account( set_t *set, char *value ) +{ +	account_t *acc = set->data; +	 +	/* Double-check: We refuse to edit on-line accounts. */ +	if( acc->gc ) +		return NULL; +	 +	if( strcmp( set->key, "username" ) == 0 ) +	{ +		g_free( acc->user ); +		acc->user = g_strdup( value ); +		return value; +	} +	else if( strcmp( set->key, "password" ) == 0 ) +	{ +		g_free( acc->pass ); +		acc->pass = g_strdup( value ); +		return NULL;	/* password shouldn't be visible in plaintext! */ +	} +	else if( strcmp( set->key, "server" ) == 0 ) +	{ +		g_free( acc->server ); +		if( *value ) +			acc->server = g_strdup( value ); +		else +			acc->server = NULL; +		return value; +	} +	else if( strcmp( set->key, "auto_connect" ) == 0 ) +	{ +		if( !is_bool( value ) ) +			return NULL; +		 +		acc->auto_connect = bool2int( value ); +		return value; +	} +	 +	return NULL; +} +  account_t *account_get( irc_t *irc, char *id )  {  	account_t *a, *ret = NULL; @@ -129,6 +186,9 @@ void account_del( irc_t *irc, account_t *acc )  				irc->accounts = a->next;  			} +			while( a->set ) +				set_del( &a->set, a->set->key ); +			  			g_free( a->user );  			g_free( a->pass );  			if( a->server ) g_free( a->server ); @@ -36,6 +36,8 @@ typedef struct account  	int auto_connect;  	int reconnect; +	set_t *set; +	  	struct irc *irc;  	struct gaim_connection *gc;  	struct account *next; @@ -47,4 +49,7 @@ void account_del( irc_t *irc, account_t *acc );  void account_on( irc_t *irc, account_t *a );  void account_off( irc_t *irc, account_t *a ); +#define ACC_SET_NOSAVE		1 +#define ACC_SET_OFFLINE_ONLY	2 +  #endif @@ -485,3 +485,37 @@ void random_bytes( unsigned char *buf, int count )  			buf[i] = rand() & 0xff;  	}  } + +int is_bool( char *value ) +{ +	if( *value == 0 ) +		return 0; +	 +	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) +		return 1; +	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) +		return 1; +	 +	while( *value ) +		if( !isdigit( *value ) ) +			return 0; +		else +			value ++; +	 +	return 1; +} + +int bool2int( char *value ) +{ +	int i; +	 +	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) +		return 1; +	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) +		return 0; +	 +	if( sscanf( value, "%d", &i ) == 1 ) +		return i; +	 +	return 0; +} @@ -50,4 +50,7 @@ G_MODULE_EXPORT signed int do_iconv( char *from_cs, char *to_cs, char *src, char  G_MODULE_EXPORT void random_bytes( unsigned char *buf, int count ); +G_MODULE_EXPORT int is_bool( char *value ); +G_MODULE_EXPORT int bool2int( char *value ); +  #endif @@ -164,7 +164,7 @@ int rc4_decode( unsigned char *crypt, int crypt_len, unsigned char **clear, char  	if( clear_len < 0 )  	{ -		*clear = g_strdup( "" ); +		*clear = (unsigned char*) g_strdup( "" );  		return 0;  	} diff --git a/root_commands.c b/root_commands.c index 3bd80e5e..b975b0f4 100644 --- a/root_commands.c +++ b/root_commands.c @@ -231,9 +231,8 @@ static void cmd_account( irc_t *irc, char **cmd )  		}  		a = account_add( irc, prpl, cmd[3], cmd[4] ); -		  		if( cmd[5] ) -			a->server = g_strdup( cmd[5] ); +			set_setstr( &a->set, "server", cmd[5] );  		irc_usermsg( irc, "Account successfully added" );  	} @@ -357,6 +356,68 @@ static void cmd_account( irc_t *irc, char **cmd )  			return;  		}  	} +	else if( g_strcasecmp( cmd[1], "set" ) == 0 ) +	{ +		char *acc_handle, *set_name = NULL, *tmp; +		 +		if( !cmd[2] ) +		{ +			irc_usermsg( irc, "Not enough parameters given (need %d)", 2 ); +			return; +		} +		 +		acc_handle = g_strdup( cmd[2] ); +		if( ( tmp = strchr( acc_handle, '/' ) ) ) +		{ +			*tmp = 0; +			set_name = tmp + 1; +		} +		a = account_get( irc, acc_handle ); +		 +		if( a == NULL ) +		{ +			irc_usermsg( irc, "Invalid account" ); +			return; +		} +		 +		if( cmd[3] ) +		{ +			set_t *s = set_find( &a->set, set_name ); +			 +			if( a->gc && s && s->flags & ACC_SET_OFFLINE_ONLY ) +			{ +				irc_usermsg( irc, "This setting can only be changed when the account is off-line" ); +				return; +			} +			 +			set_setstr( &a->set, set_name, cmd[3] ); +			 +			if( ( strcmp( cmd[3], "=" ) ) == 0 && cmd[4] ) +				irc_usermsg( irc, "Warning: Correct syntax: \002account set <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] ); @@ -681,6 +742,8 @@ static void cmd_set( irc_t *irc, char **cmd )  		char *s = set_getstr( &irc->set, cmd[1] );  		if( s )  			irc_usermsg( irc, "%s = `%s'", cmd[1], s ); +		else +			irc_usermsg( irc, "%s is empty", cmd[1] );  	}  	else  	{ @@ -689,6 +752,8 @@ static void cmd_set( irc_t *irc, char **cmd )  		{  			if( s->value || s->def )  				irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def ); +			else +				irc_usermsg( irc, "%s is empty", s->key );  			s = s->next;  		}  	} @@ -100,6 +100,16 @@ int set_getint( set_t **head, char *key )  	return i;  } +int set_getbool( set_t **head, char *key ) +{ +	char *s = set_getstr( head, key ); +	 +	if( !s ) +		return 0; +	 +	return bool2int( s ); +} +  int set_setstr( set_t **head, char *key, char *value )  {  	set_t *s = set_find( head, key ); @@ -165,7 +175,7 @@ char *set_eval_int( set_t *set, char *value )  	char *s;  	for( s = value; *s; s ++ ) -		if( *s < '0' || *s > '9' ) +		if( !isdigit( *s ) )  			return NULL;  	return value; @@ -173,11 +183,7 @@ char *set_eval_int( set_t *set, char *value )  char *set_eval_bool( set_t *set, char *value )  { -	if( ( g_strcasecmp( value, "true" ) == 0 ) || ( g_strcasecmp( value, "yes" ) == 0 ) || ( g_strcasecmp( value, "on" ) == 0 ) ) -		return( value ); -	if( ( g_strcasecmp( value, "false" ) == 0 ) || ( g_strcasecmp( value, "no" ) == 0 ) || ( g_strcasecmp( value, "off" ) == 0 ) ) -		return( value ); -	return( set_eval_int( set, value ) ); +	return is_bool( value ) ? value : NULL;  }  char *set_eval_to_char( set_t *set, char *value ) @@ -31,6 +31,8 @@ typedef struct set  	char *value;  	char *def;	/* Default */ +	int flags; +	  	/* Eval: Returns NULL if the value is incorrect or exactly the  	   passed value variable. When returning a corrected value,  	   set_setstr() should be able to free() the returned string! */ @@ -39,7 +41,7 @@ typedef struct set  } set_t;  set_t *set_add( set_t **head, char *key, char *def, void *eval, void *data ); -G_MODULE_EXPORT set_t *set_find( set_t **head, char *key ); +set_t *set_find( set_t **head, char *key );  G_MODULE_EXPORT char *set_getstr( set_t **head, char *key );  G_MODULE_EXPORT int set_getint( set_t **head, char *key );  int set_setstr( set_t **head, char *key, char *value ); diff --git a/storage_xml.c b/storage_xml.c index e0ffc481..701d5144 100644 --- a/storage_xml.c +++ b/storage_xml.c @@ -156,11 +156,9 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na  		{  			xd->current_account = account_add( irc, prpl, handle, password );  			if( server ) -				xd->current_account->server = g_strdup( server ); +				set_setstr( &xd->current_account->set, "server", server );  			if( autoconnect ) -				/* Return value doesn't matter, since account_add() already sets -				   a default! */ -				sscanf( autoconnect, "%d", &xd->current_account->auto_connect ); +				set_setstr( &xd->current_account->set, "auto_connect", autoconnect );  		}  		else  		{ @@ -175,22 +173,19 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na  	}  	else if( g_strcasecmp( element_name, "setting" ) == 0 )  	{ -		if( xd->current_account == NULL ) +		char *setting; +		 +		if( xd->current_setting )  		{ -			char *setting; -			 -			if( xd->current_setting ) -			{ -				g_free( xd->current_setting ); -				xd->current_setting = NULL; -			} -			 -			if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) -				xd->current_setting = g_strdup( setting ); -			else -				g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, -				             "Missing attributes for %s element", element_name ); +			g_free( xd->current_setting ); +			xd->current_setting = NULL;  		} +		 +		if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) ) +			xd->current_setting = g_strdup( setting ); +		else +			g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, +			             "Missing attributes for %s element", element_name );  	}  	else if( g_strcasecmp( element_name, "buddy" ) == 0 )  	{ @@ -242,10 +237,10 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text, gsize text_le  		   the password, or if we didn't get the chance to check it  		   yet. */  	} -	else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && -	         xd->current_setting && xd->current_account == NULL ) +	else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting )  	{ -		set_setstr( &irc->set, xd->current_setting, (char*) text ); +		set_setstr( xd->current_account ? &xd->current_account->set : &irc->set, +		            xd->current_setting, (char*) text );  		g_free( xd->current_setting );  		xd->current_setting = NULL;  	} @@ -347,12 +342,17 @@ static storage_status_t xml_check_pass( const char *my_nick, const char *passwor  	return xml_load_real( my_nick, password, NULL, XML_PASS_CHECK_ONLY );  } -static int xml_printf( int fd, char *fmt, ... ) +static int xml_printf( int fd, int indent, char *fmt, ... )  {  	va_list params;  	char *out; +	char tabs[9] = "\t\t\t\t\t\t\t\t";  	int len; +	/* Maybe not very clean, but who needs more than 8 levels of indentation anyway? */ +	if( write( fd, tabs, indent <= 8 ? indent : 8 ) != indent ) +		return 0; +	  	va_start( params, fmt );  	out = g_markup_vprintf_escaped( fmt, params );  	va_end( params ); @@ -403,14 +403,14 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )  	/* Save the hash in base64-encoded form. */  	pass_buf = base64_encode( (char*) pass_md5, 21 ); -	if( !xml_printf( fd, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->nick, pass_buf, XML_FORMAT_VERSION ) ) +	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, "\t<setting name=\"%s\">%s</setting>\n", set->key, set->value ) ) +			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 ) @@ -422,28 +422,33 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )  		pass_b64 = base64_encode( pass_rc4, pass_len );  		g_free( pass_rc4 ); -		if( !xml_printf( fd, "\t<account protocol=\"%s\" handle=\"%s\" password=\"%s\" autoconnect=\"%d\"", acc->prpl->name, acc->user, pass_b64, acc->auto_connect ) ) +		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, " server=\"%s\"", acc->server ) ) +		if( acc->server && acc->server[0] && !xml_printf( fd, 0, " server=\"%s\"", acc->server ) )  			goto write_error; -		if( !xml_printf( fd, ">\n" ) ) +		if( !xml_printf( fd, 0, ">\n" ) )  			goto write_error; +		for( set = acc->set; set; set = set->next ) +			if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) ) +				if( !xml_printf( fd, 2, "<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, "\t\t<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) ) +				if( !xml_printf( fd, 2, "<buddy handle=\"%s\" nick=\"%s\" />\n", nick->handle, nick->nick ) )  					goto write_error; -		if( !xml_printf( fd, "\t</account>\n" ) ) +		if( !xml_printf( fd, 1, "</account>\n" ) )  			goto write_error;  	} -	if( !xml_printf( fd, "</user>\n" ) ) +	if( !xml_printf( fd, 0, "</user>\n" ) )  		goto write_error;  	close( fd ); | 
