diff options
| author | Wilmer van der Gaast <wilmer@gaast.net> | 2006-07-03 23:22:45 +0200 | 
|---|---|---|
| committer | Wilmer van der Gaast <wilmer@gaast.net> | 2006-07-03 23:22:45 +0200 | 
| commit | 5b52a4895e5a59ff6509f7771f4d8665737688c3 (patch) | |
| tree | 32c13033b127804864507d8ff90c0c274f8b07e5 | |
| parent | 911f2eb7060f6af6fe8e4e02144cfb7c4bb4cc8b (diff) | |
Implemented per-account nick lists instead of per-protocol nick lists.
nick_t is dead, instead nicks are just saves in a per-account_t GLib
hash table. While doing this, the import_buddies command finally died
and text_save() disappeared, because the old file format can't handle
most of the new features in this branch anyway.
Still have to implement support for the new nick lists in text_load()!
| -rw-r--r-- | account.c | 6 | ||||
| -rw-r--r-- | account.h | 1 | ||||
| -rw-r--r-- | bitlbee.h | 1 | ||||
| -rw-r--r-- | irc.c | 43 | ||||
| -rw-r--r-- | irc.h | 2 | ||||
| -rw-r--r-- | irc_commands.c | 3 | ||||
| -rw-r--r-- | nick.c | 111 | ||||
| -rw-r--r-- | nick.h | 14 | ||||
| -rw-r--r-- | protocols/jabber/jabber.c | 2 | ||||
| -rw-r--r-- | protocols/msn/msn.c | 2 | ||||
| -rw-r--r-- | protocols/nogaim.c | 14 | ||||
| -rw-r--r-- | protocols/nogaim.h | 2 | ||||
| -rw-r--r-- | protocols/oscar/oscar.c | 3 | ||||
| -rw-r--r-- | protocols/yahoo/yahoo.c | 3 | ||||
| -rw-r--r-- | root_commands.c | 59 | ||||
| -rw-r--r-- | storage_text.c | 178 | ||||
| -rw-r--r-- | storage_xml.c | 23 | ||||
| -rw-r--r-- | user.c | 26 | 
18 files changed, 118 insertions, 375 deletions
@@ -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 ); @@ -37,6 +37,7 @@ typedef struct account  	int reconnect;  	set_t *set; +	GHashTable *nicks;  	struct irc *irc;  	struct gaim_connection *gc; @@ -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" @@ -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 ) @@ -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 ); @@ -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 );  } @@ -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]; @@ -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 )  | 
