aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bitlbee.c13
-rwxr-xr-xconfigure34
-rw-r--r--doc/bitlbee.schema62
-rw-r--r--lib/xmltree.c87
-rw-r--r--lib/xmltree.h1
-rw-r--r--protocols/account.c10
-rw-r--r--protocols/account.h1
-rw-r--r--protocols/jabber/jabber.c2
-rw-r--r--protocols/msn/msn.c2
-rw-r--r--protocols/oscar/oscar.c2
-rw-r--r--protocols/skype/skype.c6
-rw-r--r--protocols/twitter/twitter_lib.c8
-rw-r--r--root_commands.c2
-rw-r--r--set.h10
-rw-r--r--storage.c43
-rw-r--r--storage.h2
-rw-r--r--storage_ldap.c177
-rw-r--r--storage_xml.c654
18 files changed, 281 insertions, 835 deletions
diff --git a/bitlbee.c b/bitlbee.c
index 0e1415e8..563d9344 100644
--- a/bitlbee.c
+++ b/bitlbee.c
@@ -266,16 +266,9 @@ gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condit
if( st == size )
{
- if( irc->status & USTATUS_SHUTDOWN )
- {
- irc_free( irc );
- }
- else
- {
- g_free( irc->sendbuffer );
- irc->sendbuffer = NULL;
- irc->w_watch_source_id = 0;
- }
+ g_free( irc->sendbuffer );
+ irc->sendbuffer = NULL;
+ irc->w_watch_source_id = 0;
return FALSE;
}
diff --git a/configure b/configure
index 0aaebd08..10d7c1bd 100755
--- a/configure
+++ b/configure
@@ -38,7 +38,6 @@ otr=0
skype=0
events=glib
-ldap=0
ssl=auto
pie=1
@@ -326,23 +325,6 @@ EOF
fi;
}
-detect_ldap()
-{
- TMPFILE=$(mktemp /tmp/bitlbee-configure.XXXXXX)
- 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
- ldap=0
- ret=0
- fi
-}
-
RESOLV_TESTCODE='
#include <sys/types.h>
#include <netinet/in.h>
@@ -456,22 +438,6 @@ fi
STORAGES="xml"
-if [ "$ldap" = "auto" ]; then
- detect_ldap
-fi
-
-if [ "$ldap" = 0 ]; then
- echo "#undef WITH_LDAP" >> config.h
-elif [ "$ldap" = 1 ]; then
- echo
- echo 'LDAP support is a work in progress and does NOT work AT ALL right now.'
- echo
- exit 1
-
- echo "#define WITH_LDAP 1" >> config.h
- STORAGES="$STORAGES ldap"
-fi
-
for i in $STORAGES; do
STORAGE_OBJS="$STORAGE_OBJS storage_$i.o"
done
diff --git a/doc/bitlbee.schema b/doc/bitlbee.schema
deleted file mode 100644
index 3322e057..00000000
--- a/doc/bitlbee.schema
+++ /dev/null
@@ -1,62 +0,0 @@
-## LDAP Schema file for BitlBee
-## Copyright (C) 2006 Jelmer Vernooij <jelmer@samba.org>
-##
-## We need the following object classes and related attributes:
-##
-## bitlBeeBuddy:
-## - nick
-## - handle
-
-## each bitlBeeNick has zero or more bitlBeeAccount subentries
-## and bitlBeeAccount entries contain zero or more bitlBeeBuddy entries
-
-## The admin needs to setup the LDAP server to:
-## - allow anonymous users to auth against bitlBeeNick objects on the
-## password field
-## - allow anonymous users to create new objects that start with nick=
-## - allow read/write for a user that is authenticated only to his/her own
-## object and subentries
-
-## - userid
-## - userPassword
-## - setting (multiple values)
-## depends: top, account
-
-attributetype ( 1.3.6.1.4.1.25873.2.1.1 NAME 'bitlBeeAutoConnect'
- DESC 'Autoconnect setting'
- EQUALITY booleanMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
-
-attributetype ( 1.3.6.1.4.1.25873.2.1.2 NAME 'bitlBeeAccountNo'
- DESC 'Account number'
- EQUALITY integerMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
-
-objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeAccount' SUP account STRUCTURAL
- DESC 'BitlBee User Account '
- MUST ( userid, userPassword )
- MAY ( ) )
-
-## bitlBeeAccount:
-## - accountNo 1.3.6.1.4.1.1466.115.121.1.27
-## - protocol (msn, oscar, jabber, yahoo, ...)
-## - username
-## - password
-## - server name
-## - autoconnect (true/false) 1.3.6.1.4.1.1466.115.121.1.7
-## depends: top
-
-objectclass ( 1.3.6.1.4.1.25873.2.2.1 NAME 'bitlBeeIMAccount' SUP account STRUCTURAL
- DESC 'BitlBee IM Account '
- MUST ( bitlBeeAccountNo, userid, userPassword )
- MAY ( host, bitlBeeAutoconnect ) )
-
-objectclass ( 1.3.6.1.4.1.25873.2.2.2 NAME 'bitlBeeSetting' SUP top STRUCTURAL
- DESC 'BitlBee Configuration Setting'
- MUST ( bitlBeeSettingName )
- MAY ( bitlBeeSettingValue ) )
-
-objectclass ( 1.3.6.1.4.1.25873.2.2.3 NAME 'bitlBeeBuddy' SUP top STRUCTURAL
- DESC 'BitlBee Nick Mapping'
- MUST ( bitlBeeBuddyHandle )
- MAY ( ircNick ) )
diff --git a/lib/xmltree.c b/lib/xmltree.c
index 21e843a0..0726d387 100644
--- a/lib/xmltree.c
+++ b/lib/xmltree.c
@@ -281,12 +281,16 @@ struct xt_node *xt_from_string( const char *in, int len )
return ret;
}
-static void xt_to_string_real( struct xt_node *node, GString *str )
+static void xt_to_string_real( struct xt_node *node, GString *str, int indent )
{
char *buf;
struct xt_node *c;
int i;
+ if( indent > 1 )
+ g_string_append_len( str, "\n\t\t\t\t\t\t\t\t",
+ indent < 8 ? indent : 8 );
+
g_string_append_printf( str, "<%s", node->name );
for( i = 0; node->attr[i].key; i ++ )
@@ -311,7 +315,11 @@ static void xt_to_string_real( struct xt_node *node, GString *str )
}
for( c = node->children; c; c = c->next )
- xt_to_string_real( c, str );
+ xt_to_string_real( c, str, indent ? indent + 1 : 0 );
+
+ if( indent > 0 && node->children )
+ g_string_append_len( str, "\n\t\t\t\t\t\t\t\t",
+ indent < 8 ? indent : 8 );
g_string_append_printf( str, "</%s>", node->name );
}
@@ -319,74 +327,27 @@ static void xt_to_string_real( struct xt_node *node, GString *str )
char *xt_to_string( struct xt_node *node )
{
GString *ret;
- char *real;
ret = g_string_new( "" );
- xt_to_string_real( node, ret );
-
- real = ret->str;
- g_string_free( ret, FALSE );
+ xt_to_string_real( node, ret, 0 );
+ return g_string_free( ret, FALSE );
+}
+
+/* WITH indentation! */
+char *xt_to_string_i( struct xt_node *node )
+{
+ GString *ret;
- return real;
+ ret = g_string_new( "" );
+ xt_to_string_real( node, ret, 1 );
+ return g_string_free( ret, FALSE );
}
void xt_print( struct xt_node *node )
{
- int i;
- struct xt_node *c;
-
- /* Indentation */
- for( c = node; c->parent; c = c->parent )
- fprintf( stderr, " " );
-
- /* Start the tag */
- fprintf( stderr, "<%s", node->name );
-
- /* Print the attributes */
- for( i = 0; node->attr[i].key; i ++ )
- {
- char *v = g_markup_escape_text( node->attr[i].value, -1 );
- fprintf( stderr, " %s=\"%s\"", node->attr[i].key, v );
- g_free( v );
- }
-
- /* /> in case there's really *nothing* inside this tag, otherwise
- just >. */
- /* If this tag doesn't have any content at all... */
- if( node->text == NULL && node->children == NULL )
- {
- fprintf( stderr, "/>\n" );
- return;
- /* Then we're finished! */
- }
-
- /* Otherwise... */
- fprintf( stderr, ">" );
-
- /* Only print the text if it contains more than whitespace (TEST). */
- if( node->text_len > 0 )
- {
- for( i = 0; node->text[i] && isspace( node->text[i] ); i ++ );
- if( node->text[i] )
- {
- char *v = g_markup_escape_text( node->text, -1 );
- fprintf( stderr, "%s", v );
- g_free( v );
- }
- }
-
- if( node->children )
- fprintf( stderr, "\n" );
-
- for( c = node->children; c; c = c->next )
- xt_print( c );
-
- if( node->children )
- for( c = node; c->parent; c = c->parent )
- fprintf( stderr, " " );
-
- /* Non-empty tag is now finished. */
- fprintf( stderr, "</%s>\n", node->name );
+ char *str = xt_to_string_i( node );
+ fprintf( stderr, "%s", str );
+ g_free( str );
}
struct xt_node *xt_dup( struct xt_node *node )
diff --git a/lib/xmltree.h b/lib/xmltree.h
index 2db3caf4..a41cbac1 100644
--- a/lib/xmltree.h
+++ b/lib/xmltree.h
@@ -83,6 +83,7 @@ int xt_handle( struct xt_parser *xt, struct xt_node *node, int depth );
void xt_cleanup( struct xt_parser *xt, struct xt_node *node, int depth );
struct xt_node *xt_from_string( const char *in, int text_len );
char *xt_to_string( struct xt_node *node );
+char *xt_to_string_i( struct xt_node *node );
void xt_print( struct xt_node *node );
struct xt_node *xt_dup( struct xt_node *node );
void xt_free_node( struct xt_node *node );
diff --git a/protocols/account.c b/protocols/account.c
index e9388710..dec9c3ea 100644
--- a/protocols/account.c
+++ b/protocols/account.c
@@ -52,7 +52,7 @@ account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass )
a->bee = bee;
s = set_add( &a->set, "auto_connect", "true", set_eval_account, a );
- s->flags |= ACC_SET_NOSAVE;
+ s->flags |= SET_NOSAVE;
s = set_add( &a->set, "auto_reconnect", "true", set_eval_bool, a );
@@ -60,16 +60,16 @@ account_t *account_add( bee_t *bee, struct prpl *prpl, char *user, char *pass )
s->flags |= SET_NULL_OK;
s = set_add( &a->set, "nick_source", "handle", set_eval_nick_source, a );
- s->flags |= ACC_SET_NOSAVE; /* Just for bw compatibility! */
+ s->flags |= SET_NOSAVE; /* Just for bw compatibility! */
s = set_add( &a->set, "password", NULL, set_eval_account, a );
- s->flags |= ACC_SET_NOSAVE | SET_NULL_OK | SET_PASSWORD;
+ s->flags |= SET_NOSAVE | SET_NULL_OK | SET_PASSWORD;
s = set_add( &a->set, "tag", NULL, set_eval_account, a );
- s->flags |= ACC_SET_NOSAVE;
+ s->flags |= SET_NOSAVE;
s = set_add( &a->set, "username", NULL, set_eval_account, a );
- s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
set_setstr( &a->set, "username", user );
/* Hardcode some more clever tag guesses. */
diff --git a/protocols/account.h b/protocols/account.h
index 84f0ec36..ed3ca531 100644
--- a/protocols/account.h
+++ b/protocols/account.h
@@ -60,7 +60,6 @@ int account_reconnect_delay( account_t *a );
typedef enum
{
- ACC_SET_NOSAVE = 0x01, /* Don't save this setting (i.e. stored elsewhere). */
ACC_SET_OFFLINE_ONLY = 0x02, /* Allow changes only if the acct is offline. */
ACC_SET_ONLINE_ONLY = 0x04, /* Allow changes only if the acct is online. */
} account_set_flag_t;
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index 56263192..dab4afdf 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -79,7 +79,7 @@ static void jabber_init( account_t *acc )
s->flags |= ACC_SET_OFFLINE_ONLY | SET_HIDDEN_DEFAULT;
s = set_add( &acc->set, "server", NULL, set_eval_account, acc );
- s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
+ s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY | SET_NULL_OK;
s = set_add( &acc->set, "ssl", "false", set_eval_bool, acc );
s->flags |= ACC_SET_OFFLINE_ONLY;
diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c
index 052ff692..ad01ca24 100644
--- a/protocols/msn/msn.c
+++ b/protocols/msn/msn.c
@@ -38,7 +38,7 @@ static void msn_init( account_t *acc )
set_t *s;
s = set_add( &acc->set, "display_name", NULL, set_eval_display_name, acc );
- s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
set_add( &acc->set, "mail_notifications", "false", set_eval_bool, acc );
set_add( &acc->set, "switchboard_keepalives", "false", set_eval_bool, acc );
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 0a1de519..05be086d 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -377,7 +377,7 @@ static void oscar_init(account_t *acc)
s = set_add(&acc->set, "server",
icq ? AIM_DEFAULT_LOGIN_SERVER_ICQ
: AIM_DEFAULT_LOGIN_SERVER_AIM, set_eval_account, acc);
- s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
if (icq) {
s = set_add(&acc->set, "web_aware", "false", set_eval_bool, acc);
diff --git a/protocols/skype/skype.c b/protocols/skype/skype.c
index f6c0a261..7ce562d4 100644
--- a/protocols/skype/skype.c
+++ b/protocols/skype/skype.c
@@ -1560,16 +1560,16 @@ static void skype_init(account_t *acc)
s = set_add(&acc->set, "display_name", NULL, skype_set_display_name,
acc);
- s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
s = set_add(&acc->set, "mood_text", NULL, skype_set_mood_text, acc);
s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
s = set_add(&acc->set, "call", NULL, skype_set_call, acc);
- s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
s = set_add(&acc->set, "balance", NULL, skype_set_balance, acc);
- s->flags |= ACC_SET_NOSAVE | ACC_SET_ONLINE_ONLY;
+ s->flags |= SET_NOSAVE | ACC_SET_ONLINE_ONLY;
s = set_add(&acc->set, "skypeout_offline", "true", set_eval_bool, acc);
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c
index ccbfeb2d..05222af2 100644
--- a/protocols/twitter/twitter_lib.c
+++ b/protocols/twitter/twitter_lib.c
@@ -39,14 +39,6 @@
#include <ctype.h>
#include <errno.h>
-/* GLib < 2.12.0 doesn't have g_ascii_strtoll(), work around using system strtoll(). */
-/* GLib < 2.12.4 can be buggy: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=488013 */
-#if !GLIB_CHECK_VERSION(2,12,5)
-#include <stdlib.h>
-#include <limits.h>
-#define g_ascii_strtoll strtoll
-#endif
-
#define TXL_STATUS 1
#define TXL_USER 2
#define TXL_ID 3
diff --git a/root_commands.c b/root_commands.c
index d05861ec..77f40060 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -280,7 +280,7 @@ static void cmd_drop( irc_t *irc, char **cmd )
static void cmd_save( irc_t *irc, char **cmd )
{
if( ( irc->status & USTATUS_IDENTIFIED ) == 0 )
- irc_rootmsg( irc, "Please create an account first" );
+ irc_rootmsg( irc, "Please create an account first (see \x02help register\x02)" );
else if( storage_save( irc, NULL, TRUE ) == STORAGE_OK )
irc_rootmsg( irc, "Configuration saved" );
else
diff --git a/set.h b/set.h
index d4915546..2a3ce4d1 100644
--- a/set.h
+++ b/set.h
@@ -44,11 +44,11 @@ extern char *SET_INVALID;
typedef enum
{
- SET_NOSAVE = 0x0001,
- SET_NULL_OK = 0x0100,
- SET_HIDDEN = 0x0200,
- SET_PASSWORD = 0x0400,
- SET_HIDDEN_DEFAULT = 0x0800,
+ SET_NOSAVE = 0x0001, /* Don't save this setting (i.e. stored elsewhere). */
+ SET_NULL_OK = 0x0100, /* set->value == NULL is allowed. */
+ SET_HIDDEN = 0x0200, /* Don't show up in setting lists. Mostly for internal storage. */
+ SET_PASSWORD = 0x0400, /* Value shows up in settings list as "********". */
+ SET_HIDDEN_DEFAULT = 0x0800, /* Hide unless changed from default. */
} set_flags_t;
typedef struct set
diff --git a/storage.c b/storage.c
index d64d9cda..cb6814c4 100644
--- a/storage.c
+++ b/storage.c
@@ -194,46 +194,3 @@ storage_status_t storage_remove (const char *nick, const char *password)
return ret;
}
-
-#if 0
-Not using this yet. Test thoroughly before adding UI hooks to this function.
-
-storage_status_t storage_rename (const char *onick, const char *nnick, const char *password)
-{
- storage_status_t status;
- GList *gl = global.storage;
- storage_t *primary_storage = gl->data;
- irc_t *irc;
-
- /* First, try to rename in the current write backend, assuming onick
- * is stored there */
- status = primary_storage->rename(onick, nnick, password);
- if (status != STORAGE_NO_SUCH_USER)
- return status;
-
- /* Try to load from a migration backend and save to the current backend.
- * Explicitly remove the account from the migration backend as otherwise
- * it'd still be usable under the old name */
-
- irc = g_new0(irc_t, 1);
- status = storage_load(onick, password, irc);
- if (status != STORAGE_OK) {
- irc_free(irc);
- return status;
- }
-
- g_free(irc->nick);
- irc->nick = g_strdup(nnick);
-
- status = storage_save(irc, FALSE);
- if (status != STORAGE_OK) {
- irc_free(irc);
- return status;
- }
- irc_free(irc);
-
- storage_remove(onick, password);
-
- return STORAGE_OK;
-}
-#endif
diff --git a/storage.h b/storage.h
index f2e9afce..994851eb 100644
--- a/storage.h
+++ b/storage.h
@@ -58,8 +58,6 @@ storage_status_t storage_load (irc_t * irc, const char *password);
storage_status_t storage_save (irc_t *irc, char *password, int overwrite);
storage_status_t storage_remove (const char *nick, const char *password);
-/* storage_status_t storage_rename (const char *onick, const char *nnick, const char *password); */
-
void register_storage_backend(storage_t *);
G_GNUC_MALLOC GList *storage_init(const char *primary, char **migrate);
diff --git a/storage_ldap.c b/storage_ldap.c
deleted file mode 100644
index 4bc99de5..00000000
--- a/storage_ldap.c
+++ /dev/null
@@ -1,177 +0,0 @@
- /********************************************************************\
- * 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_xml.c b/storage_xml.c
index 0525fef5..10cb6495 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -1,7 +1,7 @@
/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
- * Copyright 2002-2006 Wilmer van der Gaast and others *
+ * Copyright 2002-2012 Wilmer van der Gaast and others *
\********************************************************************/
/* Storage backend that uses an XMLish format for all data. */
@@ -28,14 +28,9 @@
#include "base64.h"
#include "arc.h"
#include "md5.h"
+#include "xmltree.h"
-#if GLIB_CHECK_VERSION(2,8,0)
#include <glib/gstdio.h>
-#else
-/* GLib < 2.8.0 doesn't have g_access, so just use the system access(). */
-#include <unistd.h>
-#define g_access access
-#endif
typedef enum
{
@@ -46,373 +41,201 @@ typedef enum
} xml_pass_st;
/* To make it easier later when extending the format: */
-#define XML_FORMAT_VERSION 1
+#define XML_FORMAT_VERSION "1"
struct xml_parsedata
{
irc_t *irc;
- char *current_setting;
- account_t *current_account;
- irc_channel_t *current_channel;
- set_t **current_set_head;
- char *given_nick;
+ char given_nick[MAX_NICK_LENGTH+1];
char *given_pass;
- xml_pass_st pass_st;
- int unknown_tag;
};
-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 )
+static void xml_init( void )
{
- struct xml_parsedata *xd = data;
-
- g_free( xd->given_nick );
- g_free( xd->given_pass );
- g_free( xd );
+ if( g_access( global.conf->configdir, F_OK ) != 0 )
+ log_message( LOGLVL_WARNING, "The configuration directory `%s' does not exist. Configuration won't be saved.", global.conf->configdir );
+ else if( g_access( global.conf->configdir, F_OK ) != 0 ||
+ g_access( global.conf->configdir, W_OK ) != 0 )
+ log_message( LOGLVL_WARNING, "Permission problem: Can't read/write from/to `%s'.", global.conf->configdir );
}
-static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_name, const gchar **attr_names, const gchar **attr_values, gpointer data, GError **error )
+static void handle_settings( struct xt_node *node, set_t **head )
{
- struct xml_parsedata *xd = data;
- irc_t *irc = xd->irc;
+ struct xt_node *c;
- if( xd->unknown_tag > 0 )
- {
- xd->unknown_tag ++;
- }
- else if( g_strcasecmp( element_name, "user" ) == 0 )
+ for( c = node->children; ( c = xt_find_node( c, "setting" ) ); c = c->next )
{
- char *nick = xml_attr( attr_names, attr_values, "nick" );
- char *pass = xml_attr( attr_names, attr_values, "password" );
- int st;
+ char *name = xt_find_attr( c, "name" );
- if( !nick || !pass )
- {
- g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
- "Missing attributes for %s element", element_name );
- }
- else if( ( st = md5_verify_password( xd->given_pass, pass ) ) == -1 )
- {
- xd->pass_st = XML_PASS_WRONG;
- g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
- "Error while decoding password attribute" );
- }
- else if( st == 0 )
- {
- if( xd->pass_st != XML_PASS_CHECK_ONLY )
- xd->pass_st = XML_PASS_OK;
- }
- else
- {
- xd->pass_st = XML_PASS_WRONG;
- g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
- "Password mismatch" );
- }
- }
- 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, *tag;
- char *pass_b64 = NULL;
- unsigned char *pass_cr = 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" );
- tag = xml_attr( attr_names, attr_values, "tag" );
-
- protocol = xml_attr( attr_names, attr_values, "protocol" );
- if( protocol )
- prpl = find_protocol( protocol );
+ if( !name )
+ continue;
- 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_cr ) ) &&
- arc_decode( pass_cr, pass_len, &password, xd->given_pass ) >= 0 )
- {
- xd->current_account = account_add( irc->b, prpl, handle, password );
- if( server )
- set_setstr( &xd->current_account->set, "server", server );
- if( autoconnect )
- set_setstr( &xd->current_account->set, "auto_connect", autoconnect );
- if( tag )
- set_setstr( &xd->current_account->set, "tag", tag );
- }
- else
+ if( strcmp( node->name, "account" ) == 0 )
{
- /* 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" );
+ set_t *s = set_find( head, name );
+ if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) )
+ continue; /* U can't touch this! */
}
-
- g_free( pass_cr );
- g_free( password );
+ set_setstr( head, name, c->text );
}
- else if( g_strcasecmp( element_name, "setting" ) == 0 )
+}
+
+static xt_status handle_account( struct xt_node *node, gpointer data )
+{
+ struct xml_parsedata *xd = data;
+ char *protocol, *handle, *server, *password = NULL, *autoconnect, *tag;
+ char *pass_b64 = NULL;
+ unsigned char *pass_cr = NULL;
+ int pass_len;
+ struct prpl *prpl = NULL;
+ account_t *acc;
+ struct xt_node *c;
+
+ handle = xt_find_attr( node, "handle" );
+ pass_b64 = xt_find_attr( node, "password" );
+ server = xt_find_attr( node, "server" );
+ autoconnect = xt_find_attr( node, "autoconnect" );
+ tag = xt_find_attr( node, "tag" );
+
+ protocol = xt_find_attr( node, "protocol" );
+ if( protocol )
+ prpl = find_protocol( protocol );
+
+ if( !handle || !pass_b64 || !protocol || !prpl )
+ return XT_ABORT;
+ else if( ( pass_len = base64_decode( pass_b64, (unsigned char**) &pass_cr ) ) &&
+ arc_decode( pass_cr, pass_len, &password, xd->given_pass ) >= 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" ) ) )
- {
- if( xd->current_channel != NULL )
- xd->current_set_head = &xd->current_channel->set;
- else if( xd->current_account != NULL )
- xd->current_set_head = &xd->current_account->set;
- else
- xd->current_set_head = &xd->irc->b->set;
-
- 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 );
+ acc = account_add( xd->irc->b, prpl, handle, password );
+ if( server )
+ set_setstr( &acc->set, "server", server );
+ if( autoconnect )
+ set_setstr( &acc->set, "auto_connect", autoconnect );
+ if( tag )
+ set_setstr( &acc->set, "tag", tag );
}
- else if( g_strcasecmp( element_name, "buddy" ) == 0 )
+ else
+ return XT_ABORT;
+
+ g_free( pass_cr );
+ g_free( password );
+
+ handle_settings( node, &acc->set );
+
+ for( c = node->children; ( c = xt_find_node( c, "buddy" ) ); c = c->next )
{
char *handle, *nick;
- handle = xml_attr( attr_names, attr_values, "handle" );
- nick = xml_attr( attr_names, attr_values, "nick" );
+ handle = xt_find_attr( c, "handle" );
+ nick = xt_find_attr( c, "nick" );
- if( xd->current_account && handle && nick )
- {
- nick_set_raw( xd->current_account, handle, nick );
- }
+ if( handle && nick )
+ nick_set_raw( acc, handle, nick );
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, "channel" ) == 0 )
- {
- char *name, *type;
-
- name = xml_attr( attr_names, attr_values, "name" );
- type = xml_attr( attr_names, attr_values, "type" );
-
- if( !name || !type )
- {
- g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
- "Missing attributes for %s element", element_name );
- return;
- }
-
- /* The channel may exist already, for example if it's &bitlbee.
- Also, it's possible that the user just reconnected and the
- IRC client already rejoined all channels it was in. They
- should still get the right settings. */
- if( ( xd->current_channel = irc_channel_by_name( irc, name ) ) ||
- ( xd->current_channel = irc_channel_new( irc, name ) ) )
- set_setstr( &xd->current_channel->set, "type", type );
- }
- /* Backward compatibility: Keep this around for a while for people
- switching from BitlBee 1.2.4+. */
- else if( g_strcasecmp( element_name, "chat" ) == 0 )
- {
- char *handle, *channel;
-
- handle = xml_attr( attr_names, attr_values, "handle" );
- channel = xml_attr( attr_names, attr_values, "channel" );
-
- if( xd->current_account && handle && channel )
- {
- irc_channel_t *ic;
-
- if( ( ic = irc_channel_new( irc, channel ) ) &&
- set_setstr( &ic->set, "type", "chat" ) &&
- set_setstr( &ic->set, "chat_type", "room" ) &&
- set_setstr( &ic->set, "account", xd->current_account->tag ) &&
- set_setstr( &ic->set, "room", handle ) )
- {
- /* Try to pick up some settings where possible. */
- xd->current_channel = ic;
- }
- else if( ic )
- irc_channel_free( ic );
- }
- else
- {
- g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
- "Missing attributes for %s element", element_name );
- }
- }
- else
- {
- xd->unknown_tag ++;
- irc_rootmsg( irc, "Warning: Unknown XML tag found in configuration file (%s). "
- "This may happen when downgrading BitlBee versions. "
- "This tag will be skipped and the information will be lost "
- "once you save your settings.", element_name );
- /*
- g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
- "Unkown element: %s", element_name );
- */
- }
+ return XT_ABORT;
+ }
+ return XT_HANDLED;
}
-static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name, gpointer data, GError **error )
+static xt_status handle_channel( struct xt_node *node, gpointer data )
{
struct xml_parsedata *xd = data;
+ irc_channel_t *ic;
+ char *name, *type;
- if( xd->unknown_tag > 0 )
- {
- xd->unknown_tag --;
- }
- else 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;
- }
- else if( g_strcasecmp( element_name, "channel" ) == 0 ||
- g_strcasecmp( element_name, "chat" ) == 0 )
- {
- xd->current_channel = NULL;
- }
-}
-
-static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize text_len, gpointer data, GError **error )
-{
- char text[text_len+1];
- struct xml_parsedata *xd = data;
+ name = xt_find_attr( node, "name" );
+ type = xt_find_attr( node, "type" );
- strncpy( text, text_orig, text_len );
- text[text_len] = 0;
+ if( !name || !type )
+ return XT_ABORT;
- 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 )
- {
- if( xd->current_account )
- {
- set_t *s = set_find( xd->current_set_head, xd->current_setting );
- if( s && ( s->flags & ACC_SET_ONLINE_ONLY ) )
- {
- g_free( xd->current_setting );
- xd->current_setting = NULL;
- return;
- }
- }
- set_setstr( xd->current_set_head, xd->current_setting, (char*) text );
- g_free( xd->current_setting );
- xd->current_setting = NULL;
- }
+ /* The channel may exist already, for example if it's &bitlbee.
+ Also, it's possible that the user just reconnected and the
+ IRC client already rejoined all channels it was in. They
+ should still get the right settings. */
+ if( ( ic = irc_channel_by_name( xd->irc, name ) ) ||
+ ( ic = irc_channel_new( xd->irc, name ) ) )
+ set_setstr( &ic->set, "type", type );
+
+ handle_settings( node, &ic->set );
+
+ return XT_HANDLED;
}
-GMarkupParser xml_parser =
-{
- xml_start_element,
- xml_end_element,
- xml_text,
- NULL,
- NULL
+static const struct xt_handler_entry handlers[] = {
+ { "account", "user", handle_account, },
+ { "channel", "user", handle_channel, },
+ { NULL, NULL, NULL, },
};
-static void xml_init( void )
-{
- if( g_access( global.conf->configdir, F_OK ) != 0 )
- log_message( LOGLVL_WARNING, "The configuration directory `%s' does not exist. Configuration won't be saved.", global.conf->configdir );
- else if( g_access( global.conf->configdir, F_OK ) != 0 ||
- g_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( irc_t *irc, const char *my_nick, const char *password, xml_pass_st action )
{
- GMarkupParseContext *ctx;
- struct xml_parsedata *xd;
- char *fn, buf[512];
- GError *gerr = NULL;
+ struct xml_parsedata xd[1];
+ char *fn, buf[2048];
int fd, st;
+ struct xt_parser *xp;
+ struct xt_node *node;
+ storage_status_t ret = STORAGE_OTHER_ERROR;
- 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;
+ strncpy( xd->given_nick, my_nick, MAX_NICK_LENGTH );
+ xd->given_nick[MAX_NICK_LENGTH] = '\0';
nick_lc( xd->given_nick );
+ xd->given_pass = password;
- fn = g_strdup_printf( "%s%s%s", global.conf->configdir, xd->given_nick, ".xml" );
+ fn = g_strconcat( global.conf->configdir, xd->given_nick, ".xml", NULL );
if( ( fd = open( fn, O_RDONLY ) ) < 0 )
{
- xml_destroy_xd( xd );
- g_free( fn );
- return STORAGE_NO_SUCH_USER;
+ ret = STORAGE_NO_SUCH_USER;
+ goto error;
}
- g_free( fn );
-
- ctx = g_markup_parse_context_new( &xml_parser, 0, xd, xml_destroy_xd );
+ xp = xt_new( handlers, xd );
while( ( st = read( fd, buf, sizeof( buf ) ) ) > 0 )
{
- if( !g_markup_parse_context_parse( ctx, buf, st, &gerr ) || gerr )
+ st = xt_feed( xp, buf, st );
+ if( st != 1 )
+ break;
+ }
+ close( fd );
+ if( st != 0 )
+ goto error;
+
+ node = xp->root;
+ if( node == NULL || node->next != NULL || strcmp( node->name, "user" ) != 0 )
+ goto error;
+
+ {
+ char *nick = xt_find_attr( node, "nick" );
+ char *pass = xt_find_attr( node, "password" );
+
+ if( !nick || !pass )
{
- 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_rootmsg( irc, "Error from XML-parser: %s", gerr->message );
-
- g_clear_error( &gerr );
- return STORAGE_OTHER_ERROR;
- }
+ goto error;
+ }
+ else if( ( st = md5_verify_password( xd->given_pass, pass ) ) != 0 )
+ {
+ ret = STORAGE_INVALID_PASSWORD;
+ goto 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;
+ {
+ ret = STORAGE_OK;
+ goto error;
+ }
- return STORAGE_OK;
+ /* DO NOT call xt_handle() before verifying the password! */
+ if( xt_handle( xp, NULL, 1 ) == XT_HANDLED )
+ ret = STORAGE_OK;
+
+ handle_settings( node, &xd->irc->b->set );
+
+error:
+ xt_free( xp );
+ g_free( fn );
+ return ret;
}
static storage_status_t xml_load( irc_t *irc, const char *password )
@@ -422,59 +245,21 @@ static storage_status_t xml_load( irc_t *irc, const char *password )
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( NULL, my_nick, password, 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 gboolean xml_save_nick( gpointer key, gpointer value, gpointer data );
+static gboolean xml_generate_nick( gpointer key, gpointer value, gpointer data );
+static void xml_generate_settings( struct xt_node *cur, set_t **head );
-static storage_status_t xml_save( irc_t *irc, int overwrite )
+struct xt_node *xml_generate( irc_t *irc )
{
- char path[512], *path2, *pass_buf = NULL;
- set_t *set;
+ char *pass_buf = NULL;
account_t *acc;
- int fd;
md5_byte_t pass_md5[21];
md5_state_t md5_state;
GSList *l;
-
- path2 = g_strdup( irc->user->nick );
- nick_lc( path2 );
- g_snprintf( path, sizeof( path ) - 2, "%s%s%s", global.conf->configdir, path2, ".xml" );
- g_free( path2 );
-
- if( !overwrite && g_access( path, F_OK ) == 0 )
- return STORAGE_ALREADY_EXISTS;
-
- strcat( path, ".XXXXXX" );
- if( ( fd = mkstemp( path ) ) < 0 )
- {
- irc_rootmsg( irc, "Error while opening configuration file." );
- return STORAGE_OTHER_ERROR;
- }
+ struct xt_node *root, *cur;
/* 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-
@@ -487,15 +272,14 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
/* Save the hash in base64-encoded form. */
pass_buf = base64_encode( pass_md5, 21 );
- if( !xml_printf( fd, 0, "<user nick=\"%s\" password=\"%s\" version=\"%d\">\n", irc->user->nick, pass_buf, XML_FORMAT_VERSION ) )
- goto write_error;
+ root = cur = xt_new_node( "user", NULL, NULL );
+ xt_add_attr( cur, "nick", irc->user->nick );
+ xt_add_attr( cur, "password", pass_buf );
+ xt_add_attr( cur, "version", XML_FORMAT_VERSION );
g_free( pass_buf );
- for( set = irc->b->set; set; set = set->next )
- if( set->value && !( set->flags & SET_NOSAVE ) )
- if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
- goto write_error;
+ xml_generate_settings( cur, &irc->b->set );
for( acc = irc->b->accounts; acc; acc = acc->next )
{
@@ -507,37 +291,29 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
pass_b64 = base64_encode( pass_cr, pass_len );
g_free( pass_cr );
- if( !xml_printf( fd, 1, "<account protocol=\"%s\" handle=\"%s\" password=\"%s\" "
- "autoconnect=\"%d\" tag=\"%s\"", acc->prpl->name, acc->user,
- pass_b64, acc->auto_connect, acc->tag ) )
- {
- 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;
+ cur = xt_new_node( "account", NULL, NULL );
+ xt_add_attr( cur, "protocol", acc->prpl->name );
+ xt_add_attr( cur, "handle", acc->user );
+ xt_add_attr( cur, "password", pass_b64 );
+ xt_add_attr( cur, "autoconnect", acc->auto_connect ? "true" : "false" );
+ xt_add_attr( cur, "tag", acc->tag );
+ if( acc->server && acc->server[0] )
+ xt_add_attr( cur, "server", acc->server );
- for( set = acc->set; set; set = set->next )
- if( set->value && !( set->flags & ACC_SET_NOSAVE ) )
- if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
- goto write_error;
+ g_free( pass_b64 );
/* This probably looks pretty strange. g_hash_table_foreach
is quite a PITA already (but it can't get much better in
- C without using #define, I'm afraid), and since it
+ C without using #define, I'm afraid), and it
doesn't seem to be possible to abort the foreach on write
errors, so instead let's use the _find function and
return TRUE on write errors. Which means, if we found
something, there was an error. :-) */
- if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) )
- goto write_error;
+ g_hash_table_find( acc->nicks, xml_generate_nick, cur );
- if( !xml_printf( fd, 1, "</account>\n" ) )
- goto write_error;
+ xml_generate_settings( cur, &acc->set );
+
+ xt_add_child( root, cur );
}
for( l = irc->channels; l; l = l->next )
@@ -547,53 +323,95 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
if( ic->flags & IRC_CHANNEL_TEMP )
continue;
- if( !xml_printf( fd, 1, "<channel name=\"%s\" type=\"%s\">\n",
- ic->name, set_getstr( &ic->set, "type" ) ) )
- goto write_error;
+ cur = xt_new_node( "channel", NULL, NULL );
+ xt_add_attr( cur, "name", ic->name );
+ xt_add_attr( cur, "type", set_getstr( &ic->set, "type" ) );
- for( set = ic->set; set; set = set->next )
- if( set->value && strcmp( set->key, "type" ) != 0 )
- if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
- goto write_error;
+ xml_generate_settings( cur, &ic->set );
- if( !xml_printf( fd, 1, "</channel>\n" ) )
- goto write_error;
+ xt_add_child( root, cur );
}
- if( !xml_printf( fd, 0, "</user>\n" ) )
- goto write_error;
+ return root;
+}
+
+static gboolean xml_generate_nick( gpointer key, gpointer value, gpointer data )
+{
+ struct xt_node *node = xt_new_node( "buddy", NULL, NULL );
+ xt_add_attr( node, "handle", key );
+ xt_add_attr( node, "nick", value );
+ xt_add_child( (struct xt_node *) data, node );
- fsync( fd );
- close( fd );
+ return FALSE;
+}
+
+static void xml_generate_settings( struct xt_node *cur, set_t **head )
+{
+ set_t *set;
+
+ for( set = *head; set; set = set->next )
+ if( set->value && !( set->flags & SET_NOSAVE ) )
+ {
+ struct xt_node *xset;
+ xt_add_child( cur, xset = xt_new_node( "setting", set->value, NULL ) );
+ xt_add_attr( xset, "name", set->key );
+ }
+}
+
+static storage_status_t xml_save( irc_t *irc, int overwrite )
+{
+ storage_status_t ret = STORAGE_OK;
+ char path[512], *path2 = NULL, *xml = NULL;
+ struct xt_node *tree = NULL;
+ size_t len;
+ int fd;
+
+ path2 = g_strdup( irc->user->nick );
+ nick_lc( path2 );
+ g_snprintf( path, sizeof( path ) - 20, "%s%s%s", global.conf->configdir, path2, ".xml" );
+ g_free( path2 );
+
+ if( !overwrite && g_access( path, F_OK ) == 0 )
+ return STORAGE_ALREADY_EXISTS;
+
+ strcat( path, ".XXXXXX" );
+ if( ( fd = mkstemp( path ) ) < 0 )
+ {
+ irc_rootmsg( irc, "Error while opening configuration file." );
+ return STORAGE_OTHER_ERROR;
+ }
+
+ tree = xml_generate( irc );
+ xml = xt_to_string_i( tree );
+ len = strlen( xml );
+ if( write( fd, xml, len ) != len ||
+ fsync( fd ) != 0 || /* #559 */
+ close( fd ) != 0 )
+ goto error;
path2 = g_strndup( path, strlen( path ) - 7 );
if( rename( path, path2 ) != 0 )
{
- irc_rootmsg( irc, "Error while renaming temporary configuration file." );
-
g_free( path2 );
- unlink( path );
-
- return STORAGE_OTHER_ERROR;
+ goto error;
}
-
g_free( path2 );
- return STORAGE_OK;
+ goto finish;
-write_error:
- g_free( pass_buf );
-
+error:
irc_rootmsg( irc, "Write error. Disk full?" );
+ ret = STORAGE_OTHER_ERROR;
+
+finish:
close( fd );
+ unlink( path );
+ g_free( xml );
+ xt_free_node( tree );
- return STORAGE_OTHER_ERROR;
+ return ret;
}
-static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data )
-{
- return !xml_printf( *( (int*) data ), 2, "<buddy handle=\"%s\" nick=\"%s\" />\n", key, value );
-}
static storage_status_t xml_remove( const char *nick, const char *password )
{