Index: irc.c
===================================================================
--- irc.c	(revision 1195cecc99315c9c38e05c8dd0981792e7663583)
+++ irc.c	(revision c84e31ae1e972a327b103ada52cae6a2e2335767)
@@ -42,33 +42,4 @@
 }
 
-static char *set_eval_charset( set_t *set, char *value )
-{
-	irc_t *irc = set->data;
-	GIConv ic, oc;
-
-	if( g_strcasecmp( value, "none" ) == 0 )
-		value = g_strdup( "utf-8" );
-
-	if( ( ic = g_iconv_open( "utf-8", value ) ) == (GIConv) -1 )
-	{
-		return NULL;
-	}
-	if( ( oc = g_iconv_open( value, "utf-8" ) ) == (GIConv) -1 )
-	{
-		g_iconv_close( ic );
-		return NULL;
-	}
-	
-	if( irc->iconv != (GIConv) -1 )
-		g_iconv_close( irc->iconv );
-	if( irc->oconv != (GIConv) -1 )
-		g_iconv_close( irc->oconv );
-	
-	irc->iconv = ic;
-	irc->oconv = oc;
-
-	return value;
-}
-
 irc_t *irc_new( int fd )
 {
@@ -93,7 +64,4 @@
 	irc->mynick = g_strdup( ROOT_NICK );
 	irc->channel = g_strdup( ROOT_CHAN );
-	
-	irc->iconv = (GIConv) -1;
-	irc->oconv = (GIConv) -1;
 	
 	if( global.conf->hostname )
@@ -151,5 +119,4 @@
 	set_add( &irc->set, "private", "true", set_eval_bool, irc );
 	set_add( &irc->set, "query_order", "lifo", NULL, irc );
-	set_add( &irc->set, "root_nick", irc->mynick, set_eval_root_nick, irc );
 	set_add( &irc->set, "save_on_quit", "true", set_eval_bool, irc );
 	set_add( &irc->set, "simulate_netsplit", "true", set_eval_bool, irc );
@@ -160,7 +127,4 @@
 	conf_loaddefaults( irc );
 	
-	/* Evaluator sets the iconv/oconv structures. */
-	set_eval_charset( set_find( &irc->set, "charset" ), set_getstr( &irc->set, "charset" ) );
-	
 	return( irc );
 }
@@ -200,12 +164,10 @@
 	if( irc->sendbuffer && !immed )
 	{
-		/* Set up a timeout event that should shut down the connection
-		   in a second, just in case ..._write doesn't do it first. */
+		/* We won't read from this socket anymore. Instead, we'll connect a timer
+		   to it that should shut down the connection in a second, just in case
+		   bitlbee_.._write doesn't do it first. */
 		
 		b_event_remove( irc->r_watch_source_id );
-		irc->r_watch_source_id = 0;
-		
-		b_event_remove( irc->ping_source_id );
-		irc->ping_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
+		irc->r_watch_source_id = b_timeout_add( 1000, (b_event_handler) irc_free, irc );
 	}
 	else
@@ -223,6 +185,7 @@
 
 /* Because we have no garbage collection, this is quite annoying */
-void irc_free( irc_t * irc )
-{
+void irc_free(irc_t * irc)
+{
+	account_t *account;
 	user_t *user, *usertmp;
 	
@@ -233,84 +196,74 @@
 			irc_usermsg( irc, "Error while saving settings!" );
 	
+	closesocket( irc->fd );
+	
+	if( irc->ping_source_id > 0 )
+		b_event_remove( irc->ping_source_id );
+	b_event_remove( irc->r_watch_source_id );
+	if( irc->w_watch_source_id > 0 )
+		b_event_remove( irc->w_watch_source_id );
+	
 	irc_connection_list = g_slist_remove( irc_connection_list, irc );
 	
-	while( irc->accounts )
-	{
-		if( irc->accounts->ic )
-			imc_logout( irc->accounts->ic, FALSE );
-		else if( irc->accounts->reconnect )
-			cancel_auto_reconnect( irc->accounts );
-		
-		if( irc->accounts->ic == NULL )
-			account_del( irc, irc->accounts );
+	for (account = irc->accounts; account; account = account->next) {
+		if (account->ic) {
+			imc_logout(account->ic, TRUE);
+		} else if (account->reconnect) {
+			cancel_auto_reconnect(account);
+		}
+	}
+	
+	g_free(irc->sendbuffer);
+	g_free(irc->readbuffer);
+	
+	g_free(irc->nick);
+	g_free(irc->user);
+	g_free(irc->host);
+	g_free(irc->realname);
+	g_free(irc->password);
+	
+	g_free(irc->myhost);
+	g_free(irc->mynick);
+	
+	g_free(irc->channel);
+	
+	while (irc->queries != NULL)
+		query_del(irc, irc->queries);
+	
+	while (irc->accounts)
+		if (irc->accounts->ic == NULL)
+			account_del(irc, irc->accounts);
 		else
 			/* Nasty hack, but account_del() doesn't work in this
 			   case and we don't want infinite loops, do we? ;-) */
 			irc->accounts = irc->accounts->next;
-	}
-	
-	while( irc->queries != NULL )
-		query_del( irc, irc->queries );
-	
-	while( irc->set )
-		set_del( &irc->set, irc->set->key );
-	
-	if (irc->users != NULL)
-	{
+	
+	while (irc->set)
+		set_del(&irc->set, irc->set->key);
+	
+	if (irc->users != NULL) {
 		user = irc->users;
-		while( user != NULL )
-		{
-			g_free( user->nick );
-			g_free( user->away );
-			g_free( user->handle );
-			if( user->user != user->nick ) g_free( user->user );
-			if( user->host != user->nick ) g_free( user->host );
-			if( user->realname != user->nick ) g_free( user->realname );
-			b_event_remove( user->sendbuf_timer );
+		while (user != NULL) {
+			g_free(user->nick);
+			g_free(user->away);
+			g_free(user->handle);
+			if(user->user!=user->nick) g_free(user->user);
+			if(user->host!=user->nick) g_free(user->host);
+			if(user->realname!=user->nick) g_free(user->realname);
+			b_event_remove(user->sendbuf_timer);
 					
 			usertmp = user;
 			user = user->next;
-			g_free( usertmp );
-		}
-	}
-	
-	if( irc->ping_source_id > 0 )
-		b_event_remove( irc->ping_source_id );
-	if( irc->r_watch_source_id > 0 )
-		b_event_remove( irc->r_watch_source_id );
-	if( irc->w_watch_source_id > 0 )
-		b_event_remove( irc->w_watch_source_id );
-	
-	closesocket( irc->fd );
-	irc->fd = -1;
-	
-	g_hash_table_foreach_remove( irc->userhash, irc_free_hashkey, NULL );
-	g_hash_table_destroy( irc->userhash );
-	
-	g_hash_table_foreach_remove( irc->watches, irc_free_hashkey, NULL );
-	g_hash_table_destroy( irc->watches );
-	
-	if( irc->iconv != (GIConv) -1 )
-		g_iconv_close( irc->iconv );
-	if( irc->oconv != (GIConv) -1 )
-		g_iconv_close( irc->oconv );
-	
-	g_free( irc->sendbuffer );
-	g_free( irc->readbuffer );
-	
-	g_free( irc->nick );
-	g_free( irc->user );
-	g_free( irc->host );
-	g_free( irc->realname );
-	g_free( irc->password );
-	
-	g_free( irc->myhost );
-	g_free( irc->mynick );
-	
-	g_free( irc->channel );
-	
-	g_free( irc->last_target );
-	
-	g_free( irc );
+			g_free(usertmp);
+		}
+	}
+	
+	g_hash_table_foreach_remove(irc->userhash, irc_free_hashkey, NULL);
+	g_hash_table_destroy(irc->userhash);
+	
+	g_hash_table_foreach_remove(irc->watches, irc_free_hashkey, NULL);
+	g_hash_table_destroy(irc->watches);
+	
+	g_free(irc);
 	
 	if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
@@ -333,5 +286,5 @@
 void irc_process( irc_t *irc )
 {
-	char **lines, *temp, **cmd;
+	char **lines, *temp, **cmd, *cs;
 	int i;
 
@@ -342,8 +295,9 @@
 		for( i = 0; *lines[i] != '\0'; i ++ )
 		{
-			char *conv = NULL;
+			char conv[IRC_MAX_LINE+1];
 			
-			/* [WvG] If the last line isn't empty, it's an incomplete line and we
-			   should wait for the rest to come in before processing it. */
+			/* [WvG] Because irc_tokenize splits at every newline, the lines[] list
+			    should end with an empty string. This is why this actually works.
+			    Took me a while to figure out, Maurits. :-P */
 			if( lines[i+1] == NULL )
 			{
@@ -355,12 +309,8 @@
 			}
 			
-			if( irc->iconv != (GIConv) -1 )
+			if( ( cs = set_getstr( &irc->set, "charset" ) ) )
 			{
-				gsize bytes_read, bytes_written;
-				
-				conv = g_convert_with_iconv( lines[i], -1, irc->iconv,
-				                             &bytes_read, &bytes_written, NULL );
-				
-				if( conv == NULL || bytes_read != strlen( lines[i] ) )
+				conv[IRC_MAX_LINE] = 0;
+				if( do_iconv( cs, "UTF-8", lines[i], conv, 0, IRC_MAX_LINE - 2 ) == -1 )
 				{
 					/* GLib can do strange things if things are not in the expected charset,
@@ -374,16 +324,13 @@
 						                  "expect by changing the charset setting. See "
 						                  "`help set charset' for more information. Your "
-						                  "message was ignored.",
-						                  set_getstr( &irc->set, "charset" ) );
-						
-						g_free( conv );
-						conv = NULL;
+						                  "message was ignored.", cs );
+						*conv = 0;
 					}
 					else
 					{
 						irc_write( irc, ":%s NOTICE AUTH :%s", irc->myhost,
-						           "Warning: invalid characters received at login time." );
+						           "Warning: invalid (non-UTF8) characters received at login time." );
 						
-						conv = g_strdup( lines[i] );
+						strncpy( conv, lines[i], IRC_MAX_LINE );
 						for( temp = conv; *temp; temp ++ )
 							if( *temp & 0x80 )
@@ -394,13 +341,9 @@
 			}
 			
-			if( lines[i] )
-			{
-				if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
-					continue;
-				irc_exec( irc, cmd );
-				g_free( cmd );
-			}
+			if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
+				continue;
+			irc_exec( irc, cmd );
 			
-			g_free( conv );
+			g_free( cmd );
 			
 			/* Shouldn't really happen, but just in case... */
@@ -426,39 +369,40 @@
 char **irc_tokenize( char *buffer )
 {
-	int i, j, n = 3;
+	int i, j;
 	char **lines;
 
-	/* Allocate n+1 elements. */
-	lines = g_new( char *, n + 1 );
+	/* Count the number of elements we're gonna need. */
+	for( i = 0, j = 1; buffer[i] != '\0'; i ++ )
+	{
+		if( buffer[i] == '\n' )
+			if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
+				j ++;
+	}
+	
+	/* Allocate j+1 elements. */
+	lines = g_new( char *, j + 1 );
+	
+	/* NULL terminate our list. */ 
+	lines[j] = NULL;
 	
 	lines[0] = buffer;
 	
-	/* Split the buffer in several strings, and accept any kind of line endings,
-	 * knowing that ERC on Windows may send something interesting like \r\r\n,
-	 * and surely there must be clients that think just \n is enough... */
-	for( i = 0, j = 0; buffer[i] != '\0'; i ++ )
-	{
-		if( buffer[i] == '\r' || buffer[i] == '\n' )
-		{
-			while( buffer[i] == '\r' || buffer[i] == '\n' )
-				buffer[i++] = '\0';
+	/* Split the buffer in several strings, using \r\n as our seperator, where \r is optional.
+	 * Although this is not in the RFC, some braindead ircds (newnet's) use this, so some clients might too. 
+	 */
+	for( i = 0, j = 0; buffer[i] != '\0'; i ++)
+	{
+		if( buffer[i] == '\n' )
+		{
+			buffer[i] = '\0';
 			
-			lines[++j] = buffer + i;
-			
-			if( j >= n )
-			{
-				n *= 2;
-				lines = g_renew( char *, lines, n + 1 );
-			}
-
-			if( buffer[i] == '\0' )
-				break;
-		}
-	}
-	
-	/* NULL terminate our list. */ 
-	lines[++j] = NULL;
-	
-	return lines;
+			if( i > 0 && buffer[i-1] == '\r' )
+				buffer[i-1] = '\0';
+			if( buffer[i+1] != '\r' && buffer[i+1] != '\n' )
+				lines[++j] = buffer + i + 1;
+		}
+	}
+	
+	return( lines );
 }
 
@@ -594,4 +538,5 @@
 
 	return;
+
 }
 
@@ -599,5 +544,5 @@
 {
 	int size;
-	char line[IRC_MAX_LINE+1];
+	char line[IRC_MAX_LINE+1], *cs;
 		
 	/* Don't try to write anything new anymore when shutting down. */
@@ -605,22 +550,17 @@
 		return;
 	
-	memset( line, 0, sizeof( line ) );
+	line[IRC_MAX_LINE] = 0;
 	g_vsnprintf( line, IRC_MAX_LINE - 2, format, params );
+	
 	strip_newlines( line );
-	
-	if( irc->oconv != (GIConv) -1 )
-	{
-		gsize bytes_read, bytes_written;
-		char *conv;
-		
-		conv = g_convert_with_iconv( line, -1, irc->oconv,
-		                             &bytes_read, &bytes_written, NULL );
-
-		if( bytes_read == strlen( line ) )
-			strncpy( line, conv, IRC_MAX_LINE - 2 );
-		
-		g_free( conv );
-	}
-	g_strlcat( line, "\r\n", IRC_MAX_LINE + 1 );
+	if( ( cs = set_getstr( &irc->set, "charset" ) ) && ( g_strcasecmp( cs, "utf-8" ) != 0 ) )
+	{
+		char conv[IRC_MAX_LINE+1];
+		
+		conv[IRC_MAX_LINE] = 0;
+		if( do_iconv( "UTF-8", cs, line, conv, 0, IRC_MAX_LINE - 2 ) != -1 )
+			strcpy( line, conv );
+	}
+	strcat( line, "\r\n" );
 	
 	if( irc->sendbuffer != NULL )
@@ -795,10 +735,5 @@
 	irc_spawn( irc, u );
 	
-	irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\n"
-	                  "If you've never used BitlBee before, please do read the help "
-	                  "information using the \x02help\x02 command. Lots of FAQs are "
-	                  "answered there.\n"
-	                  "If you already have an account on this server, just use the "
-	                  "\x02identify\x02 command to identify yourself." );
+	irc_usermsg( irc, "Welcome to the BitlBee gateway!\n\nIf you've never used BitlBee before, please do read the help information using the \x02help\x02 command. Lots of FAQs are answered there." );
 	
 	if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
@@ -806,14 +741,4 @@
 	
 	irc->status |= USTATUS_LOGGED_IN;
-	
-	/* This is for bug #209 (use PASS to identify to NickServ). */
-	if( irc->password != NULL )
-	{
-		char *send_cmd[] = { "identify", g_strdup( irc->password ), NULL };
-		
-		irc_setpass( irc, NULL );
-		root_command( irc, send_cmd );
-		g_free( send_cmd[1] );
-	}
 }
 
