aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--account.c6
-rw-r--r--account.h1
-rw-r--r--bitlbee.h1
-rw-r--r--irc.c43
-rw-r--r--irc.h2
-rw-r--r--irc_commands.c3
-rw-r--r--nick.c111
-rw-r--r--nick.h14
-rw-r--r--protocols/jabber/jabber.c2
-rw-r--r--protocols/msn/msn.c2
-rw-r--r--protocols/nogaim.c14
-rw-r--r--protocols/nogaim.h2
-rw-r--r--protocols/oscar/oscar.c3
-rw-r--r--protocols/yahoo/yahoo.c3
-rw-r--r--root_commands.c59
-rw-r--r--storage_text.c178
-rw-r--r--storage_xml.c23
-rw-r--r--user.c26
18 files changed, 118 insertions, 375 deletions
diff --git a/account.c b/account.c
index 1f2ec165..28c33d3b 100644
--- a/account.c
+++ b/account.c
@@ -58,6 +58,8 @@ account_t *account_add( irc_t *irc, struct prpl *prpl, char *user, char *pass )
s->flags |= ACC_SET_NOSAVE | ACC_SET_OFFLINE_ONLY;
set_setstr( &a->set, "username", user );
+ a->nicks = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
+
/* This function adds some more settings (and might want to do more
things that have to be done now, although I can't think of anything. */
if( prpl->acc_init )
@@ -125,7 +127,7 @@ account_t *account_get( irc_t *irc, char *id )
{
for( a = irc->accounts; a; a = a->next )
if( a->prpl == proto &&
- a->prpl->cmp_buddynames( handle, a->user ) == 0 )
+ a->prpl->handle_cmp( handle, a->user ) == 0 )
ret = a;
}
@@ -189,6 +191,8 @@ void account_del( irc_t *irc, account_t *acc )
while( a->set )
set_del( &a->set, a->set->key );
+ g_hash_table_destroy( a->nicks );
+
g_free( a->user );
g_free( a->pass );
if( a->server ) g_free( a->server );
diff --git a/account.h b/account.h
index 9cf6987d..83f47a89 100644
--- a/account.h
+++ b/account.h
@@ -37,6 +37,7 @@ typedef struct account
int reconnect;
set_t *set;
+ GHashTable *nicks;
struct irc *irc;
struct gaim_connection *gc;
diff --git a/bitlbee.h b/bitlbee.h
index 1462316f..f068aeac 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -123,6 +123,7 @@ extern char *CONF_FILE;
#include "nogaim.h"
#include "commands.h"
#include "account.h"
+#include "nick.h"
#include "conf.h"
#include "log.h"
#include "ini.h"
diff --git a/irc.c b/irc.c
index bac91198..fe55a02c 100644
--- a/irc.c
+++ b/irc.c
@@ -203,11 +203,9 @@ static gboolean irc_free_hashkey( gpointer key, gpointer value, gpointer data )
/* Because we have no garbage collection, this is quite annoying */
void irc_free(irc_t * irc)
{
- account_t *account, *accounttmp;
+ account_t *account;
user_t *user, *usertmp;
- nick_t *nick, *nicktmp;
help_t *helpnode, *helpnodetmp;
- set_t *setnode, *setnodetmp;
log_message( LOGLVL_INFO, "Destroying connection with fd %d", irc->fd );
@@ -251,17 +249,11 @@ void irc_free(irc_t * irc)
while (irc->queries != NULL)
query_del(irc, irc->queries);
- if (irc->accounts != NULL) {
- account = irc->accounts;
- while (account != NULL) {
- g_free(account->user);
- g_free(account->pass);
- g_free(account->server);
- accounttmp = account;
- account = account->next;
- g_free(accounttmp);
- }
- }
+ while (irc->accounts)
+ account_del(irc, irc->accounts);
+
+ while (irc->set)
+ set_del(&irc->set, irc->set->key);
if (irc->users != NULL) {
user = irc->users;
@@ -286,17 +278,6 @@ void irc_free(irc_t * irc)
g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);
g_hash_table_destroy(irc->watches);
- if (irc->nicks != NULL) {
- nick = irc->nicks;
- while (nick != NULL) {
- g_free(nick->nick);
- g_free(nick->handle);
-
- nicktmp = nick;
- nick = nick->next;
- g_free(nicktmp);
- }
- }
if (irc->help != NULL) {
helpnode = irc->help;
while (helpnode != NULL) {
@@ -307,18 +288,6 @@ void irc_free(irc_t * irc)
g_free(helpnodetmp);
}
}
- if (irc->set != NULL) {
- setnode = irc->set;
- while (setnode != NULL) {
- g_free(setnode->key);
- g_free(setnode->def);
- g_free(setnode->value);
-
- setnodetmp = setnode;
- setnode = setnode->next;
- g_free(setnodetmp);
- }
- }
g_free(irc);
if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
diff --git a/irc.h b/irc.h
index ad52f42f..5b770180 100644
--- a/irc.h
+++ b/irc.h
@@ -97,7 +97,7 @@ typedef struct irc
} irc_t;
#include "user.h"
-#include "nick.h"
+// #include "nick.h"
extern GSList *irc_connection_list;
diff --git a/irc_commands.c b/irc_commands.c
index 889de9da..47d9e8cb 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -477,7 +477,8 @@ static void irc_cmd_whois( irc_t *irc, char **cmd )
if( u->gc )
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 );
+ u->gc->acc->server && *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/nick.c b/nick.c
index 56d6d378..14794bf3 100644
--- a/nick.c
+++ b/nick.c
@@ -1,7 +1,7 @@
/********************************************************************\
* BitlBee -- An IRC to other IM-networks gateway *
* *
- * Copyright 2002-2004 Wilmer van der Gaast and others *
+ * Copyright 2002-2006 Wilmer van der Gaast and others *
\********************************************************************/
/* Some stuff to fetch, save and handle nicknames for your buddies */
@@ -26,50 +26,48 @@
#define BITLBEE_CORE
#include "bitlbee.h"
-void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick )
+/* Store handles in lower case and strip spaces, because AIM is braindead. */
+static char *clean_handle( const char *orig )
{
- nick_t *m = NULL, *n = irc->nicks;
+ char *new = g_malloc( strlen( orig ) + 1 );
+ int i = 0;
- while( n )
- {
- if( ( g_strcasecmp( n->handle, handle ) == 0 ) && n->proto == proto )
- {
- g_free( n->nick );
- n->nick = nick_dup( nick );
- nick_strip( n->nick );
-
- return;
- }
- n = ( m = n )->next; // :-P
+ do {
+ if (*orig != ' ')
+ new[i++] = tolower( *orig );
}
+ while (*(orig++));
- if( m )
- n = m->next = g_new0( nick_t, 1 );
- else
- n = irc->nicks = g_new0( nick_t, 1 );
+ return new;
+}
+
+void nick_set( account_t *acc, const char *handle, const char *nick )
+{
+ char *store_handle, *store_nick = g_malloc( MAX_NICK_LENGTH + 1 );
- n->handle = g_strdup( handle );
- n->proto = proto;
- n->nick = nick_dup( nick );
+ store_handle = clean_handle( handle );
+ strncpy( store_nick, nick, MAX_NICK_LENGTH );
+ nick_strip( store_nick );
- nick_strip( n->nick );
+ g_hash_table_replace( acc->nicks, store_handle, store_nick );
}
-char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname )
+char *nick_get( account_t *acc, const char *handle, const char *realname )
{
static char nick[MAX_NICK_LENGTH+1];
- nick_t *n = irc->nicks;
+ char *store_handle, *found_nick;
int inf_protection = 256;
memset( nick, 0, MAX_NICK_LENGTH + 1 );
- while( n && !*nick )
- if( ( n->proto == proto ) && ( g_strcasecmp( n->handle, handle ) == 0 ) )
- strcpy( nick, n->nick );
- else
- n = n->next;
-
- if( !n )
+ store_handle = clean_handle( handle );
+ /* Find out if we stored a nick for this person already. If not, try
+ to generate a sane nick automatically. */
+ if( ( found_nick = g_hash_table_lookup( acc->nicks, store_handle ) ) )
+ {
+ strncpy( nick, found_nick, MAX_NICK_LENGTH );
+ }
+ else
{
char *s;
@@ -85,11 +83,14 @@ 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->set, "lcnicks" ) )
+ if( set_getbool( &acc->irc->set, "lcnicks" ) )
nick_lc( nick );
}
+ g_free( store_handle );
- while( !nick_ok( nick ) || user_find( irc, nick ) )
+ /* Now, find out if the nick is already in use at the moment, and make
+ subtle changes to make it unique. */
+ while( !nick_ok( nick ) || user_find( acc->irc, nick ) )
{
if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
{
@@ -105,19 +106,19 @@ char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *
{
int i;
- irc_usermsg( irc, "WARNING: Almost had an infinite loop in nick_get()! "
- "This used to be a fatal BitlBee bug, but we tried to fix it. "
- "This message should *never* appear anymore. "
- "If it does, please *do* send us a bug report! "
- "Please send all the following lines in your report:" );
+ irc_usermsg( acc->irc, "WARNING: Almost had an infinite loop in nick_get()! "
+ "This used to be a fatal BitlBee bug, but we tried to fix it. "
+ "This message should *never* appear anymore. "
+ "If it does, please *do* send us a bug report! "
+ "Please send all the following lines in your report:" );
- irc_usermsg( irc, "Trying to get a sane nick for handle %s", handle );
+ irc_usermsg( acc->irc, "Trying to get a sane nick for handle %s", handle );
for( i = 0; i < MAX_NICK_LENGTH; i ++ )
- irc_usermsg( irc, "Char %d: %c/%d", i, nick[i], nick[i] );
+ irc_usermsg( acc->irc, "Char %d: %c/%d", i, nick[i], nick[i] );
- irc_usermsg( irc, "FAILED. Returning an insane nick now. Things might break. "
- "Good luck, and please don't forget to paste the lines up here "
- "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
+ irc_usermsg( acc->irc, "FAILED. Returning an insane nick now. Things might break. "
+ "Good luck, and please don't forget to paste the lines up here "
+ "in #bitlbee on OFTC or in a mail to wilmer@gaast.net" );
g_snprintf( nick, MAX_NICK_LENGTH + 1, "xx%x", rand() );
@@ -125,30 +126,12 @@ char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *
}
}
- return( nick );
+ return nick;
}
-void nick_del( irc_t *irc, const char *nick )
+void nick_del( account_t *acc, const char *handle )
{
- nick_t *l = NULL, *n = irc->nicks;
-
- while( n )
- {
- if( g_strcasecmp( n->nick, nick ) == 0 )
- {
- if( l )
- l->next = n->next;
- else
- irc->nicks = n->next;
-
- g_free( n->handle );
- g_free( n->nick );
- g_free( n );
-
- break;
- }
- n = (l=n)->next;
- }
+ g_hash_table_remove( acc->nicks, handle );
}
diff --git a/nick.h b/nick.h
index 9ab1ef1e..5274cb13 100644
--- a/nick.h
+++ b/nick.h
@@ -23,17 +23,9 @@
Suite 330, Boston, MA 02111-1307 USA
*/
-typedef struct __NICK
-{
- char *handle;
- struct prpl *proto;
- char *nick;
- struct __NICK *next;
-} nick_t;
-
-void nick_set( irc_t *irc, const char *handle, struct prpl *proto, const char *nick );
-char *nick_get( irc_t *irc, const char *handle, struct prpl *proto, const char *realname );
-void nick_del( irc_t *irc, const char *nick );
+void nick_set( account_t *acc, const char *handle, const char *nick );
+char *nick_get( account_t *acc, const char *handle, const char *realname );
+void nick_del( account_t *acc, const char *handle );
void nick_strip( char *nick );
int nick_ok( const char *nick );
diff --git a/protocols/jabber/jabber.c b/protocols/jabber/jabber.c
index e7f4534e..7147a78c 100644
--- a/protocols/jabber/jabber.c
+++ b/protocols/jabber/jabber.c
@@ -2379,7 +2379,7 @@ void jabber_init()
ret->keepalive = jabber_keepalive;
ret->alias_buddy = jabber_roster_update;
ret->group_buddy = jabber_group_change;
- ret->cmp_buddynames = g_strcasecmp;
+ ret->handle_cmp = g_strcasecmp;
register_protocol (ret);
}
diff --git a/protocols/msn/msn.c b/protocols/msn/msn.c
index 790b372a..db4563dc 100644
--- a/protocols/msn/msn.c
+++ b/protocols/msn/msn.c
@@ -431,7 +431,7 @@ void msn_init()
ret->add_deny = msn_add_deny;
ret->rem_deny = msn_rem_deny;
ret->send_typing = msn_send_typing;
- ret->cmp_buddynames = g_strcasecmp;
+ ret->handle_cmp = g_strcasecmp;
register_protocol(ret);
}
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 8346f5fa..54965b84 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -365,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->acc->prpl, realname ) );
+ strcpy( nick, nick_get( gc->acc, handle, realname ) );
u = user_add( gc->irc, nick );
@@ -377,7 +377,7 @@ 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->acc->server )
+ else if( gc->acc->server )
{
char *colon;
@@ -777,7 +777,7 @@ void add_chat_buddy( struct conversation *b, char *handle )
serv_got_crap( b->gc, "User %s added to conversation %d", handle, b->id );
/* It might be yourself! */
- if( b->gc->acc->prpl->cmp_buddynames( handle, b->gc->username ) == 0 )
+ if( b->gc->acc->prpl->handle_cmp( handle, b->gc->username ) == 0 )
{
u = user_find( b->gc->irc, b->gc->irc->nick );
if( !b->joined )
@@ -1061,7 +1061,7 @@ 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->acc->prpl->cmp_buddynames ) == NULL )
+ if( g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL )
{
gc->permit = g_slist_prepend( gc->permit, g_strdup( handle ) );
}
@@ -1073,7 +1073,7 @@ void bim_rem_allow( struct gaim_connection *gc, char *handle )
{
GSList *l;
- if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) )
+ if( ( l = g_slist_find_custom( gc->permit, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) )
{
g_free( l->data );
gc->permit = g_slist_delete_link( gc->permit, l );
@@ -1084,7 +1084,7 @@ void bim_rem_allow( struct gaim_connection *gc, char *handle )
void bim_add_block( struct gaim_connection *gc, char *handle )
{
- if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) == NULL )
+ if( g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) == NULL )
{
gc->deny = g_slist_prepend( gc->deny, g_strdup( handle ) );
}
@@ -1096,7 +1096,7 @@ void bim_rem_block( struct gaim_connection *gc, char *handle )
{
GSList *l;
- if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->cmp_buddynames ) ) )
+ if( ( l = g_slist_find_custom( gc->deny, handle, (GCompareFunc) gc->acc->prpl->handle_cmp ) ) )
{
g_free( l->data );
gc->deny = g_slist_delete_link( gc->deny, l );
diff --git a/protocols/nogaim.h b/protocols/nogaim.h
index c0a867d6..bae4489f 100644
--- a/protocols/nogaim.h
+++ b/protocols/nogaim.h
@@ -164,7 +164,7 @@ struct prpl {
GList *(* away_states)(struct gaim_connection *gc);
/* Mainly for AOL, since they think "Bung hole" == "Bu ngho le". *sigh* */
- int (* cmp_buddynames) (const char *who1, const char *who2);
+ int (* handle_cmp) (const char *who1, const char *who2);
};
#define UC_UNAVAILABLE 1
diff --git a/protocols/oscar/oscar.c b/protocols/oscar/oscar.c
index 28239812..f65332dc 100644
--- a/protocols/oscar/oscar.c
+++ b/protocols/oscar/oscar.c
@@ -2680,9 +2680,10 @@ void oscar_init()
ret->rem_deny = oscar_rem_deny;
ret->set_permit_deny = oscar_set_permit_deny;
ret->keepalive = oscar_keepalive;
- ret->cmp_buddynames = aim_sncmp;
ret->get_status_string = oscar_get_status_string;
ret->send_typing = oscar_send_typing;
+
+ ret->handle_cmp = aim_sncmp;
register_protocol(ret);
}
diff --git a/protocols/yahoo/yahoo.c b/protocols/yahoo/yahoo.c
index c21779ba..23c6f813 100644
--- a/protocols/yahoo/yahoo.c
+++ b/protocols/yahoo/yahoo.c
@@ -408,7 +408,8 @@ void byahoo_init( )
ret->chat_invite = byahoo_chat_invite;
ret->chat_leave = byahoo_chat_leave;
ret->chat_open = byahoo_chat_open;
- ret->cmp_buddynames = g_strcasecmp;
+
+ ret->handle_cmp = g_strcasecmp;
register_protocol(ret);
}
diff --git a/root_commands.c b/root_commands.c
index 42e113ed..2cf67134 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -465,7 +465,7 @@ static void cmd_add( irc_t *irc, char **cmd )
}
else
{
- nick_set( irc, cmd[2], a->gc->acc->prpl, cmd[3] );
+ nick_set( a, cmd[2], cmd[3] );
}
}
@@ -547,7 +547,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->acc->prpl, cmd[2] );
+ nick_set( u->gc->acc, u->handle, cmd[2] );
}
irc_usermsg( irc, "Nick successfully changed" );
@@ -568,7 +568,7 @@ static void cmd_remove( irc_t *irc, char **cmd )
u->gc->acc->prpl->remove_buddy( u->gc, u->handle, NULL );
user_del( irc, cmd[1] );
- nick_del( irc, cmd[1] );
+ nick_del( u->gc->acc, u->handle );
irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
g_free( s );
@@ -880,58 +880,6 @@ static void cmd_qlist( irc_t *irc, char **cmd )
irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
}
-static void cmd_import_buddies( irc_t *irc, char **cmd )
-{
- struct gaim_connection *gc;
- account_t *a;
- nick_t *n;
-
- if( !( a = account_get( irc, cmd[1] ) ) )
- {
- irc_usermsg( irc, "Invalid account" );
- return;
- }
- else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) )
- {
- irc_usermsg( irc, "That account is not on-line" );
- return;
- }
-
- if( cmd[2] )
- {
- if( g_strcasecmp( cmd[2], "clear" ) == 0 )
- {
- 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->acc->prpl->remove_buddy( u->gc, u->handle, NULL );
- user_del( irc, u->nick );
- }
-
- irc_usermsg( irc, "Old buddy list cleared." );
- }
- else
- {
- irc_usermsg( irc, "Invalid argument: %s", cmd[2] );
- return;
- }
- }
-
- for( n = gc->irc->nicks; n; n = n->next )
- {
- if( n->proto == gc->acc->prpl && !user_findhandle( gc, n->handle ) )
- {
- gc->acc->prpl->add_buddy( gc, n->handle );
- add_buddy( gc, NULL, n->handle, NULL );
- }
- }
-
- irc_usermsg( irc, "Sent all add requests. Please wait for a while, the server needs some time to handle all the adds." );
-}
-
const command_t commands[] = {
{ "help", 0, cmd_help, 0 },
{ "identify", 1, cmd_identify, 0 },
@@ -950,7 +898,6 @@ const command_t commands[] = {
{ "no", 0, cmd_yesno, 0 },
{ "blist", 0, cmd_blist, 0 },
{ "nick", 1, cmd_nick, 0 },
- { "import_buddies", 1, cmd_import_buddies, 0 },
{ "qlist", 0, cmd_qlist, 0 },
{ NULL }
};
diff --git a/storage_text.c b/storage_text.c
index 06d278aa..ac197685 100644
--- a/storage_text.c
+++ b/storage_text.c
@@ -112,186 +112,13 @@ static storage_status_t text_load ( const char *my_nick, const char* password, i
continue;
http_decode( s );
- nick_set( irc, s, prpl, nick );
+ // FIXME!!!! nick_set( irc, s, prpl, nick );
}
fclose( fp );
return STORAGE_OK;
}
-static storage_status_t text_save( irc_t *irc, int overwrite )
-{
- char s[512];
- char path[512], new_path[512];
- char *line;
- nick_t *n;
- set_t *set;
- mode_t ou = umask( 0077 );
- account_t *a;
- FILE *fp;
- char *hash;
-
- if (!overwrite) {
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- if (access( path, F_OK ) != -1)
- return STORAGE_ALREADY_EXISTS;
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
- if (access( path, F_OK ) != -1)
- return STORAGE_ALREADY_EXISTS;
- }
-
- /*\
- * [SH] Nothing should be saved if no password is set, because the
- * password is not set if it was wrong, or if one is not identified
- * yet. This means that a malicious user could easily overwrite
- * files owned by someone else:
- * a Bad Thing, methinks
- \*/
-
- /* [WVG] No? Really? */
-
- /*\
- * [SH] Okay, okay, it wasn't really Wilmer who said that, it was
- * me. I just thought it was funny.
- \*/
-
- hash = hashpass( irc->password );
- if( hash == NULL )
- {
- irc_usermsg( irc, "Please register yourself if you want to save your settings." );
- return STORAGE_OTHER_ERROR;
- }
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".nicks~" );
- fp = fopen( path, "w" );
- if( !fp ) return STORAGE_OTHER_ERROR;
- for( n = irc->nicks; n; n = n->next )
- {
- strcpy( s, n->handle );
- s[169] = 0; /* Prevent any overflow (169 ~ 512 / 3) */
- http_encode( s );
- g_snprintf( s + strlen( s ), 510 - strlen( s ), " %d %s", find_protocol_id(n->proto->name), n->nick );
- if( fprintf( fp, "%s\n", s ) != strlen( s ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return STORAGE_OTHER_ERROR;
- }
- }
- if( fclose( fp ) != 0 )
- {
- irc_usermsg( irc, "fclose() reported an error. Disk full?" );
- return STORAGE_OTHER_ERROR;
- }
-
- g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".nicks" );
- if( unlink( new_path ) != 0 )
- {
- if( errno != ENOENT )
- {
- irc_usermsg( irc, "Error while removing old .nicks file" );
- return STORAGE_OTHER_ERROR;
- }
- }
- if( rename( path, new_path ) != 0 )
- {
- irc_usermsg( irc, "Error while renaming new .nicks file" );
- return STORAGE_OTHER_ERROR;
- }
-
- g_snprintf( path, 511, "%s%s%s", global.conf->configdir, irc->nick, ".accounts~" );
- fp = fopen( path, "w" );
- if( !fp ) return STORAGE_OTHER_ERROR;
- if( fprintf( fp, "%s", hash ) != strlen( hash ) )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return STORAGE_OTHER_ERROR;
- }
- g_free( hash );
-
- for( a = irc->accounts; a; a = a->next )
- {
- if( !strcmp(a->prpl->name, "oscar") )
- g_snprintf( s, sizeof( s ), "account add oscar \"%s\" \"%s\" %s", a->user, a->pass, a->server );
- else
- g_snprintf( s, sizeof( s ), "account add %s \"%s\" \"%s\" \"%s\"",
- a->prpl->name, a->user, a->pass, a->server ? a->server : "" );
-
- line = obfucrypt( s, irc->password );
- if( *line )
- {
- if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return STORAGE_OTHER_ERROR;
- }
- }
- g_free( line );
- }
-
- for( set = irc->set; set; set = set->next )
- {
- if( set->value && set->def )
- {
- g_snprintf( s, sizeof( s ), "set %s \"%s\"", set->key, set->value );
- line = obfucrypt( s, irc->password );
- if( *line )
- {
- if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return STORAGE_OTHER_ERROR;
- }
- }
- g_free( line );
- }
- }
-
- if( strcmp( irc->mynick, ROOT_NICK ) != 0 )
- {
- g_snprintf( s, sizeof( s ), "rename %s %s", ROOT_NICK, irc->mynick );
- line = obfucrypt( s, irc->password );
- if( *line )
- {
- if( fprintf( fp, "%s\n", line ) != strlen( line ) + 1 )
- {
- irc_usermsg( irc, "fprintf() wrote too little. Disk full?" );
- fclose( fp );
- return STORAGE_OTHER_ERROR;
- }
- }
- g_free( line );
- }
- if( fclose( fp ) != 0 )
- {
- irc_usermsg( irc, "fclose() reported an error. Disk full?" );
- return STORAGE_OTHER_ERROR;
- }
-
- g_snprintf( new_path, 512, "%s%s%s", global.conf->configdir, irc->nick, ".accounts" );
- if( unlink( new_path ) != 0 )
- {
- if( errno != ENOENT )
- {
- irc_usermsg( irc, "Error while removing old .accounts file" );
- return STORAGE_OTHER_ERROR;
- }
- }
- if( rename( path, new_path ) != 0 )
- {
- irc_usermsg( irc, "Error while renaming new .accounts file" );
- return STORAGE_OTHER_ERROR;
- }
-
- umask( ou );
-
- return STORAGE_OK;
-}
-
static storage_status_t text_check_pass( const char *nick, const char *password )
{
char s[512];
@@ -336,6 +163,5 @@ storage_t storage_text = {
.init = text_init,
.check_pass = text_check_pass,
.remove = text_remove,
- .load = text_load,
- .save = text_save
+ .load = text_load
};
diff --git a/storage_xml.c b/storage_xml.c
index 701d5144..b01f35d6 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -196,7 +196,7 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na
if( xd->current_account && handle && nick )
{
- nick_set( irc, handle, xd->current_account->prpl, nick );
+ nick_set( xd->current_account, handle, nick );
}
else
{
@@ -364,11 +364,12 @@ static int xml_printf( int fd, int indent, char *fmt, ... )
return len == 0;
}
+static gboolean xml_save_nick( gpointer key, gpointer value, gpointer data );
+
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];
@@ -439,10 +440,15 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
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;
+ /* 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
+ 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, (gpointer) fd ) )
+ goto write_error;
if( !xml_printf( fd, 1, "</account>\n" ) )
goto write_error;
@@ -477,6 +483,11 @@ write_error:
return STORAGE_OTHER_ERROR;
}
+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 )
{
char s[512];
diff --git a/user.c b/user.c
index cb70ab68..0892a23c 100644
--- a/user.c
+++ b/user.c
@@ -142,16 +142,22 @@ user_t *user_find( irc_t *irc, char *nick )
user_t *user_findhandle( struct gaim_connection *gc, char *handle )
{
- user_t *u = gc->irc->users;
-
- while( u )
- {
- if( u->gc == gc && u->handle && gc->acc->prpl->cmp_buddynames ( u->handle, handle ) == 0 )
- break;
- u = u->next;
- }
-
- return( u );
+ user_t *u;
+ char *nick;
+
+ /* First, let's try a hash lookup. If it works, it's probably faster. */
+ if( ( nick = g_hash_table_lookup( gc->acc->nicks, handle ) ) &&
+ ( u = user_find( gc->irc, nick ) ) &&
+ ( gc->acc->prpl->handle_cmp( handle, u->handle ) == 0 ) )
+ return u;
+
+ /* However, it doesn't always work, so in that case we'll have to dig
+ through the whole userlist. :-( */
+ for( u = gc->irc->users; u; u = u->next )
+ if( u->gc == gc && u->handle && gc->acc->prpl->handle_cmp( u->handle, handle ) == 0 )
+ return u;
+
+ return NULL;
}
void user_rename( irc_t *irc, char *oldnick, char *newnick )