diff options
author | Wilmer van der Gaast <wilmer@gaast.net> | 2006-07-01 17:52:05 +0200 |
---|---|---|
committer | Wilmer van der Gaast <wilmer@gaast.net> | 2006-07-01 17:52:05 +0200 |
commit | 5100caa16bb707d89f1873aca99b5f87abc1dd56 (patch) | |
tree | cb07ef3e313f9d6f4f5feb2231176c5e9a2a7a2a | |
parent | 0a3c243b6659dc10efb227e507f324c2711d6dcd (diff) |
Added "account set" command.
-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 ); |