Index: Makefile
===================================================================
--- Makefile	(revision a323a22773714a19254db34156500a67e5916451)
+++ Makefile	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -10,5 +10,5 @@
 
 # Program variables
-objects = account.o bitlbee.o commands.o conf.o crypting.o help.o ini.o irc.o log.o nick.o query.o set.o storage.o storage_text.o unix.o url.o user.o
+objects = account.o bitlbee.o conf.o crypting.o help.o ini.o ipc.o irc.o irc_commands.o log.o nick.o query.o root_commands.o set.o storage.o storage_text.o unix.o url.o user.o util.o
 subdirs = protocols
 
Index: bitlbee.c
===================================================================
--- bitlbee.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ bitlbee.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -29,33 +29,26 @@
 #include "protocols/nogaim.h"
 #include "help.h"
+#include "ipc.h"
 #include <signal.h>
 #include <stdio.h>
 #include <errno.h>
 
-gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data )
-{
-	size_t size = sizeof( struct sockaddr_in );
-	struct sockaddr_in conn_info;
-	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, 
-		                     &size );
-	
-	log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
-	irc_new( new_socket );
-
-	return TRUE;
-}
- 
-
+gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data );
 
 int bitlbee_daemon_init()
 {
+#ifdef IPV6
+	struct sockaddr_in6 listen_addr;
+#else
 	struct sockaddr_in listen_addr;
+#endif
 	int i;
 	GIOChannel *ch;
+	FILE *fp;
 	
 	log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );
 	log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG );
 	
-	global.listen_socket = socket( AF_INET, SOCK_STREAM, 0 );
+	global.listen_socket = socket( AF_INETx, SOCK_STREAM, 0 );
 	if( global.listen_socket == -1 )
 	{
@@ -63,9 +56,26 @@
 		return( -1 );
 	}
-	listen_addr.sin_family = AF_INET;
+	
+	/* TIME_WAIT (?) sucks.. */
+	i = 1;
+	setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) );
+	
+#ifdef IPV6
+	listen_addr.sin6_family = AF_INETx;
+	listen_addr.sin6_port = htons( global.conf->port );
+	i = inet_pton( AF_INETx, ipv6_wrap( global.conf->iface ), &listen_addr.sin6_addr );
+#else
+	listen_addr.sin_family = AF_INETx;
 	listen_addr.sin_port = htons( global.conf->port );
-	listen_addr.sin_addr.s_addr = inet_addr( global.conf->iface );
-
-	i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( struct sockaddr ) );
+	i = inet_pton( AF_INETx, global.conf->iface, &listen_addr.sin_addr );
+#endif
+	
+	if( i != 1 )
+	{
+		log_message( LOGLVL_ERROR, "Couldn't parse address `%s'", global.conf->iface );
+		return( -1 );
+	}
+	
+	i = bind( global.listen_socket, (struct sockaddr *) &listen_addr, sizeof( listen_addr ) );
 	if( i == -1 )
 	{
@@ -73,5 +83,5 @@
 		return( -1 );
 	}
-
+	
 	i = listen( global.listen_socket, 10 );
 	if( i == -1 )
@@ -80,8 +90,8 @@
 		return( -1 );
 	}
-
+	
 	ch = g_io_channel_unix_new( global.listen_socket );
-	g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL );
-
+	global.listen_watch_source_id = g_io_add_watch( ch, G_IO_IN, bitlbee_io_new_client, NULL );
+	
 #ifndef _WIN32
 	if( !global.conf->nofork )
@@ -95,10 +105,27 @@
 		else if( i != 0 ) 
 			exit( 0 );
-		close( 0 );
-		close( 1 );
-		close( 2 );
+		
 		chdir( "/" );
+		
+		/* Sometimes std* are already closed (for example when we're in a RESTARTed
+		   BitlBee process. So let's only close TTY-fds. */
+		if( isatty( 0 ) ) close( 0 );
+		if( isatty( 0 ) ) close( 1 );
+		if( isatty( 0 ) ) close( 2 );
 	}
 #endif
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		ipc_master_load_state();
+	
+	if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
+	{
+		fprintf( fp, "%d\n", (int) getpid() );
+		fclose( fp );
+	}
+	else
+	{
+		log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile );
+	}
 	
 	return( 0 );
@@ -124,5 +151,5 @@
 	if( condition & G_IO_ERR || condition & G_IO_HUP )
 	{
-		irc_free( irc );
+		irc_abort( irc, 1, "Read error" );
 		return FALSE;
 	}
@@ -131,5 +158,5 @@
 	if( st == 0 )
 	{
-		irc_free( irc );
+		irc_abort( irc, 1, "Connection reset by peer" );
 		return FALSE;
 	}
@@ -142,5 +169,5 @@
 		else
 		{
-			irc_free( irc );
+			irc_abort( irc, 1, "Read error: %s", strerror( errno ) );
 			return FALSE;
 		}
@@ -158,8 +185,10 @@
 	}
 	
-	if( !irc_process( irc ) )
-	{
-		log_message( LOGLVL_INFO, "Destroying connection with fd %d.", irc->fd );
-		irc_free( irc );
+	irc_process( irc );
+	
+	/* Normally, irc_process() shouldn't call irc_free() but irc_abort(). Just in case: */
+	if( !g_slist_find( irc_connection_list, irc ) )
+	{
+		log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", irc->fd );
 		return FALSE;
 	} 
@@ -168,6 +197,5 @@
 	if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) )
 	{
-		log_message( LOGLVL_ERROR, "Maximum line length exceeded." );
-		irc_free( irc );
+		irc_abort( irc, 0, "Maximum line length exceeded" );
 		return FALSE;
 	}
@@ -181,47 +209,20 @@
 	int st, size;
 	char *temp;
-#ifdef FLOOD_SEND
-	time_t newtime;
-#endif
-
-#ifdef FLOOD_SEND	
-	newtime = time( NULL );
-	if( ( newtime - irc->oldtime ) > FLOOD_SEND_INTERVAL )
-	{
-		irc->sentbytes = 0;
-		irc->oldtime = newtime;
-	}
-#endif
-	
+
 	if( irc->sendbuffer == NULL )
 		return( FALSE );
 	
 	size = strlen( irc->sendbuffer );
-	
-#ifdef FLOOD_SEND
-	if( ( FLOOD_SEND_BYTES - irc->sentbytes ) > size )
-		st = write( irc->fd, irc->sendbuffer, size );
-	else
-		st = write( irc->fd, irc->sendbuffer, ( FLOOD_SEND_BYTES - irc->sentbytes ) );
-#else
 	st = write( irc->fd, irc->sendbuffer, size );
-#endif
-	
-	if( st <= 0 )
-	{
-		if( sockerr_again() )
-		{
-			return TRUE;
-		}
-		else
-		{
-			irc_free( irc );
-			return FALSE;
-		}
-	}
-	
-#ifdef FLOOD_SEND
-	irc->sentbytes += st;
-#endif		
+	
+	if( st == 0 || ( st < 0 && !sockerr_again() ) )
+	{
+		irc_abort( irc, 1, "Write error: %s", strerror( errno ) );
+		return FALSE;
+	}
+	else if( st < 0 ) /* && sockerr_again() */
+	{
+		return TRUE;
+	}
 	
 	if( st == size )
@@ -229,6 +230,9 @@
 		g_free( irc->sendbuffer );
 		irc->sendbuffer = NULL;
-		
 		irc->w_watch_source_id = 0;
+		
+		if( irc->status == USTATUS_SHUTDOWN )
+			irc_free( irc );
+		
 		return( FALSE );
 	}
@@ -243,4 +247,77 @@
 }
 
+gboolean bitlbee_io_new_client( GIOChannel *source, GIOCondition condition, gpointer data )
+{
+	size_t size = sizeof( struct sockaddr_in );
+	struct sockaddr_in conn_info;
+	int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
+	pid_t client_pid = 0;
+	
+	if( new_socket == -1 )
+	{
+		log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) );
+		return TRUE;
+	}
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		int fds[2];
+		
+		if( socketpair( AF_UNIX, SOCK_STREAM, 0, fds ) == -1 )
+		{
+			log_message( LOGLVL_WARNING, "Could not create IPC socket for client: %s", strerror( errno ) );
+			fds[0] = fds[1] = -1;
+		}
+		
+		sock_make_nonblocking( fds[0] );
+		sock_make_nonblocking( fds[1] );
+		
+		client_pid = fork();
+		
+		if( client_pid > 0 && fds[0] != -1 )
+		{
+			struct bitlbee_child *child;
+			
+			child = g_new0( struct bitlbee_child, 1 );
+			child->pid = client_pid;
+			child->ipc_fd = fds[0];
+			child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
+			child_list = g_slist_append( child_list, child );
+			
+			log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", client_pid );
+			
+			/* Close some things we don't need in the parent process. */
+			close( new_socket );
+			close( fds[1] );
+		}
+		else if( client_pid == 0 )
+		{
+			irc_t *irc;
+			
+			/* Close the listening socket, we're a client. */
+			close( global.listen_socket );
+			g_source_remove( global.listen_watch_source_id );
+			
+			/* Make the connection. */
+			irc = irc_new( new_socket );
+			
+			/* We can store the IPC fd there now. */
+			global.listen_socket = fds[1];
+			global.listen_watch_source_id = gaim_input_add( fds[1], GAIM_INPUT_READ, ipc_child_read, irc );
+			
+			close( fds[0] );
+			
+			ipc_master_free_all();
+		}
+	}
+	else
+	{
+		log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
+		irc_new( new_socket );
+	}
+	
+	return TRUE;
+}
+
 void bitlbee_shutdown( gpointer data )
 {
@@ -252,133 +329,2 @@
 	g_main_quit( global.loop );
 }
-
-int root_command_string( irc_t *irc, user_t *u, char *command, int flags )
-{
-	char *cmd[IRC_MAX_ARGS];
-	char *s;
-	int k;
-	char q = 0;
-	
-	memset( cmd, 0, sizeof( cmd ) );
-	cmd[0] = command;
-	k = 1;
-	for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ )
-		if( *s == ' ' && !q )
-		{
-			*s = 0;
-			while( *++s == ' ' );
-			if( *s == '"' || *s == '\'' )
-			{
-				q = *s;
-				s ++;
-			}
-			if( *s )
-			{
-				cmd[k++] = s;
-				s --;
-			}
-		}
-		else if( *s == q )
-		{
-			q = *s = 0;
-		}
-	cmd[k] = NULL;
-	
-	return( root_command( irc, cmd ) );
-}
-
-int root_command( irc_t *irc, char *cmd[] )
-{	
-	int i;
-	
-	if( !cmd[0] )
-		return( 0 );
-	
-	for( i = 0; commands[i].command; i++ )
-		if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
-		{
-			if( !cmd[commands[i].required_parameters] )
-			{
-				irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters );
-				return( 0 );
-			}
-			commands[i].execute( irc, cmd );
-			return( 1 );
-		}
-	
-	irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] );
-	
-	return( 1 );
-}
-
-/* Decode%20a%20file%20name						*/
-void http_decode( char *s )
-{
-	char *t;
-	int i, j, k;
-	
-	t = g_new( char, strlen( s ) + 1 );
-	
-	for( i = j = 0; s[i]; i ++, j ++ )
-	{
-		if( s[i] == '%' )
-		{
-			if( sscanf( s + i + 1, "%2x", &k ) )
-			{
-				t[j] = k;
-				i += 2;
-			}
-			else
-			{
-				*t = 0;
-				break;
-			}
-		}
-		else
-		{
-			t[j] = s[i];
-		}
-	}
-	t[j] = 0;
-	
-	strcpy( s, t );
-	g_free( t );
-}
-
-/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */
-/* This fuction is safe, but make sure you call it safely as well! */
-void http_encode( char *s )
-{
-	char *t;
-	int i, j;
-	
-	t = g_strdup( s );
-	
-	for( i = j = 0; t[i]; i ++, j ++ )
-	{
-		if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' )
-		{
-			sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] );
-			j += 2;
-		}
-		else
-		{
-			s[j] = t[i];
-		}
-	}
-	s[j] = 0;
-	
-	g_free( t );
-}
-
-/* Strip newlines from a string. Modifies the string passed to it. */ 
-char *strip_newlines( char *source )
-{
-	int i;	
-
-	for( i = 0; source[i] != '\0'; i ++ )
-		if( source[i] == '\n' || source[i] == '\r' )
-			source[i] = 32;
-	
-	return source;
-}
Index: bitlbee.conf
===================================================================
--- bitlbee.conf	(revision a323a22773714a19254db34156500a67e5916451)
+++ bitlbee.conf	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -14,4 +14,7 @@
 ##    and other reasons, the use of daemon-mode is *STRONGLY* discouraged,
 ##    don't even *think* of reporting bugs when you use this.
+##  ForkDaemon -- Run as a stand-alone daemon, but keep all clients in separate
+##    child processes. This should be pretty safe and reliable to use instead
+##    of inetd mode.
 ##
 # RunMode = Inetd
@@ -19,6 +22,6 @@
 ## DaemonPort/DaemonInterface:
 ##
-## For RunMode=Daemon, here you can specify on what interface and port the
-## daemon should be listening for connections.
+## For daemon mode, you can specify on what interface and port the daemon
+## should be listening for connections.
 ##
 # DaemonInterface = 0.0.0.0
@@ -42,10 +45,15 @@
 # AuthPassword = ItllBeBitlBee   ## Heh.. Our slogan. ;-)
 
+## OperPassword
+##
+## Password that unlocks access to special operator commands.
+##
+# OperPassword = ChangeMe!
+
 ## HostName
 ##
 ## Normally, BitlBee gets a hostname using getsockname(). If you have a nicer
 ## alias for your BitlBee daemon, you can set it here and BitlBee will identify
-## itself with that name instead. Leave it commented out if you want BitlBee to
-## use getsockname() to get a hostname.
+## itself with that name instead.
 ##
 # HostName = localhost
Index: bitlbee.h
===================================================================
--- bitlbee.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ bitlbee.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -112,6 +112,8 @@
 #include "sock.h"
 
-typedef struct global_t {
+typedef struct global {
+	/* In forked mode, child processes store the fd of the IPC socket here. */
 	int listen_socket;
+	gint listen_watch_source_id;
 	help_t *help;
 	conf_t *conf;
@@ -119,4 +121,5 @@
 	char *helpfile;
 	GMainLoop *loop;
+	int restart;
 } global_t;
 
@@ -127,6 +130,6 @@
 gboolean bitlbee_io_current_client_write( GIOChannel *source, GIOCondition condition, gpointer data );
 
-int root_command_string( irc_t *irc, user_t *u, char *command, int flags );
-int root_command( irc_t *irc, char *command[] );
+void root_command_string( irc_t *irc, user_t *u, char *command, int flags );
+void root_command( irc_t *irc, char *command[] );
 void bitlbee_shutdown( gpointer data );
 double gettime( void );
Index: mmands.c
===================================================================
--- commands.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ 	(revision )
@@ -1,770 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/* User manager (root) commands                                         */
-
-/*
-  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 "commands.h"
-#include "crypting.h"
-#include "bitlbee.h"
-#include "help.h"
-
-#include <string.h>
-
-command_t commands[] = {
-	{ "help",           0, cmd_help }, 
-	{ "identify",       1, cmd_identify },
-	{ "register",       1, cmd_register },
-	{ "drop",           1, cmd_drop },
-	{ "account",        1, cmd_account },
-	{ "add",            2, cmd_add },
-	{ "info",           1, cmd_info },
-	{ "rename",         2, cmd_rename },
-	{ "remove",         1, cmd_remove },
-	{ "block",          1, cmd_block },
-	{ "allow",          1, cmd_allow },
-	{ "save",           0, cmd_save },
-	{ "set",            0, cmd_set },
-	{ "yes",            0, cmd_yesno },
-	{ "no",             0, cmd_yesno },
-	{ "blist",          0, cmd_blist },
-	{ "nick",           1, cmd_nick },
-	{ "import_buddies", 1, cmd_import_buddies },
-	{ "qlist",          0, cmd_qlist },
-	{ NULL }
-};
-
-int cmd_help( irc_t *irc, char **cmd )
-{
-	char param[80];
-	int i;
-	char *s;
-	
-	memset( param, 0, sizeof(param) );
-	for ( i = 1; (cmd[i] != NULL && ( strlen(param) < (sizeof(param)-1) ) ); i++ ) {
-		if ( i != 1 )	// prepend space except for the first parameter
-			strcat(param, " ");
-		strncat( param, cmd[i], sizeof(param) - strlen(param) - 1 );
-	}
-
-	s = help_get( &(global.help), param );
-	if( !s ) s = help_get( &(global.help), "" );
-	
-	if( s )
-	{
-		irc_usermsg( irc, "%s", s );
-		g_free( s );
-		return( 1 );
-	}
-	else
-	{
-		irc_usermsg( irc, "Error opening helpfile." );
-		return( 0 );
-	}
-}
-
-int cmd_identify( irc_t *irc, char **cmd )
-{
-	storage_status_t status = storage_load( irc->nick, cmd[1], irc );
-	
-	switch (status) {
-	case STORAGE_INVALID_PASSWORD:
-		irc_usermsg( irc, "Incorrect password" );
-		break;
-	case STORAGE_NO_SUCH_USER:
-		irc_usermsg( irc, "The nick is (probably) not registered" );
-		break;
-	case STORAGE_OK:
-		irc_usermsg( irc, "Password accepted" );
-		break;
-	default:
-		irc_usermsg( irc, "Something very weird happened" );
-		break;
-	}
-
-	return( 0 );
-}
-
-int cmd_register( irc_t *irc, char **cmd )
-{
-	if( global.conf->authmode == AUTHMODE_REGISTERED )
-	{
-		irc_usermsg( irc, "This server does not allow registering new accounts" );
-		return( 0 );
-	}
-
-	irc_setpass( irc, cmd[1] );
-	switch( storage_save( irc, FALSE )) {
-		case STORAGE_ALREADY_EXISTS:
-			irc_usermsg( irc, "Nick is already registered" );
-			break;
-			
-		case STORAGE_OK:
-			irc->status = USTATUS_IDENTIFIED;
-			break;
-
-		default:
-			irc_usermsg( irc, "Error registering" );
-			break;
-	}
-	
-	return( 0 );
-}
-
-int cmd_drop( irc_t *irc, char **cmd )
-{
-	storage_status_t status;
-	
-	status = storage_remove (irc->nick, cmd[1]);
-	switch (status) {
-	case STORAGE_NO_SUCH_USER:
-		irc_usermsg( irc, "That account does not exist" );
-		return( 0 );
-	case STORAGE_INVALID_PASSWORD:
-		irc_usermsg( irc, "Password invalid" );
-		return( 0 );
-	case STORAGE_OK:
-		irc_setpass( irc, NULL );
-		irc_usermsg( irc, "Account `%s' removed", irc->nick );
-		return( 0 );
-	default:
-		irc_usermsg( irc, "Error: '%d'", status );
-		return( 0 );
-	}
-}
-
-int cmd_account( irc_t *irc, char **cmd )
-{
-	account_t *a;
-	
-	if( global.conf->authmode == AUTHMODE_REGISTERED && irc->status < USTATUS_IDENTIFIED )
-	{
-		irc_usermsg( irc, "This server only accepts registered users" );
-		return( 0 );
-	}
-	
-	if( g_strcasecmp( cmd[1], "add" ) == 0 )
-	{
-		struct prpl *prpl;
-		
-		if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL )
-		{
-			irc_usermsg( irc, "Not enough parameters" );
-			return( 0 );
-		}
-		
-		prpl = find_protocol(cmd[2]);
-		
-		if( prpl == NULL )
-		{
-			irc_usermsg( irc, "Unknown protocol" );
-			return( 0 );
-		}
-
-		a = account_add( irc, prpl, cmd[3], cmd[4] );
-		
-		if( cmd[5] )
-			a->server = g_strdup( cmd[5] );
-		
-		irc_usermsg( irc, "Account successfully added" );
-	}
-	else if( g_strcasecmp( cmd[1], "del" ) == 0 )
-	{
-		if( !cmd[2] )
-		{
-			irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
-		}
-		else if( !( a = account_get( irc, cmd[2] ) ) )
-		{
-			irc_usermsg( irc, "Invalid account" );
-		}
-		else if( a->gc )
-		{
-			irc_usermsg( irc, "Account is still logged in, can't delete" );
-		}
-		else
-		{
-			account_del( irc, a );
-			irc_usermsg( irc, "Account deleted" );
-		}
-	}
-	else if( g_strcasecmp( cmd[1], "list" ) == 0 )
-	{
-		int i = 0;
-		
-		for( a = irc->accounts; a; a = a->next )
-		{
-			char *con;
-			
-			if( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) )
-				con = " (connected)";
-			else if( a->gc )
-				con = " (connecting)";
-			else if( a->reconnect )
-				con = " (awaiting reconnect)";
-			else
-				con = "";
-			
-			irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con );
-			
-			i ++;
-		}
-		irc_usermsg( irc, "End of account list" );
-	}
-	else if( g_strcasecmp( cmd[1], "on" ) == 0 )
-	{
-		if( cmd[2] )
-		{
-			if( ( a = account_get( irc, cmd[2] ) ) )
-			{
-				if( a->gc )
-				{
-					irc_usermsg( irc, "Account already online" );
-					return( 0 );
-				}
-				else
-				{
-					account_on( irc, a );
-				}
-			}
-			else
-			{
-				irc_usermsg( irc, "Invalid account" );
-				return( 0 );
-			}
-		}
-		else
-		{
-			if ( irc->accounts ) {
-				irc_usermsg( irc, "Trying to get all accounts connected..." );
-			
-				for( a = irc->accounts; a; a = a->next )
-					if( !a->gc )
-						account_on( irc, a );
-			} 
-			else
-			{
-				irc_usermsg( irc, "No accounts known. Use 'account add' to add one." );
-			}
-		}
-	}
-	else if( g_strcasecmp( cmd[1], "off" ) == 0 )
-	{
-		if( !cmd[2] )
-		{
-			irc_usermsg( irc, "Deactivating all active (re)connections..." );
-			
-			for( a = irc->accounts; a; a = a->next )
-			{
-				if( a->gc )
-					account_off( irc, a );
-				else if( a->reconnect )
-					cancel_auto_reconnect( a );
-			}
-		}
-		else if( ( a = account_get( irc, cmd[2] ) ) )
-		{
-			if( a->gc )
-			{
-				account_off( irc, a );
-			}
-			else if( a->reconnect )
-			{
-				cancel_auto_reconnect( a );
-				irc_usermsg( irc, "Reconnect cancelled" );
-			}
-			else
-			{
-				irc_usermsg( irc, "Account already offline" );
-				return( 0 );
-			}
-		}
-		else
-		{
-			irc_usermsg( irc, "Invalid account" );
-			return( 0 );
-		}
-	}
-	else
-	{
-		irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] );
-	}
-	
-	return( 1 );
-}
-
-int cmd_add( irc_t *irc, char **cmd )
-{
-	account_t *a;
-	
-	if( !( a = account_get( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Invalid account" );
-		return( 1 );
-	}
-	else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-		return( 1 );
-	}
-	
-	if( cmd[3] )
-	{
-		if( !nick_ok( cmd[3] ) )
-		{
-			irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] );
-			return( 0 );
-		}
-		else if( user_find( irc, cmd[3] ) )
-		{
-			irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
-			return( 0 );
-		}
-		else
-		{
-			nick_set( irc, cmd[2], a->gc->prpl, cmd[3] );
-		}
-	}
-	a->gc->prpl->add_buddy( a->gc, cmd[2] );
-	add_buddy( a->gc, NULL, cmd[2], cmd[2] );
-	
-	irc_usermsg( irc, "User `%s' added to your contact list as `%s'", cmd[2], user_findhandle( a->gc, cmd[2] )->nick );
-	
-	return( 0 );
-}
-
-int cmd_info( irc_t *irc, char **cmd )
-{
-	struct gaim_connection *gc;
-	account_t *a;
-	
-	if( !cmd[2] )
-	{
-		user_t *u = user_find( irc, cmd[1] );
-		if( !u || !u->gc )
-		{
-			irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
-			return( 1 );
-		}
-		gc = u->gc;
-		cmd[2] = u->handle;
-	}
-	else if( !( a = account_get( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Invalid account" );
-		return( 1 );
-	}
-	else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-		return( 1 );
-	}
-	
-	if( !gc->prpl->get_info )
-	{
-		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
-		return( 1 );
-	}
-	gc->prpl->get_info( gc, cmd[2] );
-	
-	return( 0 );
-}
-
-int cmd_rename( irc_t *irc, char **cmd )
-{
-	user_t *u;
-	
-	if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
-	{
-		irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
-		return( 1 );
-	}
-	if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) )
-	{
-		irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
-		return( 1 );
-	}
-	if( !nick_ok( cmd[2] ) )
-	{
-		irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
-		return( 1 );
-	}
-	if( !( u = user_find( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
-		return( 1 );
-	}
-	user_rename( irc, cmd[1], cmd[2] );
-	irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] );
-	if( g_strcasecmp( cmd[1], irc->mynick ) == 0 )
-	{
-		g_free( irc->mynick );
-		irc->mynick = g_strdup( cmd[2] );
-	}
-	else if( u->send_handler == buddy_send_handler )
-	{
-		nick_set( irc, u->handle, u->gc->prpl, cmd[2] );
-	}
-	
-	irc_usermsg( irc, "Nick successfully changed" );
-	
-	return( 0 );
-}
-
-int cmd_remove( irc_t *irc, char **cmd )
-{
-	user_t *u;
-	char *s;
-	
-	if( !( u = user_find( irc, cmd[1] ) ) || !u->gc )
-	{
-		irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
-		return( 1 );
-	}
-	s = g_strdup( u->handle );
-	
-	u->gc->prpl->remove_buddy( u->gc, u->handle, NULL );
-	user_del( irc, cmd[1] );
-	nick_del( irc, cmd[1] );
-	
-	irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
-	g_free( s );
-	
-	return( 0 );
-}
-
-int cmd_block( irc_t *irc, char **cmd )
-{
-	struct gaim_connection *gc;
-	account_t *a;
-	
-	if( !cmd[2] )
-	{
-		user_t *u = user_find( irc, cmd[1] );
-		if( !u || !u->gc )
-		{
-			irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
-			return( 1 );
-		}
-		gc = u->gc;
-		cmd[2] = u->handle;
-	}
-	else if( !( a = account_get( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Invalid account" );
-		return( 1 );
-	}
-	else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-		return( 1 );
-	}
-	
-	if( !gc->prpl->add_deny || !gc->prpl->rem_permit )
-	{
-		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
-	}
-	else
-	{
-		gc->prpl->rem_permit( gc, cmd[2] );
-		gc->prpl->add_deny( gc, cmd[2] );
-		irc_usermsg( irc, "Buddy `%s' moved from your permit- to your deny-list", cmd[2] );
-	}
-	
-	return( 0 );
-}
-
-int cmd_allow( irc_t *irc, char **cmd )
-{
-	struct gaim_connection *gc;
-	account_t *a;
-	
-	if( !cmd[2] )
-	{
-		user_t *u = user_find( irc, cmd[1] );
-		if( !u || !u->gc )
-		{
-			irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
-			return( 1 );
-		}
-		gc = u->gc;
-		cmd[2] = u->handle;
-	}
-	else if( !( a = account_get( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Invalid account" );
-		return( 1 );
-	}
-	else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-		return( 1 );
-	}
-	
-	if( !gc->prpl->rem_deny || !gc->prpl->add_permit )
-	{
-		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
-	}
-	else
-	{
-		gc->prpl->rem_deny( gc, cmd[2] );
-		gc->prpl->add_permit( gc, cmd[2] );
-		
-		irc_usermsg( irc, "Buddy `%s' moved from your deny- to your permit-list", cmd[2] );
-	}
-	
-	return( 0 );
-}
-
-int cmd_yesno( irc_t *irc, char **cmd )
-{
-	query_t *q = NULL;
-	int numq = 0;
-	
-	if( irc->queries == NULL )
-	{
-		irc_usermsg( irc, "Did I ask you something?" );
-		return( 0 );
-	}
-	
-	/* If there's an argument, the user seems to want to answer another question than the
-	   first/last (depending on the query_order setting) one. */
-	if( cmd[1] )
-	{
-		if( sscanf( cmd[1], "%d", &numq ) != 1 )
-		{
-			irc_usermsg( irc, "Invalid query number" );
-			return( 0 );
-		}
-		
-		for( q = irc->queries; q; q = q->next, numq -- )
-			if( numq == 0 )
-				break;
-		
-		if( !q )
-		{
-			irc_usermsg( irc, "Uhm, I never asked you something like that..." );
-			return( 0 );
-		}
-	}
-	
-	if( g_strcasecmp( cmd[0], "yes" ) == 0 )
-		query_answer( irc, q, 1 );
-	else if( g_strcasecmp( cmd[0], "no" ) == 0 )
-		query_answer( irc, q, 0 );
-	
-	return( 1 );
-}
-
-int cmd_set( irc_t *irc, char **cmd )
-{
-	if( cmd[1] && cmd[2] )
-	{
-		set_setstr( irc, cmd[1], cmd[2] );
-	}
-	if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */
-	{
-		char *s = set_getstr( irc, cmd[1] );
-		if( s )
-			irc_usermsg( irc, "%s = `%s'", cmd[1], s );
-	}
-	else
-	{
-		set_t *s = irc->set;
-		while( s )
-		{
-			if( s->value || s->def )
-				irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def );
-			s = s->next;
-		}
-	}
-	
-	return( 0 );
-}
-
-int cmd_save( irc_t *irc, char **cmd )
-{
-	if( storage_save( irc, TRUE ) == STORAGE_OK )
-		irc_usermsg( irc, "Configuration saved" );
-	else
-		irc_usermsg( irc, "Configuration could not be saved!" );
-	
-	return( 0 );
-}
-
-int cmd_blist( irc_t *irc, char **cmd )
-{
-	int online = 0, away = 0, offline = 0;
-	user_t *u;
-	char s[64];
-	int n_online = 0, n_away = 0, n_offline = 0;
-	
-	if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 )
-		online = offline = away = 1;
-	else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 )
-		offline = 1;
-	else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 )
-		away = 1;
-	else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 )
-		online = 1;
-	else
-		online =  away = 1;
-	
-	irc_usermsg( irc, "%-16.16s  %-40.40s  %s", "Nick", "User/Host/Network", "Status" );
-	
-	if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away )
-	{
-		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
-		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Online" );
-		n_online ++;
-	}
-
-	if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away )
-	{
-		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
-		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, u->away );
-		n_away ++;
-	}
-	
-	if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online )
-	{
-		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
-		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Offline" );
-		n_offline ++;
-	}
-	
-	irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
-	
-	return( 0 );
-}
-
-int cmd_nick( irc_t *irc, char **cmd ) 
-{
-	account_t *a;
-
-	if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) )
-	{
-		irc_usermsg( irc, "Invalid account");
-	}
-	else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-	}
-	else if ( !cmd[2] ) 
-	{
-		irc_usermsg( irc, "Your name is `%s'" , a->gc->displayname ? a->gc->displayname : "NULL" );
-	}
-	else if ( !a->gc->prpl->set_info ) 
-	{
-		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
-	}
-	else
-	{
-		char utf8[1024];
-		
-		irc_usermsg( irc, "Setting your name to `%s'", cmd[2] );
-		
-		if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 &&
-		    do_iconv( set_getstr( irc, "charset" ), "UTF-8", cmd[2], utf8, 0, 1024 ) != -1 )
-			a->gc->prpl->set_info( a->gc, utf8 );
-		else
-			a->gc->prpl->set_info( a->gc, cmd[2] );
-	}
-	
-	return( 1 );
-}
-
-int cmd_qlist( irc_t *irc, char **cmd )
-{
-	query_t *q = irc->queries;
-	int num;
-	
-	if( !q )
-	{
-		irc_usermsg( irc, "There are no pending questions." );
-		return( 0 );
-	}
-	
-	irc_usermsg( irc, "Pending queries:" );
-	
-	for( num = 0; q; q = q->next, num ++ )
-		if( q->gc ) /* Not necessary yet, but it might come later */
-			irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->prpl->name, q->gc->username, q->question );
-		else
-			irc_usermsg( irc, "%d, BitlBee: %s", num, q->question );
-	
-	return( 0 );
-}
-
-int 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( 0 );
-	}
-	else if( !( ( gc = a->gc ) && ( a->gc->flags & OPT_LOGGED_IN ) ) )
-	{
-		irc_usermsg( irc, "That account is not on-line" );
-		return( 0 );
-	}
-	
-	if( cmd[2] )
-	{
-		if( g_strcasecmp( cmd[2], "clear" ) == 0 )
-		{
-			user_t *u;
-			
-			for( u = irc->users; u; u = u->next )
-				if( u->gc == gc )
-				{
-					u->gc->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( 0 );
-		}
-	}
-	
-	for( n = gc->irc->nicks; n; n = n->next )
-	{
-		if( n->proto == gc->prpl && !user_findhandle( gc, n->handle ) )
-		{
-	                gc->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." );
-	
-	return( 0 );
-}
Index: commands.h
===================================================================
--- commands.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ commands.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -29,36 +29,20 @@
 #include "bitlbee.h"
 
-/* Hmm... Linked list? Plleeeeaaase?? ;-) */
-
-typedef struct command_t
+typedef struct command
 {
 	char *command;
 	int required_parameters;
-	int (*execute)(irc_t *, char **args);
+	void (*execute)(irc_t *, char **args);
+	int flags;
 } command_t;
 
-int cmd_account( irc_t *irc, char **cmd );
-int cmd_help( irc_t *irc, char **args);
-int cmd_info( irc_t *irc, char **args);
-int cmd_add( irc_t *irc, char **args) ;
-int cmd_rename( irc_t *irc, char **args );
-int cmd_remove( irc_t *irc, char **args );
-int cmd_block( irc_t *irc, char **args );
-int cmd_allow( irc_t *irc, char **args );
-int cmd_save( irc_t *irc, char **args );
-int cmd_set( irc_t *irc, char **args );
-int cmd_yesno( irc_t *irc, char **args );
-int cmd_identify( irc_t *irc, char **args );
-int cmd_register( irc_t *irc, char **args );
-int cmd_drop( irc_t *irc, char **args );
-int cmd_blist( irc_t *irc, char **cmd );
-int cmd_nick( irc_t *irc, char **cmd );
-int cmd_qlist( irc_t *irc, char **cmd );
-int cmd_import_buddies( irc_t *irc, char **cmd );
-int cmd_dump( irc_t *irc, char **cmd );
+extern const command_t commands[];
 
+#define IRC_CMD_PRE_LOGIN	1
+#define IRC_CMD_LOGGED_IN	2
+#define IRC_CMD_OPER_ONLY	4
+#define IRC_CMD_TO_MASTER	8
 
-
-extern command_t commands[];
+#define IPC_CMD_TO_CHILDREN	1
 
 #endif
Index: conf.c
===================================================================
--- conf.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ conf.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -32,4 +32,5 @@
 #include "ini.h"
 #include "url.h"
+#include "ipc.h"
 
 #include "protocols/proxy.h"
@@ -46,5 +47,9 @@
 	conf = g_new0( conf_t, 1 );
 	
+#ifdef IPV6
+	conf->iface = "::";
+#else
 	conf->iface = "0.0.0.0";
+#endif
 	conf->port = 6667;
 	conf->nofork = 0;
@@ -53,10 +58,13 @@
 	conf->runmode = RUNMODE_INETD;
 	conf->authmode = AUTHMODE_OPEN;
-	conf->password = NULL;
+	conf->auth_pass = NULL;
+	conf->oper_pass = NULL;
 	conf->configdir = g_strdup( CONFIG );
 	conf->plugindir = g_strdup( PLUGINDIR );
+	conf->pidfile = g_strdup( "/var/run/bitlbee.pid" );
 	conf->motdfile = g_strdup( ETCDIR "/motd.txt" );
 	conf->ping_interval = 180;
 	conf->ping_timeout = 300;
+	proxytype = 0;
 	
 	i = conf_loadini( conf, CONF_FILE );
@@ -71,5 +79,6 @@
 	}
 	
-	while( ( opt = getopt( argc, argv, "i:p:nvIDc:d:h" ) ) >= 0 )
+	while( argc > 0 && ( opt = getopt( argc, argv, "i:p:P:nvIDFc:d:hR:" ) ) >= 0 )
+	/*     ^^^^ Just to make sure we skip this step from the REHASH handler. */
 	{
 		if( opt == 'i' )
@@ -86,12 +95,19 @@
 			conf->port = i;
 		}
+		else if( opt == 'p' )
+		{
+			g_free( conf->pidfile );
+			conf->pidfile = g_strdup( optarg );
+		}
 		else if( opt == 'n' )
-			conf->nofork=1;
+			conf->nofork = 1;
 		else if( opt == 'v' )
-			conf->verbose=1;
+			conf->verbose = 1;
 		else if( opt == 'I' )
-			conf->runmode=RUNMODE_INETD;
+			conf->runmode = RUNMODE_INETD;
 		else if( opt == 'D' )
-			conf->runmode=RUNMODE_DAEMON;
+			conf->runmode = RUNMODE_DAEMON;
+		else if( opt == 'F' )
+			conf->runmode = RUNMODE_FORKDAEMON;
 		else if( opt == 'c' )
 		{
@@ -101,4 +117,8 @@
 				CONF_FILE = g_strdup( optarg );
 				g_free( conf );
+				/* Re-evaluate arguments. Don't use this option twice, 
+				   you'll end up in an infinite loop! Hope this trick
+				   works with all libcs BTW.. */
+				optind = 1;
 				return( conf_load( argc, argv ) );
 			}
@@ -118,4 +138,5 @@
 			        "  -I  Classic/InetD mode. (Default)\n"
 			        "  -D  Daemon mode. (Still EXPERIMENTAL!)\n"
+			        "  -F  Forking daemon. (one process per client)\n"
 			        "  -i  Specify the interface (by IP address) to listen on.\n"
 			        "      (Default: 0.0.0.0 (any interface))\n"
@@ -128,4 +149,12 @@
 			return( NULL );
 		}
+		else if( opt == 'R' )
+		{
+			/* We can't load the statefile yet (and should make very sure we do this
+			   only once), so set the filename here and load the state information
+			   when initializing ForkDaemon. (This option only makes sense in that
+			   mode anyway!) */
+			ipc_master_set_statefile( optarg );
+		}
 	}
 	
@@ -157,6 +186,13 @@
 				if( g_strcasecmp( ini->value, "daemon" ) == 0 )
 					conf->runmode = RUNMODE_DAEMON;
+				else if( g_strcasecmp( ini->value, "forkdaemon" ) == 0 )
+					conf->runmode = RUNMODE_FORKDAEMON;
 				else
 					conf->runmode = RUNMODE_INETD;
+			}
+			else if( g_strcasecmp( ini->key, "pidfile" ) == 0 )
+			{
+				g_free( conf->pidfile );
+				conf->pidfile = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "daemoninterface" ) == 0 )
@@ -184,5 +220,9 @@
 			else if( g_strcasecmp( ini->key, "authpassword" ) == 0 )
 			{
-				conf->password = g_strdup( ini->value );
+				conf->auth_pass = g_strdup( ini->value );
+			}
+			else if( g_strcasecmp( ini->key, "operpassword" ) == 0 )
+			{
+				conf->oper_pass = g_strdup( ini->value );
 			}
 			else if( g_strcasecmp( ini->key, "hostname" ) == 0 )
Index: conf.h
===================================================================
--- conf.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ conf.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -27,5 +27,5 @@
 #define __CONF_H
 
-typedef enum runmode { RUNMODE_DAEMON, RUNMODE_INETD } runmode_t;
+typedef enum runmode { RUNMODE_DAEMON, RUNMODE_FORKDAEMON, RUNMODE_INETD } runmode_t;
 typedef enum authmode { AUTHMODE_OPEN, AUTHMODE_CLOSED, AUTHMODE_REGISTERED } authmode_t;
 
@@ -38,8 +38,10 @@
 	runmode_t runmode;
 	authmode_t authmode;
-	char *password;
+	char *auth_pass;
+	char *oper_pass;
 	char *hostname;
 	char *configdir;
 	char *plugindir;
+	char *pidfile;
 	char *motdfile;
 	char *primary_storage;
Index: configure
===================================================================
--- configure	(revision a323a22773714a19254db34156500a67e5916451)
+++ configure	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -14,4 +14,5 @@
 datadir='$prefix/share/bitlbee/'
 config='/var/lib/bitlbee/'
+pidfile='/var/run/bitlbee.pid'
 plugindir='$prefix/lib/bitlbee'
 
@@ -23,5 +24,4 @@
 debug=0
 strip=1
-flood=0
 ipv6=1
 ssl=auto
@@ -47,4 +47,5 @@
 --datadir=...						$datadir
 --plugindir=...						$plugindir
+--pidfile=...						$pidfile
 --config=...						$config
 
@@ -75,4 +76,5 @@
 config=`eval echo "$config/" | sed 's/\/\{1,\}/\//g'`
 plugindir=`eval echo "$plugindir/" | sed 's/\/\{1,\}/\//g'`
+pidfile=`eval echo "$pidfile/" | sed 's/\/\{1,\}/\//g'`
 
 cat<<EOF>Makefile.settings
@@ -84,4 +86,5 @@
 DATADIR=$datadir
 PLUGINDIR=$plugindir
+PIDFILE=$pidfile
 CONFIG=$config
 
@@ -105,4 +108,5 @@
 #define VARDIR "$datadir"
 #define PLUGINDIR "$plugindir"
+#define PIDFILE "$pidfile"
 #define ARCH "$arch"
 #define CPU "$cpu"
@@ -289,17 +293,16 @@
 fi
 
-if [ "$flood" = 1 ]; then
-	# echo '#define FLOOD_SEND' >> config.h
-	echo 'Flood protection is disabled in this release because of too many bugs.' 2> /dev/stderr
-	rm config.h
-	rm Makefile.settings
-	exit 1
+echo
+if [ -z "$BITLBEE_VERSION" -a -d .bzr -a -x "`which bzr`" ]; then
+	rev=`bzr revno`
+	echo 'Using bzr revision #'$rev' as version number'
+	BITLBEE_VERSION=\"bzr-$rev\"
 fi
 
 if [ -n "$BITLBEE_VERSION" ]; then
-	echo
 	echo 'Spoofing version number: '$BITLBEE_VERSION
 	echo '#undef BITLBEE_VERSION' >> config.h
-	echo '#define BITLBEE_VERSION '$BITLBEE_VERSION >> config.h;
+	echo '#define BITLBEE_VERSION '$BITLBEE_VERSION >> config.h
+	echo
 fi
 
@@ -340,5 +343,4 @@
 
 if [ "$protocols" = "PROTOCOLS = " ]; then
-	echo
 	echo "WARNING: You haven't selected any communication protocol to compile!"
 	echo "         Bitlbee will run, but you will be unable to connect to IM servers!"
@@ -348,5 +350,4 @@
 echo "PROTOOBJS = $protoobjs" >> Makefile.settings
 
-echo
 echo Architecture: $arch
 case "$arch" in
Index: doc/README
===================================================================
--- doc/README	(revision a323a22773714a19254db34156500a67e5916451)
+++ doc/README	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -50,5 +50,5 @@
 
 These days, MSN Messenger clients have to connect to the MS Passport servers
-through HTTPS. BitlBee can use serveral SSL libraries for this: GnuTLS, NSS
+through HTTPS. BitlBee can use several SSL libraries for this: GnuTLS, NSS
 (which comes with Mozilla) and OpenSSL. OpenSSL is not GPL-compatible in some
 situations, so using GnuTLS or NSS is preferred. However, especially on *BSD,
Index: ipc.c
===================================================================
--- ipc.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
+++ ipc.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -0,0 +1,500 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2006 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* IPC - communication between BitlBee processes                        */
+
+/*
+  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 "ipc.h"
+#include "commands.h"
+
+GSList *child_list = NULL;
+static char *statefile = NULL;
+
+static void ipc_master_cmd_client( irc_t *data, char **cmd )
+{
+	struct bitlbee_child *child = (void*) data;
+	
+	if( child && cmd[1] )
+	{
+		child->host = g_strdup( cmd[1] );
+		child->nick = g_strdup( cmd[2] );
+		child->realname = g_strdup( cmd[3] );
+	}
+	
+	if( g_strcasecmp( cmd[0], "CLIENT" ) == 0 )
+		ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
+		                     child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
+}
+
+static void ipc_master_cmd_die( irc_t *data, char **cmd )
+{
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		ipc_to_children_str( "DIE\r\n" );
+	
+	bitlbee_shutdown( NULL );
+}
+
+void ipc_master_cmd_rehash( irc_t *data, char **cmd )
+{
+	runmode_t oldmode;
+	
+	oldmode = global.conf->runmode;
+	
+	g_free( global.conf );
+	global.conf = conf_load( 0, NULL );
+	
+	if( global.conf->runmode != oldmode )
+	{
+		log_message( LOGLVL_WARNING, "Can't change RunMode setting at runtime, restoring original setting" );
+		global.conf->runmode = oldmode;
+	}
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+		ipc_to_children( cmd );
+}
+
+void ipc_master_cmd_restart( irc_t *data, char **cmd )
+{
+	struct bitlbee_child *child = (void*) data;
+	
+	if( global.conf->runmode != RUNMODE_FORKDAEMON )
+	{
+		/* Tell child that this is unsupported. */
+		return;
+	}
+	
+	global.restart = -1;
+	bitlbee_shutdown( NULL );
+}
+
+static const command_t ipc_master_commands[] = {
+	{ "client",     3, ipc_master_cmd_client,     0 },
+	{ "hello",      0, ipc_master_cmd_client,     0 },
+	{ "die",        0, ipc_master_cmd_die,        0 },
+	{ "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
+	{ "lilo",       1, NULL,                      IPC_CMD_TO_CHILDREN },
+	{ "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },
+	{ "rehash",     0, ipc_master_cmd_rehash,     0 },
+	{ "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
+	{ "restart",    0, ipc_master_cmd_restart,    0 },
+	{ NULL }
+};
+
+
+static void ipc_child_cmd_die( irc_t *irc, char **cmd )
+{
+	irc_abort( irc, 0, "Shutdown requested by operator" );
+}
+
+static void ipc_child_cmd_wallops( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		return;
+	
+	if( strchr( irc->umode, 'w' ) )
+		irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
+}
+
+static void ipc_child_cmd_lilo( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		return;
+	
+	if( strchr( irc->umode, 's' ) )
+		irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
+}
+
+static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		return;
+	
+	if( strchr( irc->umode, 'o' ) )
+		irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
+}
+
+static void ipc_child_cmd_rehash( irc_t *irc, char **cmd )
+{
+	runmode_t oldmode;
+	
+	oldmode = global.conf->runmode;
+	
+	g_free( global.conf );
+	global.conf = conf_load( 0, NULL );
+	
+	global.conf->runmode = oldmode;
+}
+
+static void ipc_child_cmd_kill( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		return;
+	
+	if( nick_cmp( cmd[1], irc->nick ) != 0 )
+		return;		/* It's not for us. */
+	
+	irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
+	irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
+}
+
+static void ipc_child_cmd_hello( irc_t *irc, char **cmd )
+{
+	if( irc->status < USTATUS_LOGGED_IN )
+		ipc_to_master_str( "HELLO\r\n" );
+	else
+		ipc_to_master_str( "HELLO %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
+}
+
+static const command_t ipc_child_commands[] = {
+	{ "die",        0, ipc_child_cmd_die,         0 },
+	{ "wallops",    1, ipc_child_cmd_wallops,     0 },
+	{ "lilo",       1, ipc_child_cmd_lilo,        0 },
+	{ "opermsg",    1, ipc_child_cmd_opermsg,     0 },
+	{ "rehash",     0, ipc_child_cmd_rehash,      0 },
+	{ "kill",       2, ipc_child_cmd_kill,        0 },
+	{ "hello",      0, ipc_child_cmd_hello,       0 },
+	{ NULL }
+};
+
+
+static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
+{
+	int i, j;
+	
+	if( !cmd[0] )
+		return;
+	
+	for( i = 0; commands[i].command; i ++ )
+		if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
+		{
+			/* There is no typo in this line: */
+			for( j = 1; cmd[j]; j ++ ); j --;
+			
+			if( j < commands[i].required_parameters )
+				break;
+			
+			if( commands[i].flags & IPC_CMD_TO_CHILDREN )
+				ipc_to_children( cmd );
+			else
+				commands[i].execute( data, cmd );
+			
+			break;
+		}
+}
+
+static char *ipc_readline( int fd )
+{
+	char *buf, *eol;
+	int size;
+	
+	buf = g_new0( char, 513 );
+	
+	/* Because this is internal communication, it should be pretty safe
+	   to just peek at the message, find its length (by searching for the
+	   end-of-line) and then just read that message. With internal
+	   sockets and limites message length, messages should always be
+	   complete. Saves us quite a lot of code and buffering. */
+	size = recv( fd, buf, 512, MSG_PEEK );
+	if( size == 0 || ( size < 0 && !sockerr_again() ) )
+		return NULL;
+	else if( size < 0 ) /* && sockerr_again() */
+		return( g_strdup( "" ) );
+	else
+		buf[size] = 0;
+	
+	eol = strstr( buf, "\r\n" );
+	if( eol == NULL )
+		return NULL;
+	else
+		size = eol - buf + 2;
+	
+	g_free( buf );
+	buf = g_new0( char, size + 1 );
+	
+	if( recv( fd, buf, size, 0 ) != size )
+		return NULL;
+	else
+		buf[size-2] = 0;
+	
+	return buf;
+}
+
+void ipc_master_read( gpointer data, gint source, GaimInputCondition cond )
+{
+	char *buf, **cmd;
+	
+	if( ( buf = ipc_readline( source ) ) )
+	{
+		cmd = irc_parse_line( buf );
+		if( cmd )
+			ipc_command_exec( data, cmd, ipc_master_commands );
+	}
+	else
+	{
+		GSList *l;
+		struct bitlbee_child *c;
+		
+		for( l = child_list; l; l = l->next )
+		{
+			c = l->data;
+			if( c->ipc_fd == source )
+			{
+				ipc_master_free_one( c );
+				child_list = g_slist_remove( child_list, c );
+				break;
+			}
+		}
+	}
+}
+
+void ipc_child_read( gpointer data, gint source, GaimInputCondition cond )
+{
+	char *buf, **cmd;
+	
+	if( ( buf = ipc_readline( source ) ) )
+	{
+		cmd = irc_parse_line( buf );
+		if( cmd )
+			ipc_command_exec( data, cmd, ipc_child_commands );
+	}
+	else
+	{
+		gaim_input_remove( global.listen_watch_source_id );
+		close( global.listen_socket );
+		
+		global.listen_socket = -1;
+	}
+}
+
+void ipc_to_master( char **cmd )
+{
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		char *s = irc_build_line( cmd );
+		ipc_to_master_str( "%s", s );
+		g_free( s );
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		ipc_command_exec( NULL, cmd, ipc_master_commands );
+	}
+}
+
+void ipc_to_master_str( char *format, ... )
+{
+	char *msg_buf;
+	va_list params;
+
+	va_start( params, format );
+	msg_buf = g_strdup_vprintf( format, params );
+	va_end( params );
+	
+	if( strlen( msg_buf ) > 512 )
+	{
+		/* Don't send it, it's too long... */
+	}
+	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		write( global.listen_socket, msg_buf, strlen( msg_buf ) );
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		char **cmd, *s;
+		
+		if( ( s = strchr( msg_buf, '\r' ) ) )
+			*s = 0;
+		
+		cmd = irc_parse_line( msg_buf );
+		ipc_command_exec( NULL, cmd, ipc_master_commands );
+		g_free( cmd );
+	}
+	
+	g_free( msg_buf );
+}
+
+void ipc_to_children( char **cmd )
+{
+	if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		char *msg_buf = irc_build_line( cmd );
+		ipc_to_children_str( "%s", msg_buf );
+		g_free( msg_buf );
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		GSList *l;
+		
+		for( l = irc_connection_list; l; l = l->next )
+			ipc_command_exec( l->data, cmd, ipc_child_commands );
+	}
+}
+
+void ipc_to_children_str( char *format, ... )
+{
+	char *msg_buf;
+	va_list params;
+
+	va_start( params, format );
+	msg_buf = g_strdup_vprintf( format, params );
+	va_end( params );
+	
+	if( strlen( msg_buf ) > 512 )
+	{
+		/* Don't send it, it's too long... */
+	}
+	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		int msg_len = strlen( msg_buf );
+		GSList *l;
+		
+		for( l = child_list; l; l = l->next )
+		{
+			struct bitlbee_child *c = l->data;
+			write( c->ipc_fd, msg_buf, msg_len );
+		}
+	}
+	else if( global.conf->runmode == RUNMODE_DAEMON )
+	{
+		char **cmd, *s;
+		
+		if( ( s = strchr( msg_buf, '\r' ) ) )
+			*s = 0;
+		
+		cmd = irc_parse_line( msg_buf );
+		ipc_to_children( cmd );
+		g_free( cmd );
+	}
+	
+	g_free( msg_buf );
+}
+
+void ipc_master_free_one( struct bitlbee_child *c )
+{
+	gaim_input_remove( c->ipc_inpa );
+	closesocket( c->ipc_fd );
+	
+	g_free( c->host );
+	g_free( c->nick );
+	g_free( c->realname );
+	g_free( c );
+}
+
+void ipc_master_free_all()
+{
+	GSList *l;
+	
+	for( l = child_list; l; l = l->next )
+		ipc_master_free_one( l->data );
+	
+	g_slist_free( child_list );
+	child_list = NULL;
+}
+
+char *ipc_master_save_state()
+{
+	char *fn = g_strdup( "/tmp/bee-restart.XXXXXX" );
+	int fd = mkstemp( fn );
+	GSList *l;
+	FILE *fp;
+	int i;
+	
+	if( fd == -1 )
+	{
+		log_message( LOGLVL_ERROR, "Could not create temporary file: %s", strerror( errno ) );
+		g_free( fn );
+		return NULL;
+	}
+	
+	/* This is more convenient now. */
+	fp = fdopen( fd, "w" );
+	
+	for( l = child_list, i = 0; l; l = l->next )
+		i ++;
+	
+	/* Number of client processes. */
+	fprintf( fp, "%d\n", i );
+	
+	for( l = child_list; l; l = l->next )
+		fprintf( fp, "%d %d\n", ((struct bitlbee_child*)l->data)->pid,
+		                        ((struct bitlbee_child*)l->data)->ipc_fd );
+	
+	if( fclose( fp ) == 0 )
+	{
+		return fn;
+	}
+	else
+	{
+		unlink( fn );
+		g_free( fn );
+		return NULL;
+	}
+}
+
+void ipc_master_set_statefile( char *fn )
+{
+	statefile = g_strdup( fn );
+}
+
+int ipc_master_load_state()
+{
+	struct bitlbee_child *child;
+	FILE *fp;
+	int i, n;
+	
+	if( statefile == NULL )
+		return 0;
+	fp = fopen( statefile, "r" );
+	unlink( statefile );	/* Why do it later? :-) */
+	if( fp == NULL )
+		return 0;
+	
+	if( fscanf( fp, "%d", &n ) != 1 )
+	{
+		log_message( LOGLVL_WARNING, "Could not import state information for child processes." );
+		fclose( fp );
+		return 0;
+	}
+	
+	log_message( LOGLVL_INFO, "Importing information for %d child processes.", n );
+	for( i = 0; i < n; i ++ )
+	{
+		child = g_new0( struct bitlbee_child, 1 );
+		
+		if( fscanf( fp, "%d %d", &child->pid, &child->ipc_fd ) != 2 )
+		{
+			log_message( LOGLVL_WARNING, "Unexpected end of file: Only processed %d clients.", i );
+			g_free( child );
+			fclose( fp );
+			return 0;
+		}
+		child->ipc_inpa = gaim_input_add( child->ipc_fd, GAIM_INPUT_READ, ipc_master_read, child );
+		
+		child_list = g_slist_append( child_list, child );
+	}
+	
+	ipc_to_children_str( "HELLO\r\n" );
+	ipc_to_children_str( "OPERMSG :New BitlBee master process started (version " BITLBEE_VERSION ")\r\n" );
+	
+	return 1;
+}
Index: ipc.h
===================================================================
--- ipc.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
+++ ipc.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -0,0 +1,61 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* IPC - communication between BitlBee processes                        */
+
+/*
+  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"
+
+
+struct bitlbee_child
+{
+	pid_t pid;
+	int ipc_fd;
+	gint ipc_inpa;
+	
+	char *host;
+	char *nick;
+	char *realname;
+};
+
+
+void ipc_master_read( gpointer data, gint source, GaimInputCondition cond );
+void ipc_child_read( gpointer data, gint source, GaimInputCondition cond );
+
+void ipc_master_free_one( struct bitlbee_child *child );
+void ipc_master_free_all();
+
+void ipc_to_master( char **cmd );
+void ipc_to_master_str( char *format, ... );
+void ipc_to_children( char **cmd );
+void ipc_to_children_str( char *format, ... );
+
+/* We need this function in inetd mode, so let's just make it non-static. */
+void ipc_master_cmd_rehash( irc_t *data, char **cmd );
+
+char *ipc_master_save_state();
+void ipc_master_set_statefile( char *fn );
+int ipc_master_load_state();
+
+
+extern GSList *child_list;
Index: irc.c
===================================================================
--- irc.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ irc.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -27,4 +27,5 @@
 #include "bitlbee.h"
 #include "crypting.h"
+#include "ipc.h"
 
 static gboolean irc_userping( gpointer _irc );
@@ -40,12 +41,15 @@
 irc_t *irc_new( int fd )
 {
-	irc_t *irc = g_new0( irc_t, 1 );
-	
+	irc_t *irc;
+	struct hostent *peer;
+	unsigned int i;
+	char buf[128];
+#ifdef IPV6
+	struct sockaddr_in6 sock[1];
+#else
 	struct sockaddr_in sock[1];
-#ifdef IPV6
-	struct sockaddr_in6 sock6[1];
 #endif
-	struct hostent *peer;
-	unsigned int i, j;
+	
+	irc = g_new0( irc_t, 1 );
 	
 	irc->fd = fd;
@@ -71,19 +75,22 @@
 	
 	i = sizeof( *sock );
-#ifdef IPV6
-	j = sizeof( *sock6 );
-#endif
+	
 	if( global.conf->hostname )
 		irc->myhost = g_strdup( global.conf->hostname );
-	else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET )
-	{
-		if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) )
+#ifdef IPV6
+	else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx )
+	{
+		if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) )
 			irc->myhost = g_strdup( peer->h_name );
-	}
-#ifdef IPV6
-	else if( getsockname( irc->fd, (struct sockaddr*) sock6, &j ) == 0 && sock6->sin6_family == AF_INET6 )
-	{
-		if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) )
+		else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL )
+			irc->myhost = g_strdup( ipv6_unwrap( buf ) );
+	}
+#else
+	else if( getsockname( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx )
+	{
+		if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) )
 			irc->myhost = g_strdup( peer->h_name );
+		else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL )
+			irc->myhost = g_strdup( buf );
 	}
 #endif
@@ -91,19 +98,22 @@
 	i = sizeof( *sock );
 #ifdef IPV6
-	j = sizeof( *sock6 );
+	if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin6_family == AF_INETx )
+	{
+		if( ( peer = gethostbyaddr( (char*) &sock->sin6_addr, sizeof( sock->sin6_addr ), AF_INETx ) ) )
+			irc->host = g_strdup( peer->h_name );
+		else if( inet_ntop( AF_INETx, &sock->sin6_addr, buf, sizeof( buf ) - 1 ) != NULL )
+			irc->host = g_strdup( ipv6_unwrap( buf ) );
+	}
+#else
+	if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INETx )
+	{
+		if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INETx ) ) )
+			irc->host = g_strdup( peer->h_name );
+		else if( inet_ntop( AF_INETx, &sock->sin_addr, buf, sizeof( buf ) - 1 ) != NULL )
+			irc->host = g_strdup( buf );
+	}
 #endif
-	if( getpeername( irc->fd, (struct sockaddr*) sock, &i ) == 0 && sock->sin_family == AF_INET )
-	{
-		if( ( peer = gethostbyaddr( (char*) &sock->sin_addr, sizeof( sock->sin_addr ), AF_INET ) ) )
-			irc->host = g_strdup( peer->h_name );
-	}
-#ifdef IPV6
-	else if( getpeername( irc->fd, (struct sockaddr*) sock6, &j ) == 0 && sock6->sin6_family == AF_INET6 )
-	{
-		if( ( peer = gethostbyaddr( (char*) &sock6->sin6_addr, sizeof( sock6->sin6_addr ), AF_INET6 ) ) )
-			irc->host = g_strdup( peer->h_name );
-	}
-#endif
-	
+	
+	/* Rare, but possible. */
 	if( !irc->host ) irc->host = g_strdup( "localhost." );
 	if( !irc->myhost ) irc->myhost = g_strdup( "localhost." );
@@ -142,4 +152,51 @@
 }
 
+/* immed=1 makes this function pretty much equal to irc_free(), except that
+   this one will "log". In case the connection is already broken and we
+   shouldn't try to write to it. */
+void irc_abort( irc_t *irc, int immed, char *format, ... )
+{
+	if( format != NULL )
+	{
+		va_list params;
+		char *reason;
+		
+		va_start( params, format );
+		reason = g_strdup_vprintf( format, params );
+		va_end( params );
+		
+		if( !immed )
+			irc_write( irc, "ERROR :Closing link: %s", reason );
+		
+		ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
+	                           irc->nick ? irc->nick : "(NONE)", irc->host, reason );
+	     	
+		g_free( reason );
+	}
+	else
+	{
+		if( !immed )
+			irc_write( irc, "ERROR :Closing link" );
+		
+		ipc_to_master_str( "OPERMSG :Client exiting: %s@%s [%s]\r\n",
+	        	           irc->nick ? irc->nick : "(NONE)", irc->host, "No reason given" );
+	}
+	
+	irc->status = USTATUS_SHUTDOWN;
+	if( irc->sendbuffer && !immed )
+	{
+		/* 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. */
+		
+		g_source_remove( irc->r_watch_source_id );
+		irc->r_watch_source_id = g_timeout_add_full( G_PRIORITY_HIGH, 1000, (GSourceFunc) irc_free, irc, NULL );
+	}
+	else
+	{
+		irc_free( irc );
+	}
+}
+
 static gboolean irc_free_userhash( gpointer key, gpointer value, gpointer data )
 {
@@ -163,4 +220,6 @@
 		if( storage_save( irc, TRUE ) != STORAGE_OK )
 			irc_usermsg( irc, "Error while saving settings!" );
+	
+	closesocket( irc->fd );
 	
 	if( irc->ping_source_id > 0 )
@@ -264,5 +323,5 @@
 	g_free(irc);
 	
-	if( global.conf->runmode == RUNMODE_INETD )
+	if( global.conf->runmode == RUNMODE_INETD || global.conf->runmode == RUNMODE_FORKDAEMON )
 		g_main_quit( global.loop );
 }
@@ -282,31 +341,46 @@
 }
 
-int irc_process( irc_t *irc )
-{
-	char **lines, *temp;	
+void irc_process( irc_t *irc )
+{
+	char **lines, *temp, **cmd;
 	int i;
 
-	if( irc->readbuffer != NULL ) {
-		lines = irc_tokenize(irc->readbuffer );
-		for( i = 0; *lines[i] != '\0'; i++ ) {
-			if( lines[i+1] == NULL ) {
+	if( irc->readbuffer != NULL )
+	{
+		lines = irc_tokenize( irc->readbuffer );
+		
+		for( i = 0; *lines[i] != '\0'; i ++ )
+		{
+			if( lines[i+1] == NULL )
+			{
 				temp = g_strdup( lines[i] );
 				g_free( irc->readbuffer );
 				irc->readbuffer = temp;
-				i++;
+				i ++;
 				break;
 			}			
-			if (!irc_process_line(irc, lines[i])) {
+			
+			if( ( cmd = irc_parse_line( lines[i] ) ) == NULL )
+				continue;
+			irc_exec( irc, cmd );
+			
+			g_free( cmd );
+			
+			/* Shouldn't really happen, but just in case... */
+			if( !g_slist_find( irc_connection_list, irc ) )
+			{
 				g_free( lines );
-				return 0;
+				return;
 			}
 		}
-		if(lines[i]!=NULL) {
-			g_free(irc->readbuffer);
-			irc->readbuffer=NULL;	
-		}
+		
+		if( lines[i] != NULL )
+		{
+			g_free( irc->readbuffer );
+			irc->readbuffer = NULL;
+		}
+		
 		g_free( lines );
 	}
-	return 1;	
 }
 
@@ -317,40 +391,39 @@
 
 	/* 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++;
+	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);
+	lines = g_new( char *, j + 1 );
 	
 	/* NULL terminate our list. */ 
-	lines[j]=NULL;
-	
-	lines[0]=buffer;
+	lines[j] = NULL;
+	
+	lines[0] = buffer;
 	
 	/* 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';
-
-			/* We dont want to read 1 byte before our buffer
-			 * and (in rare cases) generate a SIGSEGV.
-			 */
-			if(i!=0)
-				if(buffer[i-1]=='\r')
-					buffer[i-1]='\0';
-			if(buffer[i+1]!='\r'&&buffer[i+1]!='\n')
-				lines[++j]=buffer+i+1;
-		}
-	}
-
-	return(lines);
-}
-
-int irc_process_line( irc_t *irc, char *line )
+	for( i = 0, j = 0; buffer[i] != '\0'; i ++)
+	{
+		if( buffer[i] == '\n' )
+		{
+			buffer[i] = '\0';
+			
+			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 );
+}
+
+char **irc_parse_line( char *line )
 {
 	int i, j;
@@ -358,31 +431,32 @@
 	
 	/* Move the line pointer to the start of the command, skipping spaces and the optional prefix. */
-	if(line[0]==':') {
-		for(i=0; line[i]!=32; i++);
-		line=line+i;
-	}
-	for(i=0; line[i]==32; i++);
-	line=line+i;
-
+	if( line[0] == ':' )
+	{
+		for( i = 0; line[i] != ' '; i ++ );
+		line = line + i;
+	}
+	for( i = 0; line[i] == ' '; i ++ );
+	line = line + i;
+	
 	/* If we're already at the end of the line, return. If not, we're going to need at least one element. */
-	if(line[0]=='\0')
-		return 1;
-	else
-		j=1;	
-	
-	/* Count the number of char **cmd elements we're going to need. */	
-	for(i=0; line[i]!='\0'; i++) {
-		if((line[i]==32) && (line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':'))		
-			j++;
-		else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]==32)) {
-			j++;
-			break;
-		}
+	if( line[0] == '\0')
+		return NULL;
+	
+	/* Count the number of char **cmd elements we're going to need. */
+	j = 1;
+	for( i = 0; line[i] != '\0'; i ++ )
+	{
+		if( line[i] == ' ' )
+		{
+			j ++;
 			
+			if( line[i+1] == ':' )
+				break;
+		}
 	}	
 
 	/* Allocate the space we need. */
-	cmd=g_new(char *, j+1);
-	cmd[j]=NULL;
+	cmd = g_new( char *, j + 1 );
+	cmd[j] = NULL;
 	
 	/* Do the actual line splitting, format is:
@@ -391,477 +465,52 @@
 	 */
 
-	cmd[0]=line;
-	for(i=0, j=0; line[i]!='\0'; i++) {
-		if((line[i]==32)) {
-			line[i]='\0';
-			if((line[i+1]!=32) && (line[i+1]!='\0') && (line[i+1]!=':')) 		
-				cmd[++j]=line+i+1;
-		}
-		else if((line[i]==':') && (line[i+1]!='\0') && (line[i-1]=='\0')) {
-			cmd[++j]=line+i+1;
-			break;
-		}
-	}
-	
-	i=irc_exec(irc, cmd);
-	g_free(cmd);
-
-	return(i);	
-}
-
-int irc_exec( irc_t *irc, char **cmd )
-{	
-	int i;
-
-	if( (global.conf)->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED )
-	{
-		if( g_strcasecmp( cmd[0], "PASS" ) == 0 )
-		{
-			if( !cmd[1] )
+	cmd[0] = line;
+	for( i = 0, j = 0; line[i] != '\0'; i ++ )
+	{
+		if( line[i] == ' ' )
+		{
+			line[i] = '\0';
+			cmd[++j] = line + i + 1;
+			
+			if( line[i+1] == ':' )
 			{
-				irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
+				cmd[j] ++;
+				break;
 			}
-			else if( strcmp( cmd[1], (global.conf)->password ) == 0 )
-			{
-				irc->status = USTATUS_AUTHORIZED;
-			}
-			else
-			{
-				irc_reply( irc, 464, ":Nope, maybe you should try it again..." );
-			}
-		}
-		else
-		{
-			irc_reply( irc, 464, ":Uhh, fine, but I want the password first." );
-		}
-		
-		return( 1 );
-	}
-	
-	if( g_strcasecmp( cmd[0], "USER" ) == 0 )
-	{
-		if( !( cmd[1] && cmd[2] && cmd[3] && cmd[4] ) )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-		else if( irc->user )
-		{
-			irc_reply( irc, 462, ":You can't change your nick/userinfo" );
-		}
-		else
-		{
-			irc->user = g_strdup( cmd[1] );
-			irc->realname = g_strdup( cmd[4] );
-			if( irc->nick ) irc_login( irc );
-		}
-		return( 1 );
-	}
-	else if( g_strcasecmp( cmd[0], "NICK" ) == 0 )
-	{
-		if( !cmd[1] )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-		else if( irc->nick )
-		{
-			irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
-		}
-		/* This is not clean, but for now it'll have to be like this... */
-		else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
-		{
-			irc_reply( irc, 433, ":This nick is already in use" );
-		}
-		else if( !nick_ok( cmd[1] ) )
-		{
-			/* [SH] Invalid characters. */
-			irc_reply( irc, 432, ":This nick contains invalid characters" );
-		}
-		else
-		{
-			irc->nick = g_strdup( cmd[1] );
-			if( irc->user ) irc_login( irc );
-		}
-		return( 1 );
-	}
-	else if( g_strcasecmp( cmd[0], "QUIT" ) == 0 )
-	{
-		irc_write( irc, "ERROR :%s%s", cmd[1]?"Quit: ":"", cmd[1]?cmd[1]:"Client Quit" );
-		g_io_channel_close( irc->io_channel );
-		return( 0 );
-	}
-	
-	if( !irc->user || !irc->nick )
-	{
-		irc_reply( irc, 451, ":Register first" );
-		return( 1 );
-	}
-	
-	if( g_strcasecmp( cmd[0], "PING" ) == 0 )
-	{
-		irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
-	}
-	else if( g_strcasecmp( cmd[0], "MODE" ) == 0 )
-	{
-		if( !cmd[1] )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-		else if( *cmd[1] == '#' || *cmd[1] == '&' )
-		{
-			if( cmd[2] )
-			{
-				if( *cmd[2] == '+' || *cmd[2] == '-' )
-					irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
-				else if( *cmd[2] == 'b' )
-					irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
-			}
-			else
-				irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
-		}
-		else
-		{
-			if( nick_cmp( cmd[1], irc->nick ) == 0 )
-			{
-				if( cmd[2] )
-					irc_umode_set( irc, irc->nick, cmd[2] );
-			}
-			else
-				irc_reply( irc, 502, ":Don't touch their modes" );
-		}
-	}
-	else if( g_strcasecmp( cmd[0], "NAMES" ) == 0 )
-	{
-		irc_names( irc, cmd[1]?cmd[1]:irc->channel );
-	}
-	else if( g_strcasecmp( cmd[0], "PART" ) == 0 )
-	{
-		struct conversation *c;
-		
-		if( !cmd[1] )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-		else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
-		{
-			user_t *u = user_find( irc, irc->nick );
-			
-			/* Not allowed to leave control channel */
-			irc_part( irc, u, irc->channel );
-			irc_join( irc, u, irc->channel );
-		}
-		else if( ( c = conv_findchannel( cmd[1] ) ) )
-		{
-			user_t *u = user_find( irc, irc->nick );
-			
-			irc_part( irc, u, c->channel );
-			
-			if( c->gc && c->gc->prpl )
-			{
-				c->joined = 0;
-				c->gc->prpl->chat_leave( c->gc, c->id );
-			}
-		}
-		else
-		{
-			irc_reply( irc, 403, "%s :No such channel", cmd[1] );
-		}
-	}
-	else if( g_strcasecmp( cmd[0], "JOIN" ) == 0 )
-	{
-		if( !cmd[1] )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-		else if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
-			; /* Dude, you're already there...
-			     RFC doesn't have any reply for that though? */
-		else if( cmd[1] )
-		{
-			if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
-			{
-				user_t *u = user_find( irc, cmd[1] + 1 );
-				
-				if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open )
-				{
-					irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
-					
-					if( !u->gc->prpl->chat_open( u->gc, u->handle ) )
-					{
-						irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick );
-					}
-				}
-				else
-				{
-					irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
-				}
-			}
-			else
-			{
-				irc_reply( irc, 403, "%s :No such channel", cmd[1] );
-			}
-		}
-	}
-	else if( g_strcasecmp( cmd[0], "INVITE" ) == 0 )
-	{
-		if( cmd[1] && cmd[2] )
-			irc_invite( irc, cmd[1], cmd[2] );
-		else
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-	}
-	else if( g_strcasecmp( cmd[0], "PRIVMSG" ) == 0 || g_strcasecmp( cmd[0], "NOTICE" ) == 0 )
-	{
-		if( !cmd[1] )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		} 
-		else if ( !cmd[2] ) 
-		{
-			irc_reply( irc, 412, ":No text to send" );
-		}
-		else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) 
-		{
-			irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); 
-		}
-		else 
-		{
-			if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
-			{
-				unsigned int i;
-				char *t = set_getstr( irc, "default_target" );
-				
-				if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
-					cmd[1] = irc->last_target;
-				else if( g_strcasecmp( t, "root" ) == 0 )
-					cmd[1] = irc->mynick;
-				
-				for( i = 0; i < strlen( cmd[2] ); i ++ )
-				{
-					if( cmd[2][i] == ' ' ) break;
-					if( cmd[2][i] == ':' || cmd[2][i] == ',' )
-					{
-						cmd[1] = cmd[2];
-						cmd[2] += i;
-						*cmd[2] = 0;
-						while( *(++cmd[2]) == ' ' );
-						break;
-					}
-				}
-				
-				irc->is_private = 0;
-				
-				if( cmd[1] != irc->last_target )
-				{
-					if( irc->last_target )
-						g_free( irc->last_target );
-					irc->last_target = g_strdup( cmd[1] );
-				}
-			}
-			else
-			{
-				irc->is_private = 1;
-			}
-			irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 );
-		}
-	}
-	else if( g_strcasecmp( cmd[0], "WHO" ) == 0 )
-	{
-		irc_who( irc, cmd[1] );
-	}
-	else if( g_strcasecmp( cmd[0], "USERHOST" ) == 0 )
-	{
-		user_t *u;
-		
-		if( !cmd[1] )
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-		/* [TV] Usable USERHOST-implementation according to
-			RFC1459. Without this, mIRC shows an error
-			while connecting, and the used way of rejecting
-			breaks standards.
-		*/
-		
-		for( i = 1; cmd[i]; i ++ )
-			if( ( u = user_find( irc, cmd[i] ) ) )
-			{
-				if( u->online && u->away )
-					irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
-				else
-					irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
-			}
-	}
-	else if( g_strcasecmp( cmd[0], "ISON" ) == 0 )
-	{
-		user_t *u;
-		char buff[IRC_MAX_LINE];
-		int lenleft;
-		
-		buff[0] = '\0';
-		
-		/* [SH] Leave room for : and \0 */
-		lenleft = IRC_MAX_LINE - 2;
-		
-		for( i = 1; cmd[i]; i ++ )
-		{
-			if( ( u = user_find( irc, cmd[i] ) ) && u->online )
-			{
-				/* [SH] Make sure we don't use too much buffer space. */
-				lenleft -= strlen( u->nick ) + 1;
-				
-				if( lenleft < 0 )
-				{
-					break;
-				}
-				
-				/* [SH] Add the nick to the buffer. Note
-				 * that an extra space is always added. Even
-				 * if it's the last nick in the list. Who
-				 * cares?
-				 */
-				
-				strcat( buff, u->nick );
-				strcat( buff, " " );
-			}
-		}
-		
-		/* [WvG] Well, maybe someone cares, so why not remove it? */
-		if( strlen( buff ) > 0 )
-			buff[strlen(buff)-1] = '\0';
-		
-		/* [SH] By the way, that really *was* WvG talking. */
-		/* [WvG] Really? */
-		/* [SH] Yeah... But *this* is WvG talking too. ;-P */
-		/* [WvG] *sigh* */
-		
-		irc_reply( irc, 303, ":%s", buff );
-	}
-	else if( g_strcasecmp( cmd[0], "WATCH" ) == 0 )
-	{
-		/* Obviously we could also mark a user structure as being
-		   watched, but what if the WATCH command is sent right
-		   after connecting? The user won't exist yet then... */
-		for( i = 1; cmd[i]; i ++ )
-		{
-			char *nick;
-			user_t *u;
-			
-			if( !cmd[i][0] || !cmd[i][1] )
-				break;
-			
-			nick = g_strdup( cmd[i] + 1 );
-			nick_lc( nick );
-			
-			u = user_find( irc, nick );
-			
-			if( cmd[i][0] == '+' )
-			{
-				if( !g_hash_table_lookup( irc->watches, nick ) )
-					g_hash_table_insert( irc->watches, nick, nick );
-				
-				if( u && u->online )
-					irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "is online" );
-				else
-					irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" );
-			}
-			else if( cmd[i][0] == '-' )
-			{
-				gpointer okey, ovalue;
-				
-				if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
-				{
-					g_free( okey );
-					g_hash_table_remove( irc->watches, okey );
-					
-					irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
-				}
-			}
-		}
-	}
-	else if( g_strcasecmp( cmd[0], "TOPIC" ) == 0 )
-	{
-		if( cmd[1] && cmd[2] )
-			irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] );
-		else if( cmd[1] )
-			irc_topic( irc, cmd[1] );
-		else
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-	}
-	else if( g_strcasecmp( cmd[0], "AWAY" ) == 0 )
-	{
-		irc_away( irc, cmd[1] );
-	}
-	else if( g_strcasecmp( cmd[0], "WHOIS" ) == 0 )
-	{
-		if( cmd[1] )
-		{
-			irc_whois( irc, cmd[1] );
-		}
-		else
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-	}
-	else if( g_strcasecmp( cmd[0], "WHOWAS" ) == 0 )
-	{
-		/* For some reason irssi tries a whowas when whois fails. We can
-		   ignore this, but then the user never gets a "user not found"
-		   message from irssi which is a bit annoying. So just respond
-		   with not-found and irssi users will get better error messages */
-		
-		if( cmd[1] )
-		{
-			irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
-			irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
-		}
-		else
-		{
-			irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
-		}
-	}
-	else if( ( g_strcasecmp( cmd[0], "NICKSERV" ) == 0 ) || ( g_strcasecmp( cmd[0], "NS" ) == 0 ) )
-	{
-		/* [SH] This aliases the NickServ command to PRIVMSG root */
-		/* [TV] This aliases the NS command to PRIVMSG root as well */
-		root_command( irc, cmd + 1 );
-	}
-	else if( g_strcasecmp( cmd[0], "MOTD" ) == 0 )
-	{
-		irc_motd( irc );
-	}
-	else if( g_strcasecmp( cmd[0], "PONG" ) == 0 )
-	{
-		/* We could check the value we get back from the user, but in
-		   fact we don't care, we're just happy he's still alive. */
-		irc->last_pong = gettime();
-		irc->pinging = 0;
-	}
-	else if( g_strcasecmp( cmd[0], "COMPLETIONS" ) == 0 )
-	{
-		user_t *u = user_find( irc, irc->mynick );
-		help_t *h;
-		set_t *s;
-		int i;
-		
-		irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
-		
-		for( i = 0; commands[i].command; i ++ )
-			irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
-		
-		for( h = global.help; h; h = h->next )
-			irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string );
-		
-		for( s = irc->set; s; s = s->next )
-			irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
-		
-		irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
-	}
-	else if( set_getint( irc, "debug" ) )
-	{
-		irc_usermsg( irc, "\002--- Unknown command:" );
-		for( i = 0; cmd[i]; i ++ ) irc_usermsg( irc, "%s", cmd[i] );
-		irc_usermsg( irc, "\002--------------------" );
-	}
-	
-	return( 1 );
+		}
+	}
+	
+	return cmd;
+}
+
+char *irc_build_line( char **cmd )
+{
+	int i, len;
+	char *s;
+	
+	if( cmd[0] == NULL )
+		return NULL;
+	
+	len = 1;
+	for( i = 0; cmd[i]; i ++ )
+		len += strlen( cmd[i] ) + 1;
+	
+	if( strchr( cmd[i-1], ' ' ) != NULL )
+		len ++;
+	
+	s = g_new0( char, len + 1 );
+	for( i = 0; cmd[i]; i ++ )
+	{
+		if( cmd[i+1] == NULL && strchr( cmd[i], ' ' ) != NULL )
+			strcat( s, ":" );
+		
+		strcat( s, cmd[i] );
+		
+		if( cmd[i+1] )
+			strcat( s, " " );
+	}
+	strcat( s, "\r\n" );
+	
+	return s;
 }
 
@@ -923,19 +572,4 @@
 	if( irc->sendbuffer != NULL ) {
 		size = strlen( irc->sendbuffer ) + strlen( line );
-#ifdef FLOOD_SEND
-		if( size > FLOOD_SEND_MAXBUFFER ) {
-			/* Die flooder, die! >:) */
-
-			g_free(irc->sendbuffer);
-			
-			/* We need the \r\n at the start because else we might append our string to a half
-			 * sent line. A bit hackish, but it works.
-			 */
-			irc->sendbuffer = g_strdup( "\r\nERROR :Sendq Exceeded\r\n" );
-			irc->quit = 1;
-			
-			return;
-		}
-#endif
 		irc->sendbuffer = g_renew ( char, irc->sendbuffer, size + 1 );
 		strcpy( ( irc->sendbuffer + strlen( irc->sendbuffer ) ), line );
@@ -1037,33 +671,24 @@
 }
 
-void irc_who( irc_t *irc, char *channel )
-{
-	user_t *u = irc->users;
-	struct conversation *c;
-	GList *l;
-	
-	if( !channel || *channel == '0' || *channel == '*' || !*channel )
-		while( u )
-		{
-			irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
-			u = u->next;
-		}
-	else if( g_strcasecmp( channel, irc->channel ) == 0 )
-		while( u )
-		{
-			if( u->online )
-				irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
-			u = u->next;
-		}
-	else if( ( c = conv_findchannel( channel ) ) )
-		for( l = c->in_room; l; l = l->next )
-		{
-			if( ( u = user_findhandle( c->gc, l->data ) ) )
-				irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
-		}
-	else if( ( u = user_find( irc, channel ) ) )
-		irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
-	
-	irc_reply( irc, 315, "%s :End of /WHO list.", channel?channel:"**" );
+int irc_check_login( irc_t *irc )
+{
+	if( irc->user && irc->nick )
+	{
+		if( global.conf->authmode == AUTHMODE_CLOSED && irc->status < USTATUS_AUTHORIZED )
+		{
+			irc_reply( irc, 464, ":This server is password-protected." );
+			return 0;
+		}
+		else
+		{
+			irc_login( irc );
+			return 1;
+		}
+	}
+	else
+	{
+		/* More information needed. */
+		return 0;
+	}
 }
 
@@ -1075,8 +700,8 @@
 	irc_reply( irc,   2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
 	irc_reply( irc,   3, ":%s", IRCD_INFO );
-	irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES, CMODES );
+	irc_reply( irc,   4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
 	irc_reply( irc,   5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 );
 	irc_motd( irc );
-	irc_umode_set( irc, irc->myhost, "+" UMODE );
+	irc_umode_set( irc, "+" UMODE, 1 );
 
 	u = user_add( irc, irc->mynick );
@@ -1100,8 +725,10 @@
 	u->realname = g_strdup( irc->realname );
 	u->online = 1;
-//	u->send_handler = msg_echo;
 	irc_spawn( irc, u );
 	
 	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 FAQ's are answered there." );
+	
+	if( global.conf->runmode == RUNMODE_FORKDAEMON || global.conf->runmode == RUNMODE_DAEMON )
+		ipc_to_master_str( "CLIENT %s %s :%s\r\n", irc->host, irc->nick, irc->realname );
 	
 	irc->status = USTATUS_LOGGED_IN;
@@ -1156,5 +783,5 @@
 		}
 		irc_reply( irc, 376, ":End of MOTD" );
-		closesocket( fd );
+		close( fd );
 	}
 }
@@ -1177,34 +804,8 @@
 }
 
-void irc_whois( irc_t *irc, char *nick )
-{
-	user_t *u = user_find( irc, nick );
-	
-	if( u )
-	{
-		irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
-		
-		if( u->gc )
-			irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username,
-			           *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name );
-		else
-			irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
-		
-		if( !u->online )
-			irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
-		else if( u->away )
-			irc_reply( irc, 301, "%s :%s", u->nick, u->away );
-		
-		irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
-	}
-	else
-	{
-		irc_reply( irc, 401, "%s :Nick does not exist", nick );
-	}
-}
-
-
-void irc_umode_set( irc_t *irc, char *who, char *s )
-{
+void irc_umode_set( irc_t *irc, char *s, int allow_priv )
+{
+	/* allow_priv: Set to 0 if s contains user input, 1 if you want
+	   to set a "privileged" mode (+o, +R, etc). */
 	char m[256], st = 1, *t;
 	int i;
@@ -1219,5 +820,5 @@
 		if( *t == '+' || *t == '-' )
 			st = *t == '+';
-		else
+		else if( st == 0 || ( strchr( UMODES, *t ) || ( allow_priv && strchr( UMODES_PRIV, *t ) ) ) )
 			m[(int)*t] = st;
 	}
@@ -1226,49 +827,8 @@
 	
 	for( i = 0; i < 256 && strlen( irc->umode ) < ( sizeof( irc->umode ) - 1 ); i ++ )
-		if( m[i] && strchr( UMODES, i ) )
+		if( m[i] )
 			irc->umode[strlen(irc->umode)] = i;
 	
 	irc_reply( irc, 221, "+%s", irc->umode );
-}
-
-int irc_away( irc_t *irc, char *away )
-{
-	user_t *u = user_find( irc, irc->nick );
-	GSList *c = get_connections();
-	
-	if( !u ) return( 0 );
-	
-	if( away && *away )
-	{
-		int i, j;
-		
-		/* Copy away string, but skip control chars. Mainly because
-		   Jabber really doesn't like them. */
-		u->away = g_malloc( strlen( away ) + 1 );
-		for( i = j = 0; away[i]; i ++ )
-			if( ( u->away[j] = away[i] ) >= ' ' )
-				j ++;
-		u->away[j] = 0;
-		
-		irc_reply( irc, 306, ":You're now away: %s", u->away );
-		/* irc_umode_set( irc, irc->myhost, "+a" ); */
-	}
-	else
-	{
-		if( u->away ) g_free( u->away );
-		u->away = NULL;
-		/* irc_umode_set( irc, irc->myhost, "-a" ); */
-		irc_reply( irc, 305, ":Welcome back" );
-	}
-	
-	while( c )
-	{
-		if( ((struct gaim_connection *)c->data)->flags & OPT_LOGGED_IN )
-			proto_away( c->data, u->away );
-		
-		c = c->next;
-	}
-	
-	return( 1 );
 }
 
@@ -1324,20 +884,4 @@
 	}
 	g_free( nick );
-}
-
-void irc_invite( irc_t *irc, char *nick, char *channel )
-{
-	struct conversation *c = conv_findchannel( channel );
-	user_t *u = user_find( irc, nick );
-	
-	if( u && c && ( u->gc == c->gc ) )
-		if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite )
-		{
-			c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle );
-			irc_reply( irc, 341, "%s %s", nick, channel );
-			return;
-		}
-	
-	irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
 }
 
@@ -1430,5 +974,8 @@
 		
 		if( u->send_handler )
-			return( u->send_handler( irc, u, s, flags ) );
+		{
+			u->send_handler( irc, u, s, flags );
+			return 1;
+		}
 	}
 	else if( c && c->gc && c->gc->prpl )
@@ -1456,7 +1003,7 @@
 }
 
-int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
-{
-	if( !u || !u->gc ) return( 0 );
+void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags )
+{
+	if( !u || !u->gc ) return;
 	
 	if( set_getint( irc, "buddy_sendbuffer" ) && set_getint( irc, "buddy_sendbuffer_delay" ) > 0 )
@@ -1494,10 +1041,8 @@
 			g_source_remove( u->sendbuf_timer );
 		u->sendbuf_timer = g_timeout_add( delay, buddy_send_handler_delayed, u );
-		
-		return( 1 );
 	}
 	else
 	{
-		return( serv_send_im( irc, u, msg, flags ) );
+		serv_send_im( irc, u, msg, flags );
 	}
 }
@@ -1604,6 +1149,5 @@
 	if( rv > 0 )
 	{
-		irc_write( irc, "ERROR :Closing Link: Ping Timeout: %d seconds", rv );
-		irc_free( irc );
+		irc_abort( irc, 0, "Ping Timeout: %d seconds", rv );
 		return FALSE;
 	}
Index: irc.h
===================================================================
--- irc.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ irc.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -33,12 +33,6 @@
 #define IRC_PING_STRING "PinglBee"
 
-/* #define FLOOD_SEND 
- * Not yet enabled by default due to some problems.
- */
-#define FLOOD_SEND_INTERVAL 30
-#define FLOOD_SEND_BYTES (1024*10)
-#define FLOOD_SEND_MAXBUFFER (1024*20)
-
-#define UMODES "ais"
+#define UMODES "iasw"
+#define UMODES_PRIV "Ro"
 #define CMODES "nt"
 #define CMODE "t"
@@ -47,8 +41,9 @@
 typedef enum
 {
-	USTATUS_OFFLINE,
+	USTATUS_OFFLINE = 0,
 	USTATUS_AUTHORIZED,
 	USTATUS_LOGGED_IN,
-	USTATUS_IDENTIFIED
+	USTATUS_IDENTIFIED,
+	USTATUS_SHUTDOWN = -1
 } irc_status_t;
 
@@ -110,9 +105,11 @@
 
 irc_t *irc_new( int fd );
+void irc_abort( irc_t *irc, int immed, char *format, ... );
 void irc_free( irc_t *irc );
 
-int irc_exec( irc_t *irc, char **cmd );
-int irc_process( irc_t *irc );
-int irc_process_line( irc_t *irc, char *line );
+void irc_exec( irc_t *irc, char **cmd );
+void irc_process( irc_t *irc );
+char **irc_parse_line( char *line );
+char *irc_build_line( char **cmd );
 
 void irc_vawrite( irc_t *irc, char *format, va_list params );
@@ -124,8 +121,9 @@
 
 void irc_login( irc_t *irc );
+int irc_check_login( irc_t *irc );
 void irc_motd( irc_t *irc );
 void irc_names( irc_t *irc, char *channel );
 void irc_topic( irc_t *irc, char *channel );
-void irc_umode_set( irc_t *irc, char *who, char *s );
+void irc_umode_set( irc_t *irc, char *s, int allow_priv );
 void irc_who( irc_t *irc, char *channel );
 void irc_spawn( irc_t *irc, user_t *u );
@@ -136,5 +134,4 @@
 void irc_invite( irc_t *irc, char *nick, char *channel );
 void irc_whois( irc_t *irc, char *nick );
-int irc_away( irc_t *irc, char *away );
 void irc_setpass( irc_t *irc, const char *pass ); /* USE WITH CAUTION! */
 
@@ -144,5 +141,5 @@
 int irc_noticefrom( irc_t *irc, char *nick, char *msg );
 
-int buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
+void buddy_send_handler( irc_t *irc, user_t *u, char *msg, int flags );
 
 #endif
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
+++ irc_commands.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -0,0 +1,622 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2006 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* IRC commands                                                         */
+
+/*
+  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 "ipc.h"
+
+static void irc_cmd_pass( irc_t *irc, char **cmd )
+{
+	if( global.conf->auth_pass && strcmp( cmd[1], global.conf->auth_pass ) == 0 )
+	{
+		irc->status = USTATUS_AUTHORIZED;
+		irc_check_login( irc );
+	}
+	else
+	{
+		irc_reply( irc, 464, ":Incorrect password" );
+	}
+}
+
+static void irc_cmd_user( irc_t *irc, char **cmd )
+{
+	irc->user = g_strdup( cmd[1] );
+	irc->realname = g_strdup( cmd[4] );
+	
+	irc_check_login( irc );
+}
+
+static void irc_cmd_nick( irc_t *irc, char **cmd )
+{
+	if( irc->nick )
+	{
+		irc_reply( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
+	}
+	/* This is not clean, but for now it'll have to be like this... */
+	else if( ( nick_cmp( cmd[1], irc->mynick ) == 0 ) || ( nick_cmp( cmd[1], NS_NICK ) == 0 ) )
+	{
+		irc_reply( irc, 433, ":This nick is already in use" );
+	}
+	else if( !nick_ok( cmd[1] ) )
+	{
+		/* [SH] Invalid characters. */
+		irc_reply( irc, 432, ":This nick contains invalid characters" );
+	}
+	else
+	{
+		irc->nick = g_strdup( cmd[1] );
+		
+		irc_check_login( irc );
+	}
+}
+
+static void irc_cmd_quit( irc_t *irc, char **cmd )
+{
+	if( cmd[1] && *cmd[1] )
+		irc_abort( irc, 0, "Quit: %s", cmd[1] );
+	else
+		irc_abort( irc, 0, "Leaving..." );
+}
+
+static void irc_cmd_ping( irc_t *irc, char **cmd )
+{
+	irc_write( irc, ":%s PONG %s :%s", irc->myhost, irc->myhost, cmd[1]?cmd[1]:irc->myhost );
+}
+
+static void irc_cmd_oper( irc_t *irc, char **cmd )
+{
+	if( global.conf->oper_pass && strcmp( cmd[2], global.conf->oper_pass ) == 0 )
+	{
+		irc_umode_set( irc, "+o", 1 );
+		irc_reply( irc, 381, ":Password accepted" );
+	}
+	else
+	{
+		irc_reply( irc, 432, ":Incorrect password" );
+	}
+}
+
+static void irc_cmd_mode( irc_t *irc, char **cmd )
+{
+	if( *cmd[1] == '#' || *cmd[1] == '&' )
+	{
+		if( cmd[2] )
+		{
+			if( *cmd[2] == '+' || *cmd[2] == '-' )
+				irc_reply( irc, 477, "%s :Can't change channel modes", cmd[1] );
+			else if( *cmd[2] == 'b' )
+				irc_reply( irc, 368, "%s :No bans possible", cmd[1] );
+		}
+		else
+			irc_reply( irc, 324, "%s +%s", cmd[1], CMODE );
+	}
+	else
+	{
+		if( nick_cmp( cmd[1], irc->nick ) == 0 )
+		{
+			if( cmd[2] )
+				irc_umode_set( irc, cmd[2], 0 );
+		}
+		else
+			irc_reply( irc, 502, ":Don't touch their modes" );
+	}
+}
+
+static void irc_cmd_names( irc_t *irc, char **cmd )
+{
+	irc_names( irc, cmd[1]?cmd[1]:irc->channel );
+}
+
+static void irc_cmd_part( irc_t *irc, char **cmd )
+{
+	struct conversation *c;
+	
+	if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
+	{
+		user_t *u = user_find( irc, irc->nick );
+		
+		/* Not allowed to leave control channel */
+		irc_part( irc, u, irc->channel );
+		irc_join( irc, u, irc->channel );
+	}
+	else if( ( c = conv_findchannel( cmd[1] ) ) )
+	{
+		user_t *u = user_find( irc, irc->nick );
+		
+		irc_part( irc, u, c->channel );
+		
+		if( c->gc && c->gc->prpl )
+		{
+			c->joined = 0;
+			c->gc->prpl->chat_leave( c->gc, c->id );
+		}
+	}
+	else
+	{
+		irc_reply( irc, 403, "%s :No such channel", cmd[1] );
+	}
+}
+
+static void irc_cmd_join( irc_t *irc, char **cmd )
+{
+	if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
+		; /* Dude, you're already there...
+		     RFC doesn't have any reply for that though? */
+	else if( cmd[1] )
+	{
+		if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
+		{
+			user_t *u = user_find( irc, cmd[1] + 1 );
+			
+			if( u && u->gc && u->gc->prpl && u->gc->prpl->chat_open )
+			{
+				irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
+				
+				if( !u->gc->prpl->chat_open( u->gc, u->handle ) )
+				{
+					irc_usermsg( irc, "Could not open a groupchat with %s, maybe you don't have a connection to him/her yet?", u->nick );
+				}
+			}
+			else if( u )
+			{
+				irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
+			}
+			else
+			{
+				irc_reply( irc, 403, "%s :No such nick", cmd[1] );
+			}
+		}
+		else
+		{
+			irc_reply( irc, 403, "%s :No such channel", cmd[1] );
+		}
+	}
+}
+
+static void irc_cmd_invite( irc_t *irc, char **cmd )
+{
+	char *nick = cmd[1], *channel = cmd[2];
+	struct conversation *c = conv_findchannel( channel );
+	user_t *u = user_find( irc, nick );
+	
+	if( u && c && ( u->gc == c->gc ) )
+		if( c->gc && c->gc->prpl && c->gc->prpl->chat_invite )
+		{
+			c->gc->prpl->chat_invite( c->gc, c->id, "", u->handle );
+			irc_reply( irc, 341, "%s %s", nick, channel );
+			return;
+		}
+	
+	irc_reply( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
+}
+
+static void irc_cmd_privmsg( irc_t *irc, char **cmd )
+{
+	if ( !cmd[2] ) 
+	{
+		irc_reply( irc, 412, ":No text to send" );
+	}
+	else if ( irc->nick && g_strcasecmp( cmd[1], irc->nick ) == 0 ) 
+	{
+		irc_write( irc, ":%s!%s@%s %s %s :%s", irc->nick, irc->user, irc->host, cmd[0], cmd[1], cmd[2] ); 
+	}
+	else 
+	{
+		if( g_strcasecmp( cmd[1], irc->channel ) == 0 )
+		{
+			unsigned int i;
+			char *t = set_getstr( irc, "default_target" );
+			
+			if( g_strcasecmp( t, "last" ) == 0 && irc->last_target )
+				cmd[1] = irc->last_target;
+			else if( g_strcasecmp( t, "root" ) == 0 )
+				cmd[1] = irc->mynick;
+			
+			for( i = 0; i < strlen( cmd[2] ); i ++ )
+			{
+				if( cmd[2][i] == ' ' ) break;
+				if( cmd[2][i] == ':' || cmd[2][i] == ',' )
+				{
+					cmd[1] = cmd[2];
+					cmd[2] += i;
+					*cmd[2] = 0;
+					while( *(++cmd[2]) == ' ' );
+					break;
+				}
+			}
+			
+			irc->is_private = 0;
+			
+			if( cmd[1] != irc->last_target )
+			{
+				if( irc->last_target )
+					g_free( irc->last_target );
+				irc->last_target = g_strdup( cmd[1] );
+			}
+		}
+		else
+		{
+			irc->is_private = 1;
+		}
+		irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? IM_FLAG_AWAY : 0 );
+	}
+}
+
+static void irc_cmd_who( irc_t *irc, char **cmd )
+{
+	char *channel = cmd[1];
+	user_t *u = irc->users;
+	struct conversation *c;
+	GList *l;
+	
+	if( !channel || *channel == '0' || *channel == '*' || !*channel )
+		while( u )
+		{
+			irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", u->online ? irc->channel : "*", u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
+			u = u->next;
+		}
+	else if( g_strcasecmp( channel, irc->channel ) == 0 )
+		while( u )
+		{
+			if( u->online )
+				irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
+			u = u->next;
+		}
+	else if( ( c = conv_findchannel( channel ) ) )
+		for( l = c->in_room; l; l = l->next )
+		{
+			if( ( u = user_findhandle( c->gc, l->data ) ) )
+				irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->away ? 'G' : 'H', u->realname );
+		}
+	else if( ( u = user_find( irc, channel ) ) )
+		irc_reply( irc, 352, "%s %s %s %s %s %c :0 %s", channel, u->user, u->host, irc->myhost, u->nick, u->online ? ( u->away ? 'G' : 'H' ) : 'G', u->realname );
+	
+	irc_reply( irc, 315, "%s :End of /WHO list", channel?channel:"**" );
+}
+
+static void irc_cmd_userhost( irc_t *irc, char **cmd )
+{
+	user_t *u;
+	int i;
+	
+	/* [TV] Usable USERHOST-implementation according to
+		RFC1459. Without this, mIRC shows an error
+		while connecting, and the used way of rejecting
+		breaks standards.
+	*/
+	
+	for( i = 1; cmd[i]; i ++ )
+		if( ( u = user_find( irc, cmd[i] ) ) )
+		{
+			if( u->online && u->away )
+				irc_reply( irc, 302, ":%s=-%s@%s", u->nick, u->user, u->host );
+			else
+				irc_reply( irc, 302, ":%s=+%s@%s", u->nick, u->user, u->host );
+		}
+}
+
+static void irc_cmd_ison( irc_t *irc, char **cmd )
+{
+	user_t *u;
+	char buff[IRC_MAX_LINE];
+	int lenleft, i;
+	
+	buff[0] = '\0';
+	
+	/* [SH] Leave room for : and \0 */
+	lenleft = IRC_MAX_LINE - 2;
+	
+	for( i = 1; cmd[i]; i ++ )
+	{
+		if( ( u = user_find( irc, cmd[i] ) ) && u->online )
+		{
+			/* [SH] Make sure we don't use too much buffer space. */
+			lenleft -= strlen( u->nick ) + 1;
+			
+			if( lenleft < 0 )
+			{
+				break;
+			}
+			
+			/* [SH] Add the nick to the buffer. Note
+			 * that an extra space is always added. Even
+			 * if it's the last nick in the list. Who
+			 * cares?
+			 */
+			
+			strcat( buff, u->nick );
+			strcat( buff, " " );
+		}
+	}
+	
+	/* [WvG] Well, maybe someone cares, so why not remove it? */
+	if( strlen( buff ) > 0 )
+		buff[strlen(buff)-1] = '\0';
+	
+	irc_reply( irc, 303, ":%s", buff );
+}
+
+static void irc_cmd_watch( irc_t *irc, char **cmd )
+{
+	int i;
+	
+	/* Obviously we could also mark a user structure as being
+	   watched, but what if the WATCH command is sent right
+	   after connecting? The user won't exist yet then... */
+	for( i = 1; cmd[i]; i ++ )
+	{
+		char *nick;
+		user_t *u;
+		
+		if( !cmd[i][0] || !cmd[i][1] )
+			break;
+		
+		nick = g_strdup( cmd[i] + 1 );
+		nick_lc( nick );
+		
+		u = user_find( irc, nick );
+		
+		if( cmd[i][0] == '+' )
+		{
+			if( !g_hash_table_lookup( irc->watches, nick ) )
+				g_hash_table_insert( irc->watches, nick, nick );
+			
+			if( u && u->online )
+				irc_reply( irc, 604, "%s %s %s %d :%s", u->nick, u->user, u->host, time( NULL ), "is online" );
+			else
+				irc_reply( irc, 605, "%s %s %s %d :%s", nick, "*", "*", time( NULL ), "is offline" );
+		}
+		else if( cmd[i][0] == '-' )
+		{
+			gpointer okey, ovalue;
+			
+			if( g_hash_table_lookup_extended( irc->watches, nick, &okey, &ovalue ) )
+			{
+				g_free( okey );
+				g_hash_table_remove( irc->watches, okey );
+				
+				irc_reply( irc, 602, "%s %s %s %d :%s", nick, "*", "*", 0, "Stopped watching" );
+			}
+		}
+	}
+}
+
+static void irc_cmd_topic( irc_t *irc, char **cmd )
+{
+	if( cmd[2] )
+		irc_reply( irc, 482, "%s :Cannot change topic", cmd[1] );
+	else
+		irc_topic( irc, cmd[1] );
+}
+
+static void irc_cmd_away( irc_t *irc, char **cmd )
+{
+	user_t *u = user_find( irc, irc->nick );
+	char *away = cmd[1];
+	account_t *a;
+	
+	if( !u ) return;
+	
+	if( away && *away )
+	{
+		int i, j;
+		
+		/* Copy away string, but skip control chars. Mainly because
+		   Jabber really doesn't like them. */
+		u->away = g_malloc( strlen( away ) + 1 );
+		for( i = j = 0; away[i]; i ++ )
+			if( ( u->away[j] = away[i] ) >= ' ' )
+				j ++;
+		u->away[j] = 0;
+		
+		irc_reply( irc, 306, ":You're now away: %s", u->away );
+		/* irc_umode_set( irc, irc->myhost, "+a" ); */
+	}
+	else
+	{
+		if( u->away ) g_free( u->away );
+		u->away = NULL;
+		/* irc_umode_set( irc, irc->myhost, "-a" ); */
+		irc_reply( irc, 305, ":Welcome back" );
+	}
+	
+	for( a = irc->accounts; a; a = a->next )
+	{
+		struct gaim_connection *gc = a->gc;
+		
+		if( gc && gc->flags & OPT_LOGGED_IN )
+			proto_away( gc, u->away );
+	}
+}
+
+static void irc_cmd_whois( irc_t *irc, char **cmd )
+{
+	char *nick = cmd[1];
+	user_t *u = user_find( irc, nick );
+	
+	if( u )
+	{
+		irc_reply( irc, 311, "%s %s %s * :%s", u->nick, u->user, u->host, u->realname );
+		
+		if( u->gc )
+			irc_reply( irc, 312, "%s %s.%s :%s network", u->nick, u->gc->user->username,
+			           *u->gc->user->proto_opt[0] ? u->gc->user->proto_opt[0] : "", u->gc->prpl->name );
+		else
+			irc_reply( irc, 312, "%s %s :%s", u->nick, irc->myhost, IRCD_INFO );
+		
+		if( !u->online )
+			irc_reply( irc, 301, "%s :%s", u->nick, "User is offline" );
+		else if( u->away )
+			irc_reply( irc, 301, "%s :%s", u->nick, u->away );
+		
+		irc_reply( irc, 318, "%s :End of /WHOIS list", nick );
+	}
+	else
+	{
+		irc_reply( irc, 401, "%s :Nick does not exist", nick );
+	}
+}
+
+static void irc_cmd_whowas( irc_t *irc, char **cmd )
+{
+	/* For some reason irssi tries a whowas when whois fails. We can
+	   ignore this, but then the user never gets a "user not found"
+	   message from irssi which is a bit annoying. So just respond
+	   with not-found and irssi users will get better error messages */
+	
+	irc_reply( irc, 406, "%s :Nick does not exist", cmd[1] );
+	irc_reply( irc, 369, "%s :End of WHOWAS", cmd[1] );
+}
+
+static void irc_cmd_nickserv( irc_t *irc, char **cmd )
+{
+	/* [SH] This aliases the NickServ command to PRIVMSG root */
+	/* [TV] This aliases the NS command to PRIVMSG root as well */
+	root_command( irc, cmd + 1 );
+}
+
+static void irc_cmd_motd( irc_t *irc, char **cmd )
+{
+	irc_motd( irc );
+}
+
+static void irc_cmd_pong( irc_t *irc, char **cmd )
+{
+	/* We could check the value we get back from the user, but in
+	   fact we don't care, we're just happy he's still alive. */
+	irc->last_pong = gettime();
+	irc->pinging = 0;
+}
+
+static void irc_cmd_completions( irc_t *irc, char **cmd )
+{
+	user_t *u = user_find( irc, irc->mynick );
+	help_t *h;
+	set_t *s;
+	int i;
+	
+	irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "OK" );
+	
+	for( i = 0; commands[i].command; i ++ )
+		irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", commands[i].command );
+	
+	for( h = global.help; h; h = h->next )
+		irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS help ", h->string );
+	
+	for( s = irc->set; s; s = s->next )
+		irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS set ", s->key );
+	
+	irc_privmsg( irc, u, "NOTICE", irc->nick, "COMPLETIONS ", "END" );
+}
+
+static void irc_cmd_rehash( irc_t *irc, char **cmd )
+{
+	if( global.conf->runmode == RUNMODE_INETD )
+		ipc_master_cmd_rehash( NULL, NULL );
+	else
+		ipc_to_master( cmd );
+	
+	irc_reply( irc, 382, "%s :Rehashing", CONF_FILE );
+}
+
+static const command_t irc_commands[] = {
+	{ "pass",        1, irc_cmd_pass,        IRC_CMD_PRE_LOGIN },
+	{ "user",        4, irc_cmd_user,        IRC_CMD_PRE_LOGIN },
+	{ "nick",        1, irc_cmd_nick,        0 },
+	{ "quit",        0, irc_cmd_quit,        0 },
+	{ "ping",        0, irc_cmd_ping,        0 },
+	{ "oper",        2, irc_cmd_oper,        IRC_CMD_LOGGED_IN },
+	{ "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
+	{ "names",       0, irc_cmd_names,       IRC_CMD_LOGGED_IN },
+	{ "part",        1, irc_cmd_part,        IRC_CMD_LOGGED_IN },
+	{ "join",        1, irc_cmd_join,        IRC_CMD_LOGGED_IN },
+	{ "invite",      2, irc_cmd_invite,      IRC_CMD_LOGGED_IN },
+	{ "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
+	{ "notice",      1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
+	{ "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
+	{ "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
+	{ "ison",        1, irc_cmd_ison,        IRC_CMD_LOGGED_IN },
+	{ "watch",       1, irc_cmd_watch,       IRC_CMD_LOGGED_IN },
+	{ "topic",       1, irc_cmd_topic,       IRC_CMD_LOGGED_IN },
+	{ "away",        0, irc_cmd_away,        IRC_CMD_LOGGED_IN },
+	{ "whois",       1, irc_cmd_whois,       IRC_CMD_LOGGED_IN },
+	{ "whowas",      1, irc_cmd_whowas,      IRC_CMD_LOGGED_IN },
+	{ "nickserv",    1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
+	{ "ns",          1, irc_cmd_nickserv,    IRC_CMD_LOGGED_IN },
+	{ "motd",        0, irc_cmd_motd,        IRC_CMD_LOGGED_IN },
+	{ "pong",        0, irc_cmd_pong,        IRC_CMD_LOGGED_IN },
+	{ "completions", 0, irc_cmd_completions, IRC_CMD_LOGGED_IN },
+	{ "die",         0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+	{ "wallops",     1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+	{ "lilo",        1, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+	{ "rehash",      0, irc_cmd_rehash,      IRC_CMD_OPER_ONLY },
+	{ "restart",     0, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+	{ "kill",        2, NULL,                IRC_CMD_OPER_ONLY | IRC_CMD_TO_MASTER },
+	{ NULL }
+};
+
+void irc_exec( irc_t *irc, char *cmd[] )
+{	
+	int i, n_arg;
+	
+	if( !cmd[0] )
+		return;
+	
+	for( i = 0; irc_commands[i].command; i++ )
+		if( g_strcasecmp( irc_commands[i].command, cmd[0] ) == 0 )
+		{
+			/* There should be no typo in the next line: */
+			for( n_arg = 0; cmd[n_arg]; n_arg ++ ); n_arg --;
+			
+			if( irc_commands[i].flags & IRC_CMD_PRE_LOGIN && irc->status >= USTATUS_LOGGED_IN )
+			{
+				irc_reply( irc, 462, ":Only allowed before logging in" );
+			}
+			else if( irc_commands[i].flags & IRC_CMD_LOGGED_IN && irc->status < USTATUS_LOGGED_IN )
+			{
+				irc_reply( irc, 451, ":Register first" );
+			}
+			else if( irc_commands[i].flags & IRC_CMD_OPER_ONLY && !strchr( irc->umode, 'o' ) )
+			{
+				irc_reply( irc, 481, ":Permission denied - You're not an IRC operator" );
+			}
+			else if( n_arg < irc_commands[i].required_parameters )
+			{
+				irc_reply( irc, 461, "%s :Need more parameters", cmd[0] );
+			}
+			else if( irc_commands[i].flags & IRC_CMD_TO_MASTER )
+			{
+				/* IPC doesn't make sense in inetd mode,
+				    but the function will catch that. */
+				ipc_to_master( cmd );
+			}
+			else
+			{
+				irc_commands[i].execute( irc, cmd );
+			}
+			
+			break;
+		}
+}
Index: log.c
===================================================================
--- log.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ log.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -38,9 +38,9 @@
 	openlog("bitlbee", LOG_PID, LOG_DAEMON);	
 
-	logoutput.informational=&log_null;
-	logoutput.warning=&log_null;
-	logoutput.error=&log_null;
+	logoutput.informational = &log_null;
+	logoutput.warning = &log_null;
+	logoutput.error = &log_null;
 #ifdef DEBUG
-	logoutput.debug=&log_null;
+	logoutput.debug = &log_null;
 #endif
 
@@ -51,44 +51,44 @@
 	/* I know it's ugly, but it works and I didn't feel like messing with pointer to function pointers */
 
-	if(level==LOGLVL_INFO) {
-		if(output==LOGOUTPUT_NULL)
-			logoutput.informational=&log_null;	
-		else if(output==LOGOUTPUT_IRC)
-			logoutput.informational=&log_irc;	
-		else if(output==LOGOUTPUT_SYSLOG)
-			logoutput.informational=&log_syslog;	
-		else if(output==LOGOUTPUT_CONSOLE) 
-			logoutput.informational=&log_console;	
+	if(level == LOGLVL_INFO) {
+		if(output == LOGOUTPUT_NULL)
+			logoutput.informational = &log_null;	
+		else if(output == LOGOUTPUT_IRC)
+			logoutput.informational = &log_irc;	
+		else if(output == LOGOUTPUT_SYSLOG)
+			logoutput.informational = &log_syslog;	
+		else if(output == LOGOUTPUT_CONSOLE) 
+			logoutput.informational = &log_console;	
 	}
-	else if(level==LOGLVL_WARNING) {
-		if(output==LOGOUTPUT_NULL)
-			logoutput.warning=&log_null;
-		else if(output==LOGOUTPUT_IRC)
-			logoutput.warning=&log_irc;
-		else if(output==LOGOUTPUT_SYSLOG)
-			logoutput.warning=&log_syslog;
-		else if(output==LOGOUTPUT_CONSOLE)
-			logoutput.warning=&log_console;
+	else if(level == LOGLVL_WARNING) {
+		if(output == LOGOUTPUT_NULL)
+			logoutput.warning = &log_null;
+		else if(output == LOGOUTPUT_IRC)
+			logoutput.warning = &log_irc;
+		else if(output == LOGOUTPUT_SYSLOG)
+			logoutput.warning = &log_syslog;
+		else if(output == LOGOUTPUT_CONSOLE)
+			logoutput.warning = &log_console;
 	}
-	else if(level==LOGLVL_ERROR) {
-		if(output==LOGOUTPUT_NULL)
-			logoutput.error=&log_null;
-		else if(output==LOGOUTPUT_IRC)
-			logoutput.error=&log_irc;
-		else if(output==LOGOUTPUT_SYSLOG)
-			logoutput.error=&log_syslog;
-		else if(output==LOGOUTPUT_CONSOLE)
-			logoutput.error=&log_console;
+	else if(level == LOGLVL_ERROR) {
+		if(output == LOGOUTPUT_NULL)
+			logoutput.error = &log_null;
+		else if(output == LOGOUTPUT_IRC)
+			logoutput.error = &log_irc;
+		else if(output == LOGOUTPUT_SYSLOG)
+			logoutput.error = &log_syslog;
+		else if(output == LOGOUTPUT_CONSOLE)
+			logoutput.error = &log_console;
 	}
 #ifdef DEBUG
-	else if(level==LOGLVL_DEBUG) {
-		if(output==LOGOUTPUT_NULL)
-			logoutput.debug=&log_null;
-		else if(output==LOGOUTPUT_IRC)
-			logoutput.debug=&log_irc;
-		else if(output==LOGOUTPUT_SYSLOG)
-			logoutput.debug=&log_syslog;
-		else if(output==LOGOUTPUT_CONSOLE)
-			logoutput.debug=&log_console;
+	else if(level == LOGLVL_DEBUG) {
+		if(output == LOGOUTPUT_NULL)
+			logoutput.debug = &log_null;
+		else if(output == LOGOUTPUT_IRC)
+			logoutput.debug = &log_irc;
+		else if(output == LOGOUTPUT_SYSLOG)
+			logoutput.debug = &log_syslog;
+		else if(output == LOGOUTPUT_CONSOLE)
+			logoutput.debug = &log_console;
 	}
 #endif
@@ -106,12 +106,12 @@
 	va_end(ap);
 
-	if(level==LOGLVL_INFO)
+	if(level == LOGLVL_INFO)
 		(*(logoutput.informational))(level, msgstring);
-	if(level==LOGLVL_WARNING) 
+	if(level == LOGLVL_WARNING) 
 		(*(logoutput.warning))(level, msgstring);
-	if(level==LOGLVL_ERROR)
+	if(level == LOGLVL_ERROR)
 		(*(logoutput.error))(level, msgstring);
 #ifdef DEBUG
-	if(level==LOGLVL_DEBUG)
+	if(level == LOGLVL_DEBUG)
 		(*(logoutput.debug))(level, msgstring);
 #endif
@@ -133,12 +133,12 @@
 
 static void log_irc(int level, char *message) {
-	if(level==LOGLVL_ERROR)
+	if(level == LOGLVL_ERROR)
 		irc_write_all(1, "ERROR :Error: %s", message);
-	if(level==LOGLVL_WARNING)
+	if(level == LOGLVL_WARNING)
 		irc_write_all(0, "ERROR :Warning: %s", message);
-	if(level==LOGLVL_INFO)
+	if(level == LOGLVL_INFO)
 		irc_write_all(0, "ERROR :Informational: %s", message);	
 #ifdef DEBUG
-	if(level==LOGLVL_DEBUG)
+	if(level == LOGLVL_DEBUG)
 		irc_write_all(0, "ERROR :Debug: %s", message);	
 #endif	
@@ -148,12 +148,12 @@
 
 static void log_syslog(int level, char *message) {
-	if(level==LOGLVL_ERROR)
+	if(level == LOGLVL_ERROR)
 		syslog(LOG_ERR, "%s", message);
-	if(level==LOGLVL_WARNING)
+	if(level == LOGLVL_WARNING)
 		syslog(LOG_WARNING, "%s", message);
-	if(level==LOGLVL_INFO)
+	if(level == LOGLVL_INFO)
 		syslog(LOG_INFO, "%s", message);
 #ifdef DEBUG
-	if(level==LOGLVL_DEBUG)
+	if(level == LOGLVL_DEBUG)
 		syslog(LOG_DEBUG, "%s", message);
 #endif
@@ -162,12 +162,12 @@
 
 static void log_console(int level, char *message) {
-	if(level==LOGLVL_ERROR)
+	if(level == LOGLVL_ERROR)
 		fprintf(stderr, "Error: %s\n", message);
-	if(level==LOGLVL_WARNING)
+	if(level == LOGLVL_WARNING)
 		fprintf(stderr, "Warning: %s\n", message);
-	if(level==LOGLVL_INFO)
+	if(level == LOGLVL_INFO)
 		fprintf(stdout, "Informational: %s\n", message);
 #ifdef DEBUG
-	if(level==LOGLVL_DEBUG)
+	if(level == LOGLVL_DEBUG)
 		fprintf(stdout, "Debug: %s\n", message);
 #endif
Index: protocols/Makefile
===================================================================
--- protocols/Makefile	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/Makefile	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -10,5 +10,5 @@
 
 # [SH] Program variables
-objects = http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT) util.o
+objects = http_client.o md5.o nogaim.o proxy.o sha.o $(SSL_CLIENT)
 
 # [SH] The next two lines should contain the directory name (in $(subdirs))
Index: protocols/http_client.c
===================================================================
--- protocols/http_client.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/http_client.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -27,7 +27,7 @@
 #include <stdio.h>
 
-#include "sock.h"
 #include "http_client.h"
 #include "url.h"
+#include "sock.h"
 
 
Index: protocols/jabber/jabber.c
===================================================================
--- protocols/jabber/jabber.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/jabber/jabber.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -413,5 +413,5 @@
 		if (jd->die)
 			signoff(GJ_GC(gjc));
-	} else if (len < 0 || errno != EAGAIN) {
+	} else if (len == 0 || (len < 0 && (!sockerr_again() || gjc->ssl))) {
 		STATE_EVT(JCONN_STATE_OFF)
 	}
@@ -1856,9 +1856,5 @@
 			xmlnode_insert_cdata(y, "away", -1);
 			y = xmlnode_insert_tag(x, "status");
-			{
-				char *utf8 = str_to_utf8(message);
-				xmlnode_insert_cdata(y, utf8, -1);
-				g_free(utf8);
-			}
+			xmlnode_insert_cdata(y, message, -1);
 			gc->away = "";
 		} else {
Index: protocols/msn/msn.c
===================================================================
--- protocols/msn/msn.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/msn/msn.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -84,4 +84,6 @@
 		{
 			m = l->data;
+		
+			serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message to %s, you'll have to resend it.", m->who );
 			g_free( m->who );
 			g_free( m->text );
@@ -89,6 +91,4 @@
 		}
 		g_slist_free( md->msgq );
-		
-		serv_got_crap( gc, "Warning: Closing down MSN connection with unsent message(s), you'll have to resend them." );
 	}
 	
@@ -170,5 +170,5 @@
 	
 	for( i = 0; msn_away_state_list[i].number > -1; i ++ )
-		l = g_list_append( l, msn_away_state_list[i].name );
+		l = g_list_append( l, (void*) msn_away_state_list[i].name );
 	
 	return( l );
@@ -177,8 +177,8 @@
 static char *msn_get_status_string( struct gaim_connection *gc, int number )
 {
-	struct msn_away_state *st = msn_away_state_by_number( number );
+	const struct msn_away_state *st = msn_away_state_by_number( number );
 	
 	if( st )
-		return( st->name );
+		return( (char*) st->name );
 	else
 		return( "" );
@@ -189,5 +189,5 @@
 	char buf[1024];
 	struct msn_data *md = gc->proto_data;
-	struct msn_away_state *st;
+	const struct msn_away_state *st;
 	
 	if( strcmp( state, GAIM_AWAY_CUSTOM ) == 0 )
Index: protocols/msn/msn.h
===================================================================
--- protocols/msn/msn.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/msn/msn.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -67,5 +67,5 @@
 	GSList *switchboards;
 	int buddycount;
-	struct msn_away_state *away_state;
+	const struct msn_away_state *away_state;
 };
 
@@ -131,6 +131,6 @@
 
 int msn_chat_id;
-extern struct msn_away_state msn_away_state_list[];
-extern struct msn_status_code msn_status_code_list[];
+extern const struct msn_away_state msn_away_state_list[];
+extern const struct msn_status_code msn_status_code_list[];
 
 /* Keep a list of all the active connections. We need these lists because
@@ -156,8 +156,8 @@
 
 /* tables.c */
-struct msn_away_state *msn_away_state_by_number( int number );
-struct msn_away_state *msn_away_state_by_code( char *code );
-struct msn_away_state *msn_away_state_by_name( char *name );
-struct msn_status_code *msn_status_by_number( int number );
+const struct msn_away_state *msn_away_state_by_number( int number );
+const struct msn_away_state *msn_away_state_by_code( char *code );
+const struct msn_away_state *msn_away_state_by_name( char *name );
+const struct msn_status_code *msn_status_by_number( int number );
 
 /* sb.c */
Index: protocols/msn/ns.c
===================================================================
--- protocols/msn/ns.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/msn/ns.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -365,5 +365,5 @@
 	else if( strcmp( cmd[0], "ILN" ) == 0 )
 	{
-		struct msn_away_state *st;
+		const struct msn_away_state *st;
 		
 		if( num_parts != 6 )
@@ -393,5 +393,5 @@
 	else if( strcmp( cmd[0], "NLN" ) == 0 )
 	{
-		struct msn_away_state *st;
+		const struct msn_away_state *st;
 		
 		if( num_parts != 5 )
@@ -539,5 +539,5 @@
 	{
 		int num = atoi( cmd[0] );
-		struct msn_status_code *err = msn_status_by_number( num );
+		const struct msn_status_code *err = msn_status_by_number( num );
 		
 		g_snprintf( buf, sizeof( buf ), "Error reported by MSN server: %s", err->text );
Index: protocols/msn/sb.c
===================================================================
--- protocols/msn/sb.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/msn/sb.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -213,4 +213,5 @@
 		{
 			m = l->data;
+
 			g_free( m->who );
 			g_free( m->text );
@@ -219,5 +220,7 @@
 		g_slist_free( sb->msgq );
 		
-		serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with unsent message(s), you'll have to resend them." );
+		serv_got_crap( gc, "Warning: Closing down MSN switchboard connection with "
+		                   "unsent message to %s, you'll have to resend it.",
+		                   m->who ? m->who : "(unknown)" );
 	}
 	
@@ -512,5 +515,5 @@
 	{
 		int num = atoi( cmd[0] );
-		struct msn_status_code *err = msn_status_by_number( num );
+		const struct msn_status_code *err = msn_status_by_number( num );
 		
 		g_snprintf( buf, sizeof( buf ), "Error reported by switchboard server: %s", err->text );
Index: protocols/msn/tables.c
===================================================================
--- protocols/msn/tables.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/msn/tables.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -27,5 +27,5 @@
 #include "msn.h"
 
-struct msn_away_state msn_away_state_list[] =
+const struct msn_away_state msn_away_state_list[] =
 {
 	{  0, "NLN", "Available" },
@@ -40,5 +40,5 @@
 };
 
-struct msn_away_state *msn_away_state_by_number( int number )
+const struct msn_away_state *msn_away_state_by_number( int number )
 {
 	int i;
@@ -51,5 +51,5 @@
 }
 
-struct msn_away_state *msn_away_state_by_code( char *code )
+const struct msn_away_state *msn_away_state_by_code( char *code )
 {
 	int i;
@@ -62,5 +62,5 @@
 }
 
-struct msn_away_state *msn_away_state_by_name( char *name )
+const struct msn_away_state *msn_away_state_by_name( char *name )
 {
 	int i;
@@ -73,5 +73,5 @@
 }
 
-struct msn_status_code msn_status_code_list[] =
+const struct msn_status_code msn_status_code_list[] =
 {
 	{ 200, "Invalid syntax",                                        0 },
@@ -144,5 +144,5 @@
 };
 
-struct msn_status_code *msn_status_by_number( int number )
+const struct msn_status_code *msn_status_by_number( int number )
 {
 	static struct msn_status_code *unknown = NULL;
Index: protocols/nogaim.h
===================================================================
--- protocols/nogaim.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/nogaim.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -288,9 +288,6 @@
 G_MODULE_EXPORT void serv_got_chat_in( struct gaim_connection *gc, int id, char *who, int whisper, char *msg, time_t mtime );
 G_MODULE_EXPORT void serv_got_chat_left( struct gaim_connection *gc, int id );
-/* void serv_finish_login( struct gaim_connection *gc ); */
 
 /* util.c */
-G_MODULE_EXPORT char *utf8_to_str( const char *in );
-G_MODULE_EXPORT char *str_to_utf8( const char *in );
 G_MODULE_EXPORT void strip_linefeed( gchar *text );
 G_MODULE_EXPORT char *add_cr( char *text );
@@ -299,6 +296,8 @@
 G_MODULE_EXPORT time_t get_time( int year, int month, int day, int hour, int min, int sec );
 G_MODULE_EXPORT void strip_html( char *msg );
-G_MODULE_EXPORT char * escape_html(const char *html);
+G_MODULE_EXPORT char *escape_html( const char *html );
 G_MODULE_EXPORT void info_string_append(GString *str, char *newline, char *name, char *value);
+G_MODULE_EXPORT char *ipv6_wrap( char *src );
+G_MODULE_EXPORT char *ipv6_unwrap( char *src );
 
 /* prefs.c */
Index: protocols/oscar/oscar.c
===================================================================
--- protocols/oscar/oscar.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/oscar/oscar.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -21,5 +21,4 @@
  */
 
-#include "sock.h"
 #include <errno.h>
 #include <ctype.h>
@@ -33,4 +32,5 @@
 #include "bitlbee.h"
 #include "proxy.h"
+#include "sock.h"
 
 #include "aim.h"
@@ -608,4 +608,5 @@
 		return;
 	}
+	/* [WvG] Wheeeee! Who needs error checking anyway? ;-) */
 	read(pos->fd, m, 16);
 	m[16] = '\0';
Index: protocols/oscar/rxqueue.c
===================================================================
--- protocols/oscar/rxqueue.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/oscar/rxqueue.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -353,6 +353,13 @@
 		return -1; /* its a aim_conn_close()'d connection */
 
-	if (conn->fd < 3)  /* can happen when people abuse the interface */
+	/* KIDS, THIS IS WHAT HAPPENS IF YOU USE CODE WRITTEN FOR GUIS IN A DAEMON!
+	   
+	   And wouldn't it make sense to return something that prevents this function
+	   from being called again IMMEDIATELY (and making the program suck up all
+	   CPU time)?...
+	   
+	if (conn->fd < 3)
 		return 0;
+	*/
 
 	if (conn->status & AIM_CONN_STATUS_INPROGRESS)
Index: protocols/oscar/service.c
===================================================================
--- protocols/oscar/service.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/oscar/service.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -736,6 +736,4 @@
 
 	tlvlen = aim_addtlvtochain32(&tl, 0x0006, data);
-
-	printf("%d\n", tlvlen);
 
 	if (!(fr = aim_tx_new(sess, conn, AIM_FRAMETYPE_FLAP, 0x02, 10 + 8)))
Index: protocols/ssl_bogus.c
===================================================================
--- protocols/ssl_bogus.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/ssl_bogus.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -51,2 +51,7 @@
 	return( -1 );
 }
+
+GaimInputCondition ssl_getdirection( void *conn )
+{
+	return GAIM_INPUT_READ;
+}
Index: protocols/ssl_openssl.c
===================================================================
--- protocols/ssl_openssl.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/ssl_openssl.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -5,5 +5,5 @@
   \********************************************************************/
 
-/* SSL module - GnuTLS version                                          */
+/* SSL module - OpenTLS version                                          */
 
 /*
@@ -41,11 +41,9 @@
 struct scd
 {
-	ssl_input_function func;
+	SslInputFunction func;
 	gpointer data;
 	int fd;
 	gboolean established;
 	
-	int inpa;
-	int lasterr;		/* Necessary for SSL_get_error */
 	SSL *ssl;
 	SSL_CTX *ssl_ctx;
@@ -56,5 +54,5 @@
 
 
-void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
+void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data )
 {
 	struct scd *conn = g_new0( struct scd, 1 );
@@ -95,6 +93,4 @@
 }
 
-static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond );
-
 static void ssl_connected( gpointer data, gint source, GaimInputCondition cond )
 {
@@ -102,36 +98,12 @@
 	
 	if( source == -1 )
-		return ssl_handshake( data, -1, cond );
+		goto ssl_connected_failure;
 	
-	/* Make it non-blocking at least during the handshake... */
-	sock_make_nonblocking( conn->fd );
 	SSL_set_fd( conn->ssl, conn->fd );
 	
-	return ssl_handshake( data, source, cond );
-}	
-
-static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )
-{
-	struct scd *conn = data;
-	int st;
-	
-	if( conn->inpa != -1 )
-	{
-		gaim_input_remove( conn->inpa );
-		conn->inpa = -1;
-	}
-	
-	if( ( st = SSL_connect( conn->ssl ) ) < 0 )
-	{
-		conn->lasterr = SSL_get_error( conn->ssl, st );
-		if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
-			goto ssl_connected_failure;
-		
-		conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
-		return;
-	}
+	if( SSL_connect( conn->ssl ) < 0 )
+		goto ssl_connected_failure;
 	
 	conn->established = TRUE;
-	sock_make_blocking( conn->fd );		/* For now... */
 	conn->func( conn->data, conn, cond );
 	return;
@@ -155,46 +127,16 @@
 int ssl_read( void *conn, char *buf, int len )
 {
-	int st;
+	if( !((struct scd*)conn)->established )
+		return( 0 );
 	
-	if( !((struct scd*)conn)->established )
-	{
-		ssl_errno = SSL_NOHANDSHAKE;
-		return -1;
-	}
-	
-	st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
-	
-	ssl_errno = SSL_OK;
-	if( st <= 0 )
-	{
-		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
-		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
-			ssl_errno = SSL_AGAIN;
-	}
-	
-	return st;
+	return( SSL_read( ((struct scd*)conn)->ssl, buf, len ) );
 }
 
 int ssl_write( void *conn, const char *buf, int len )
 {
-	int st;
+	if( !((struct scd*)conn)->established )
+		return( 0 );
 	
-	if( !((struct scd*)conn)->established )
-	{
-		ssl_errno = SSL_NOHANDSHAKE;
-		return -1;
-	}
-	
-	st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
-	
-	ssl_errno = SSL_OK;
-	if( st <= 0 )
-	{
-		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
-		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
-			ssl_errno = SSL_AGAIN;
-	}
-	
-	return st;
+	return( SSL_write( ((struct scd*)conn)->ssl, buf, len ) );
 }
 
@@ -202,7 +144,4 @@
 {
 	struct scd *conn = conn_;
-	
-	if( conn->inpa != -1 )
-		gaim_input_remove( conn->inpa );
 	
 	if( conn->established )
@@ -220,7 +159,2 @@
 	return( ((struct scd*)conn)->fd );
 }
-
-GaimInputCondition ssl_getdirection( void *conn )
-{
-	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ );
-}
Index: otocols/util.c
===================================================================
--- protocols/util.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ 	(revision )
@@ -1,413 +1,0 @@
-  /********************************************************************\
-  * BitlBee -- An IRC to other IM-networks gateway                     *
-  *                                                                    *
-  * Copyright 2002-2004 Wilmer van der Gaast and others                *
-  \********************************************************************/
-
-/*
- * nogaim
- *
- * Gaim without gaim - for BitlBee
- *
- * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
- *                          (and possibly other members of the Gaim team)
- * Copyright 2002-2004 Wilmer van der Gaast <lintux@lintux.cx>
- */
-
-/*
-  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
-*/
-
-/* Parts from util.c from gaim needed by nogaim */
-#define BITLBEE_CORE
-#include "nogaim.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-#include <time.h>
-
-char *utf8_to_str(const char *in)
-{
-	int n = 0, i = 0;
-	int inlen;
-	char *result;
-
-	if (!in)
-		return NULL;
-
-	inlen = strlen(in);
-
-	result = g_malloc(inlen + 1);
-
-	while (n <= inlen - 1) {
-		long c = (long)in[n];
-		if (c < 0x80)
-			result[i++] = (char)c;
-		else {
-			if ((c & 0xC0) == 0xC0)
-				result[i++] =
-				    (char)(((c & 0x03) << 6) | (((unsigned char)in[++n]) & 0x3F));
-			else if ((c & 0xE0) == 0xE0) {
-				if (n + 2 <= inlen) {
-					result[i] =
-					    (char)(((c & 0xF) << 4) | (((unsigned char)in[++n]) & 0x3F));
-					result[i] =
-					    (char)(((unsigned char)result[i]) |
-						   (((unsigned char)in[++n]) & 0x3F));
-					i++;
-				} else
-					n += 2;
-			} else if ((c & 0xF0) == 0xF0)
-				n += 3;
-			else if ((c & 0xF8) == 0xF8)
-				n += 4;
-			else if ((c & 0xFC) == 0xFC)
-				n += 5;
-		}
-		n++;
-	}
-	result[i] = '\0';
-
-	return result;
-}
-
-char *str_to_utf8(const char *in)
-{
-	int n = 0, i = 0;
-	int inlen;
-	char *result = NULL;
-
-	if (!in)
-		return NULL;
-
-	inlen = strlen(in);
-
-	result = g_malloc(inlen * 2 + 1);
-
-	while (n < inlen) {
-		long c = (long)in[n];
-		if (c == 27) {
-			n += 2;
-			if (in[n] == 'x')
-				n++;
-			if (in[n] == '3')
-				n++;
-			n += 2;
-			continue;
-		}
-		/* why are we removing newlines and carriage returns?
-		if ((c == 0x0D) || (c == 0x0A)) {
-			n++;
-			continue;
-		}
-		*/
-		if (c < 128)
-			result[i++] = (char)c;
-		else {
-			result[i++] = (char)((c >> 6) | 192);
-			result[i++] = (char)((c & 63) | 128);
-		}
-		n++;
-	}
-	result[i] = '\0';
-
-	return result;
-}
-
-void strip_linefeed(gchar *text)
-{
-	int i, j;
-	gchar *text2 = g_malloc(strlen(text) + 1);
-
-	for (i = 0, j = 0; text[i]; i++)
-		if (text[i] != '\r')
-			text2[j++] = text[i];
-	text2[j] = '\0';
-
-	strcpy(text, text2);
-	g_free(text2);
-}
-
-char *add_cr(char *text)
-{
-	char *ret = NULL;
-	int count = 0, j;
-	unsigned int i;
-
-	if (text[0] == '\n')
-		count++;
-	for (i = 1; i < strlen(text); i++)
-		if (text[i] == '\n' && text[i - 1] != '\r')
-			count++;
-
-	if (count == 0)
-		return g_strdup(text);
-
-	ret = g_malloc0(strlen(text) + count + 1);
-
-	i = 0; j = 0;
-	if (text[i] == '\n')
-		ret[j++] = '\r';
-	ret[j++] = text[i++];
-	for (; i < strlen(text); i++) {
-		if (text[i] == '\n' && text[i - 1] != '\r')
-			ret[j++] = '\r';
-		ret[j++] = text[i];
-	}
-
-	return ret;
-}
-
-static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/";
-
-/* XXX Find bug */
-char *tobase64(const char *text)
-{
-	char *out = NULL;
-	const char *c;
-	unsigned int tmp = 0;
-	int len = 0, n = 0;
-
-	c = text;
-
-	while (*c) {
-		tmp = tmp << 8;
-		tmp += *c;
-		n++;
-
-		if (n == 3) {
-			out = g_realloc(out, len + 4);
-			out[len] = alphabet[(tmp >> 18) & 0x3f];
-			out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
-			out[len + 2] = alphabet[(tmp >> 6) & 0x3f];
-			out[len + 3] = alphabet[tmp & 0x3f];
-			len += 4;
-			tmp = 0;
-			n = 0;
-		}
-		c++;
-	}
-	switch (n) {
-
-	case 2:
-		tmp <<= 8;
-		out = g_realloc(out, len + 5);
-		out[len] = alphabet[(tmp >> 18) & 0x3f];
-		out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
-		out[len + 2] = alphabet[(tmp >> 6) & 0x3f];
-		out[len + 3] = '=';
-		out[len + 4] = 0;
-		break;
-	case 1:
-		tmp <<= 16;
-		out = g_realloc(out, len + 5);
-		out[len] = alphabet[(tmp >> 18) & 0x3f];
-		out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
-		out[len + 2] = '=';
-		out[len + 3] = '=';
-		out[len + 4] = 0;
-		break;
-	case 0:
-		out = g_realloc(out, len + 1);
-		out[len] = 0;
-		break;
-	}
-	return out;
-}
-
-char *normalize(const char *s)
-{
-	static char buf[BUF_LEN];
-	char *t, *u;
-	int x = 0;
-
-	g_return_val_if_fail((s != NULL), NULL);
-
-	u = t = g_strdup(s);
-
-	strcpy(t, s);
-	g_strdown(t);
-
-	while (*t && (x < BUF_LEN - 1)) {
-		if (*t != ' ') {
-			buf[x] = *t;
-			x++;
-		}
-		t++;
-	}
-	buf[x] = '\0';
-	g_free(u);
-	return buf;
-}
-
-time_t get_time(int year, int month, int day, int hour, int min, int sec)
-{
-	struct tm tm;
-
-	tm.tm_year = year - 1900;
-	tm.tm_mon = month - 1;
-	tm.tm_mday = day;
-	tm.tm_hour = hour;
-	tm.tm_min = min;
-	tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60;
-	return mktime(&tm);
-}
-
-typedef struct htmlentity
-{
-	char code[8];
-	char is;
-} htmlentity_t;
-
-/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */
-
-static htmlentity_t ent[] =
-{
-	{ "lt",     '<' },
-	{ "gt",     '>' },
-	{ "amp",    '&' },
-	{ "quot",   '"' },
-	{ "aacute", 'á' },
-	{ "eacute", 'é' },
-	{ "iacute", 'é' },
-	{ "oacute", 'ó' },
-	{ "uacute", 'ú' },
-	{ "agrave", 'à' },
-	{ "egrave", 'è' },
-	{ "igrave", 'ì' },
-	{ "ograve", 'ò' },
-	{ "ugrave", 'ù' },
-	{ "acirc",  'â' },
-	{ "ecirc",  'ê' },
-	{ "icirc",  'î' },
-	{ "ocirc",  'ô' },
-	{ "ucirc",  'û' },
-	{ "nbsp",   ' ' },
-	{ "",        0  }
-};
-
-void strip_html( char *in )
-{
-	char *start = in;
-	char *out = g_malloc( strlen( in ) + 1 );
-	char *s = out, *cs;
-	int i, matched;
-	
-	memset( out, 0, strlen( in ) + 1 );
-	
-	while( *in )
-	{
-		if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) )
-		{
-			/* If in points at a < and in+1 points at a letter or a slash, this is probably
-			   a HTML-tag. Try to find a closing > and continue there. If the > can't be
-			   found, assume that it wasn't a HTML-tag after all. */
-			
-			cs = in;
-			
-			while( *in && *in != '>' )
-				in ++;
-			
-			if( *in )
-			{
-				if( g_strncasecmp( cs+1, "br", 2) == 0 )
-					*(s++) = '\n';
-				in ++;
-			}
-			else
-			{
-				in = cs;
-				*(s++) = *(in++);
-			}
-		}
-		else if( *in == '&' )
-		{
-			cs = ++in;
-			while( *in && isalpha( *in ) )
-				in ++;
-			
-			if( *in == ';' ) in ++;
-			matched = 0;
-			
-			for( i = 0; *ent[i].code; i ++ )
-				if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 )
-				{
-					*(s++) = ent[i].is;
-					matched = 1;
-					break;
-				}
-
-			/* None of the entities were matched, so return the string */
-			if( !matched )
-			{
-				in = cs - 1;
-				*(s++) = *(in++);
-			}
-		}
-		else
-		{
-			*(s++) = *(in++);
-		}
-	}
-	
-	strcpy( start, out );
-	g_free( out );
-}
-
-char *escape_html( const char *html )
-{
-	const char *c = html;
-	GString *ret;
-	char *str;
-	
-	if( html == NULL )
-		return( NULL );
-	
-	ret = g_string_new( "" );
-	
-	while( *c )
-	{
-		switch( *c )
-		{
-			case '&':
-				ret = g_string_append( ret, "&amp;" );
-				break;
-			case '<':
-				ret = g_string_append( ret, "&lt;" );
-				break;
-			case '>':
-				ret = g_string_append( ret, "&gt;" );
-				break;
-			case '"':
-				ret = g_string_append( ret, "&quot;" );
-				break;
-			default:
-				ret = g_string_append_c( ret, *c );
-		}
-		c ++;
-	}
-	
-	str = ret->str;
-	g_string_free( ret, FALSE );
-	return( str );
-}
-
-void info_string_append(GString *str, char *newline, char *name, char *value)
-{
-	if( value && value[0] )
-		g_string_sprintfa( str, "%s%s: %s", newline, name, value );
-}
Index: protocols/yahoo/Makefile
===================================================================
--- protocols/yahoo/Makefile	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/yahoo/Makefile	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -10,5 +10,5 @@
 
 # [SH] Program variables
-objects = yahoo.o crypt.o libyahoo2.o yahoo_fn.o yahoo_httplib.o yahoo_list.o yahoo_util.o
+objects = yahoo.o crypt.o libyahoo2.o yahoo_fn.o yahoo_httplib.o yahoo_util.o
 
 CFLAGS += -Wall -DSTDC_HEADERS -DHAVE_STRING_H -DHAVE_STRCHR -DHAVE_MEMCPY -DHAVE_GLIB
Index: protocols/yahoo/yahoo.c
===================================================================
--- protocols/yahoo/yahoo.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/yahoo/yahoo.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -189,16 +189,16 @@
 {
 	struct byahoo_data *yd = (struct byahoo_data *) gc->proto_data;
-
+	
 	gc->away = NULL;
-
-	if (msg)
+	
+	if( msg )
 	{
 		yd->current_status = YAHOO_STATUS_CUSTOM;
 		gc->away = "";
 	}
-	else if (state)
+	if( state )
 	{
 		gc->away = "";
-		if( g_strcasecmp(state, "Available" ) == 0 )
+		if( g_strcasecmp( state, "Available" ) == 0 )
 		{
 			yd->current_status = YAHOO_STATUS_AVAILABLE;
@@ -235,10 +235,13 @@
 		}
 	}
-	else if ( gc->is_idle )
+	else if( gc->is_idle )
 		yd->current_status = YAHOO_STATUS_IDLE;
 	else
 		yd->current_status = YAHOO_STATUS_AVAILABLE;
 	
-	yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL );
+	if( yd->current_status == YAHOO_STATUS_INVISIBLE )
+		yahoo_set_away( yd->y2_id, yd->current_status, NULL, gc->away != NULL );
+	else
+		yahoo_set_away( yd->y2_id, yd->current_status, msg, gc->away != NULL );
 }
 
Index: protocols/yahoo/yahoo_fn.c
===================================================================
--- protocols/yahoo/yahoo_fn.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/yahoo/yahoo_fn.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -25,5 +25,5 @@
 #include "yahoo_fn.h"
 
-unsigned char table_0[256] = {
+static const unsigned char table_0[256] = {
    0x5A, 0x41, 0x11, 0x77, 0x29, 0x9C, 0x31, 0xAD,
    0x4A, 0x32, 0x1A, 0x6D, 0x56, 0x9F, 0x39, 0xA6,
@@ -59,5 +59,5 @@
    0x7B, 0xBE, 0xF9, 0xAF, 0x82, 0x63, 0x47, 0x23 };
 
-unsigned char table_1[256] = {
+static const unsigned char table_1[256] = {
    0x08, 0xCB, 0x54, 0xCF, 0x97, 0x53, 0x59, 0xF1,
    0x66, 0xEC, 0xDB, 0x1B, 0xB1, 0xE2, 0x36, 0xEB,
@@ -93,5 +93,5 @@
    0x05, 0x95, 0xBB, 0x79, 0x61, 0x3E, 0x81, 0xF7 };
 
-unsigned char table_2[32] = {
+static const unsigned char table_2[32] = {
    0x19, 0x05, 0x09, 0x1C, 0x0B, 0x1A, 0x12, 0x03,
    0x06, 0x04, 0x0D, 0x1D, 0x15, 0x0E, 0x1B, 0x18,
@@ -99,5 +99,5 @@
    0x16, 0x0A, 0x10, 0x0F, 0x01, 0x14, 0x11, 0x17 };
 
-unsigned char table_3[256] = {
+static const unsigned char table_3[256] = {
    0xBC, 0x1B, 0xCC, 0x1E, 0x5B, 0x59, 0x4F, 0xA8,
    0x62, 0xC6, 0xC1, 0xBB, 0x83, 0x2D, 0xA3, 0xA6,
@@ -133,5 +133,5 @@
    0x7C, 0xEF, 0xE0, 0x99, 0x09, 0xA0, 0x01, 0x7E };
 
-unsigned char table_4[32] = {
+static const unsigned char table_4[32] = {
    0x1F, 0x0B, 0x00, 0x1E, 0x03, 0x0E, 0x15, 0x01,
    0x1A, 0x17, 0x1D, 0x1B, 0x11, 0x0F, 0x0A, 0x12,
@@ -139,5 +139,5 @@
    0x08, 0x05, 0x10, 0x19, 0x0C, 0x14, 0x16, 0x1C };
 
-unsigned char table_5[256] = {
+static const unsigned char table_5[256] = {
    0x9A, 0xAB, 0x61, 0x28, 0x0A, 0x23, 0xFC, 0xBA,
    0x90, 0x22, 0xB7, 0x62, 0xD9, 0x09, 0x91, 0xF4,
@@ -173,5 +173,5 @@
    0x46, 0x73, 0x69, 0xD5, 0x10, 0xEE, 0x02, 0xEF };
 
-unsigned char table_6[32] = {
+static const unsigned char table_6[32] = {
    0x1A, 0x1C, 0x0F, 0x0C, 0x00, 0x02, 0x13, 0x09,
    0x11, 0x05, 0x0D, 0x12, 0x18, 0x0B, 0x04, 0x10,
@@ -179,5 +179,5 @@
    0x19, 0x1F, 0x01, 0x0E, 0x15, 0x06, 0x0A, 0x1D };
 
-unsigned char table_7[256] = {
+static const unsigned char table_7[256] = {
    0x52, 0x11, 0x72, 0xD0, 0x76, 0xD7, 0xAE, 0x03,
    0x7F, 0x19, 0xF4, 0xB8, 0xB3, 0x5D, 0xCA, 0x2D,
@@ -213,5 +213,5 @@
    0x88, 0x9E, 0x9C, 0x5B, 0x4D, 0x3A, 0x39, 0xEF };
 
-unsigned char table_8[32] = {
+static const unsigned char table_8[32] = {
    0x13, 0x08, 0x1E, 0x1D, 0x17, 0x16, 0x07, 0x1F,
    0x0E, 0x03, 0x1A, 0x19, 0x01, 0x12, 0x11, 0x10,
@@ -219,5 +219,5 @@
    0x1C, 0x18, 0x0A, 0x15, 0x02, 0x1B, 0x06, 0x0D };
 
-unsigned char table_9[256] = {
+static const unsigned char table_9[256] = {
    0x20, 0x2A, 0xDA, 0xFE, 0x76, 0x0D, 0xED, 0x39,
    0x51, 0x4C, 0x46, 0x9A, 0xF1, 0xB0, 0x10, 0xC7,
@@ -253,5 +253,5 @@
    0xF9, 0xF0, 0x2C, 0x74, 0xE9, 0x71, 0xC0, 0x2D };
 
-unsigned char table_10[32] = {
+static const unsigned char table_10[32] = {
    0x1D, 0x12, 0x11, 0x0D, 0x1E, 0x19, 0x16, 0x1B,
    0x18, 0x13, 0x07, 0x17, 0x0C, 0x02, 0x00, 0x15,
@@ -259,5 +259,5 @@
    0x1F, 0x1A, 0x0B, 0x09, 0x0A, 0x14, 0x1C, 0x03 };
 
-unsigned char table_11[256] = {
+static const unsigned char table_11[256] = {
    0x6B, 0x1D, 0xC6, 0x0A, 0xB7, 0xAC, 0xB2, 0x11,
    0x29, 0xD3, 0xA2, 0x4D, 0xCB, 0x03, 0xEF, 0xA6,
@@ -293,5 +293,5 @@
    0x64, 0x76, 0xFF, 0x9F, 0x2E, 0x02, 0xCC, 0x57 };
 
-unsigned char table_12[32] = {
+static const unsigned char table_12[32] = {
    0x14, 0x1B, 0x18, 0x00, 0x1F, 0x15, 0x17, 0x07,
    0x11, 0x1A, 0x0E, 0x13, 0x12, 0x06, 0x01, 0x03,
@@ -299,5 +299,5 @@
    0x0D, 0x1E, 0x04, 0x05, 0x08, 0x16, 0x0A, 0x02 };
 
-unsigned char table_13[256] = {
+static const unsigned char table_13[256] = {
    0x37, 0x8A, 0x1B, 0x91, 0xA5, 0x2B, 0x2D, 0x88,
    0x8E, 0xFE, 0x0E, 0xD3, 0xF3, 0xE9, 0x7D, 0xD1,
@@ -333,5 +333,5 @@
    0x97, 0x4A, 0xB8, 0x7A, 0xF4, 0xFB, 0x04, 0xA8 };
 
-unsigned char table_14[32] = {
+static const unsigned char table_14[32] = {
    0x04, 0x14, 0x13, 0x15, 0x1A, 0x1B, 0x0F, 0x16,
    0x02, 0x0D, 0x0C, 0x06, 0x10, 0x17, 0x01, 0x0B,
@@ -339,5 +339,5 @@
    0x11, 0x09, 0x1D, 0x07, 0x0E, 0x12, 0x03, 0x00 };
 
-unsigned char table_15[256] = {
+static const unsigned char table_15[256] = {
    0x61, 0x48, 0x58, 0x41, 0x7F, 0x88, 0x43, 0x42,
    0xD9, 0x80, 0x81, 0xFE, 0xC6, 0x49, 0xD7, 0x2C,
@@ -373,5 +373,5 @@
    0xAB, 0x8D, 0x02, 0x74, 0xBD, 0x3D, 0x8E, 0xDD };
 
-unsigned char table_16[256] = {
+static const unsigned char table_16[256] = {
    0x3F, 0x9C, 0x17, 0xC1, 0x59, 0xC6, 0x23, 0x93,
    0x4B, 0xDF, 0xCB, 0x55, 0x2B, 0xDE, 0xCD, 0xAD,
@@ -407,5 +407,5 @@
    0xF4, 0xBE, 0xEA, 0x19, 0x43, 0x01, 0xB1, 0x96 };
 
-unsigned char table_17[256] = {
+static const unsigned char table_17[256] = {
    0x7E, 0xF1, 0xD3, 0x75, 0x87, 0xA6, 0xED, 0x9E,
    0xA9, 0xD5, 0xC6, 0xBF, 0xE6, 0x6A, 0xEE, 0x4B,
@@ -441,5 +441,5 @@
    0x9F, 0x99, 0x62, 0xAA, 0xFA, 0x11, 0x0C, 0x52 };
 
-unsigned char table_18[256] = {
+static const unsigned char table_18[256] = {
    0x0F, 0x42, 0x3D, 0x86, 0x3E, 0x66, 0xFE, 0x5C,
    0x52, 0xE2, 0xA3, 0xB3, 0xCE, 0x16, 0xCC, 0x95,
@@ -475,5 +475,5 @@
    0xFA, 0x4E, 0xEF, 0x54, 0xE6, 0x7F, 0xC0, 0x67 };
 
-unsigned char table_19[256] = {
+static const unsigned char table_19[256] = {
    0xEA, 0xE7, 0x13, 0x14, 0xB9, 0xC0, 0xC4, 0x42,
    0x49, 0x6E, 0x2A, 0xA6, 0x65, 0x3C, 0x6A, 0x40,
@@ -509,5 +509,5 @@
    0x1E, 0x0D, 0xAE, 0x7B, 0x5E, 0x61, 0xE9, 0x63 };
 
-unsigned char table_20[32] = {
+static const unsigned char table_20[32] = {
    0x0D, 0x0B, 0x11, 0x02, 0x05, 0x1B, 0x08, 0x1D,
    0x04, 0x14, 0x01, 0x09, 0x00, 0x19, 0x1E, 0x15,
@@ -515,5 +515,5 @@
    0x13, 0x1A, 0x06, 0x17, 0x0E, 0x12, 0x18, 0x03 };
 
-unsigned char table_21[256] = {
+static const unsigned char table_21[256] = {
    0x4C, 0x94, 0xAD, 0x66, 0x9E, 0x69, 0x04, 0xA8,
    0x61, 0xE0, 0xE1, 0x3D, 0xFD, 0x9C, 0xFB, 0x19,
@@ -549,5 +549,5 @@
    0xFF, 0xD8, 0xE7, 0xDD, 0xBB, 0x78, 0xD5, 0x81 };
 
-unsigned char table_22[32] = {
+static const unsigned char table_22[32] = {
    0x0B, 0x15, 0x1C, 0x0C, 0x06, 0x0A, 0x1D, 0x16,
    0x12, 0x0E, 0x04, 0x11, 0x1F, 0x0F, 0x07, 0x02,
@@ -555,5 +555,5 @@
    0x03, 0x00, 0x01, 0x08, 0x09, 0x14, 0x1B, 0x1E };
 
-unsigned char table_23[256] = {
+static const unsigned char table_23[256] = {
    0x36, 0x53, 0x2D, 0xD0, 0x7A, 0xF0, 0xD5, 0x1C,
    0x50, 0x61, 0x9A, 0x90, 0x0B, 0x29, 0x20, 0x77,
@@ -589,5 +589,5 @@
    0x1D, 0x15, 0xC6, 0xBF, 0xA9, 0x43, 0xC0, 0x49 };
 
-unsigned char table_24[256] = {
+static const unsigned char table_24[256] = {
    0xDC, 0x5A, 0xE6, 0x59, 0x64, 0xDA, 0x58, 0x40,
    0x95, 0xF8, 0x2A, 0xE0, 0x39, 0x7E, 0x32, 0x89,
@@ -623,5 +623,5 @@
    0xEA, 0x8D, 0x2D, 0x5F, 0xF6, 0xA7, 0x80, 0x3A };
 
-unsigned char table_25[32] = {
+static const unsigned char table_25[32] = {
    0x0A, 0x11, 0x17, 0x03, 0x05, 0x0B, 0x18, 0x13,
    0x09, 0x02, 0x00, 0x1C, 0x0C, 0x08, 0x1B, 0x14,
@@ -629,5 +629,5 @@
    0x0F, 0x1A, 0x10, 0x04, 0x12, 0x15, 0x07, 0x1F };
 
-unsigned char table_26[32] = {
+static const unsigned char table_26[32] = {
    0x19, 0x13, 0x1B, 0x01, 0x1C, 0x0D, 0x0C, 0x15,
    0x0B, 0x00, 0x1A, 0x0F, 0x12, 0x16, 0x08, 0x0A,
@@ -635,5 +635,5 @@
    0x1F, 0x07, 0x17, 0x05, 0x02, 0x0E, 0x1E, 0x09 };
 
-unsigned char table_27[256] = {
+static const unsigned char table_27[256] = {
    0x72, 0xF0, 0x14, 0xCB, 0x61, 0xA5, 0xB2, 0x02,
    0x75, 0x22, 0xC3, 0x9D, 0x5A, 0x63, 0xFA, 0x5F,
@@ -669,5 +669,5 @@
    0x5E, 0x6F, 0x47, 0x64, 0xBC, 0x9A, 0x60, 0x7E };
 
-unsigned char table_28[32] = {
+static const unsigned char table_28[32] = {
    0x15, 0x05, 0x08, 0x19, 0x02, 0x18, 0x1E, 0x07,
    0x0D, 0x0C, 0x1A, 0x06, 0x17, 0x03, 0x10, 0x09,
@@ -675,5 +675,5 @@
    0x1B, 0x13, 0x0A, 0x16, 0x0E, 0x00, 0x1D, 0x14 };
 
-unsigned char table_29[256] = {
+static const unsigned char table_29[256] = {
    0x34, 0x59, 0x05, 0x13, 0x09, 0x1D, 0xDF, 0x77,
    0x11, 0xA5, 0x92, 0x27, 0xCD, 0x7B, 0x5E, 0x80,
@@ -709,5 +709,5 @@
    0x46, 0x62, 0xB6, 0xB0, 0x15, 0x04, 0x95, 0x4D };
 
-unsigned char table_30[32] = {
+static const unsigned char table_30[32] = {
    0x00, 0x1C, 0x0E, 0x0C, 0x06, 0x16, 0x09, 0x12,
    0x01, 0x13, 0x0B, 0x14, 0x11, 0x08, 0x04, 0x18,
@@ -715,5 +715,5 @@
    0x1E, 0x1F, 0x0F, 0x07, 0x0D, 0x05, 0x1D, 0x0A };
 
-unsigned char table_31[256] = {
+static const unsigned char table_31[256] = {
    0xDF, 0xD8, 0x3F, 0xBC, 0x5F, 0xC9, 0x8E, 0x4C,
    0x0B, 0x3C, 0xE5, 0xBF, 0x39, 0xD5, 0x30, 0xDD,
@@ -749,5 +749,5 @@
    0x92, 0x48, 0xF7, 0x0A, 0xF6, 0xE2, 0x4B, 0x56 };
 
-unsigned char table_32[256] = {
+static const unsigned char table_32[256] = {
    0x7B, 0x0F, 0x56, 0x2F, 0x1E, 0x2A, 0x7A, 0xD1,
    0x02, 0x91, 0x4E, 0x37, 0x6C, 0x10, 0xA7, 0xF2,
@@ -783,5 +783,5 @@
    0x47, 0x6B, 0x8A, 0xA2, 0x9A, 0xA3, 0x45, 0x41 };
 
-unsigned char table_33[256] = {
+static const unsigned char table_33[256] = {
    0xDE, 0xD3, 0x79, 0x67, 0x13, 0x5C, 0x04, 0xF2,
    0xD9, 0x9F, 0x65, 0x56, 0xCC, 0x3B, 0xA4, 0x9A,
@@ -817,5 +817,5 @@
    0x80, 0x3C, 0xEE, 0x47, 0xC6, 0x3A, 0x53, 0xF6 };
 
-unsigned char table_34[256] = {
+static const unsigned char table_34[256] = {
    0xF0, 0xE9, 0x3E, 0xD6, 0x89, 0xC8, 0xC7, 0x23,
    0x75, 0x26, 0x5F, 0x9C, 0x57, 0xB8, 0x2A, 0x29,
@@ -851,5 +851,5 @@
    0x03, 0x05, 0xBF, 0x06, 0x1B, 0xC0, 0x1A, 0x60 };
 
-unsigned char table_35[256] = {
+static const unsigned char table_35[256] = {
    0xCC, 0x40, 0xEF, 0x1F, 0xDB, 0xE5, 0x71, 0x51,
    0x3B, 0x0F, 0x7D, 0x9C, 0x83, 0x17, 0x6F, 0x8F,
@@ -885,5 +885,5 @@
    0x59, 0xC4, 0x9F, 0xD0, 0x66, 0x7B, 0x33, 0xB5 };
 
-unsigned char table_36[256] = {
+static const unsigned char table_36[256] = {
    0xDB, 0x6F, 0xFE, 0xB3, 0x5C, 0x1F, 0xB8, 0xBF,
    0xA3, 0x71, 0x11, 0x56, 0x90, 0xE2, 0x63, 0x18,
@@ -919,5 +919,5 @@
    0x4B, 0xB6, 0x7B, 0x4D, 0xCF, 0x7E, 0x48, 0xE3 };
 
-unsigned char table_37[256] = {
+static const unsigned char table_37[256] = {
    0x1F, 0xD6, 0xB1, 0xB3, 0x40, 0xAD, 0xDE, 0xB7,
    0x19, 0xB4, 0xE7, 0x0B, 0x9C, 0x2D, 0xE0, 0xF5,
@@ -953,5 +953,5 @@
    0x73, 0xC8, 0x86, 0x47, 0xDB, 0xAB, 0x6F, 0x8C };
 
-unsigned char table_38[256] = {
+static const unsigned char table_38[256] = {
    0xAA, 0x8D, 0x37, 0x94, 0x99, 0xDD, 0x70, 0x77,
    0x78, 0xC9, 0x0F, 0xFA, 0xE2, 0x05, 0xC2, 0x16,
@@ -987,5 +987,5 @@
    0x09, 0x76, 0x00, 0x46, 0x4E, 0x53, 0xCE, 0x4A };
 
-unsigned char table_39[32] = {
+static const unsigned char table_39[32] = {
    0x12, 0x18, 0x0E, 0x08, 0x16, 0x05, 0x06, 0x00,
    0x11, 0x17, 0x15, 0x1B, 0x14, 0x01, 0x1F, 0x19,
@@ -993,5 +993,5 @@
    0x0B, 0x13, 0x0C, 0x09, 0x1E, 0x02, 0x1A, 0x1C };
 
-unsigned char table_40[32] = {
+static const unsigned char table_40[32] = {
    0x16, 0x02, 0x06, 0x0E, 0x0D, 0x1C, 0x08, 0x0A,
    0x0F, 0x13, 0x0B, 0x18, 0x07, 0x04, 0x14, 0x01,
@@ -999,5 +999,5 @@
    0x12, 0x19, 0x1D, 0x03, 0x0C, 0x00, 0x09, 0x15 };
 
-unsigned char table_41[32] = {
+static const unsigned char table_41[32] = {
    0x13, 0x18, 0x04, 0x1F, 0x1D, 0x11, 0x03, 0x00,
    0x10, 0x12, 0x06, 0x0A, 0x1C, 0x07, 0x15, 0x0E,
@@ -1005,5 +1005,5 @@
    0x1A, 0x17, 0x14, 0x1E, 0x0D, 0x0F, 0x19, 0x1B };
 
-unsigned char table_42[32] = {
+static const unsigned char table_42[32] = {
    0x00, 0x08, 0x15, 0x1D, 0x05, 0x18, 0x06, 0x07,
    0x1F, 0x01, 0x0B, 0x03, 0x19, 0x13, 0x02, 0x1C,
@@ -1011,5 +1011,5 @@
    0x1B, 0x16, 0x10, 0x0D, 0x0A, 0x14, 0x12, 0x04 };
 
-unsigned char table_43[256] = {
+static const unsigned char table_43[256] = {
    0x34, 0xB7, 0x36, 0x85, 0x5F, 0x93, 0x98, 0x70,
    0x1E, 0x59, 0x83, 0x60, 0x6F, 0xBF, 0xF9, 0xD0,
@@ -1045,5 +1045,5 @@
    0x73, 0x76, 0x3A, 0x21, 0x53, 0xA4, 0x50, 0x6A };
 
-unsigned char table_44[32] = {
+static const unsigned char table_44[32] = {
    0x1A, 0x0E, 0x0A, 0x17, 0x1F, 0x08, 0x10, 0x14,
    0x0C, 0x0F, 0x09, 0x1C, 0x06, 0x18, 0x1E, 0x12,
@@ -1051,5 +1051,5 @@
    0x16, 0x19, 0x05, 0x1D, 0x02, 0x07, 0x04, 0x1B };
 
-unsigned char table_45[256] = {
+static const unsigned char table_45[256] = {
    0x5E, 0xD6, 0xE2, 0x54, 0x35, 0xC2, 0xAC, 0x9D,
    0x92, 0x64, 0x57, 0x65, 0xC8, 0xAE, 0x21, 0xA9,
@@ -1085,5 +1085,5 @@
    0xF9, 0x2B, 0x32, 0x8F, 0xFB, 0xC7, 0x07, 0x82 };
 
-unsigned char table_46[256] = {
+static const unsigned char table_46[256] = {
    0x85, 0x78, 0xFE, 0x6C, 0x61, 0xA0, 0x71, 0xCC,
    0x45, 0x54, 0x7A, 0xE6, 0x82, 0x1D, 0xA6, 0x02,
@@ -1119,5 +1119,5 @@
    0xC7, 0xE4, 0x37, 0xE5, 0xFC, 0xBD, 0x99, 0x41 };
 
-unsigned char table_47[32] = {
+static const unsigned char table_47[32] = {
    0x18, 0x1D, 0x16, 0x10, 0x11, 0x04, 0x1E, 0x08,
    0x19, 0x0E, 0x0F, 0x02, 0x14, 0x1C, 0x07, 0x17,
@@ -1125,5 +1125,5 @@
    0x13, 0x15, 0x0C, 0x00, 0x06, 0x1F, 0x03, 0x1B };
 
-unsigned char table_48[32] = {
+static const unsigned char table_48[32] = {
    0x13, 0x08, 0x15, 0x01, 0x17, 0x10, 0x0F, 0x1F,
    0x1D, 0x0D, 0x12, 0x03, 0x06, 0x0A, 0x1C, 0x19,
@@ -1131,5 +1131,5 @@
    0x14, 0x09, 0x0C, 0x18, 0x05, 0x07, 0x0E, 0x0B };
 
-unsigned char table_49[32] = {
+static const unsigned char table_49[32] = {
    0x1F, 0x0F, 0x19, 0x07, 0x18, 0x05, 0x1E, 0x1D,
    0x15, 0x08, 0x17, 0x10, 0x0A, 0x0E, 0x0C, 0x1B,
@@ -1137,5 +1137,5 @@
    0x12, 0x1C, 0x0B, 0x16, 0x14, 0x01, 0x11, 0x00 };
 
-unsigned char table_50[32] = {
+static const unsigned char table_50[32] = {
    0x16, 0x18, 0x1C, 0x0E, 0x12, 0x00, 0x04, 0x1B,
    0x1F, 0x13, 0x17, 0x0A, 0x1E, 0x03, 0x0C, 0x01,
@@ -1143,5 +1143,5 @@
    0x06, 0x0D, 0x0B, 0x1D, 0x05, 0x07, 0x11, 0x1A };
 
-unsigned char table_51[32] = {
+static const unsigned char table_51[32] = {
    0x1C, 0x0D, 0x1B, 0x07, 0x17, 0x0E, 0x06, 0x01,
    0x12, 0x19, 0x03, 0x0B, 0x10, 0x08, 0x00, 0x1E,
@@ -1149,5 +1149,5 @@
    0x0F, 0x11, 0x05, 0x09, 0x15, 0x16, 0x1F, 0x14 };
 
-unsigned char table_52[256] = {
+static const unsigned char table_52[256] = {
    0x34, 0x0B, 0x47, 0xA3, 0x56, 0x30, 0x73, 0xD4,
    0x4B, 0xF6, 0xA6, 0x80, 0x22, 0x95, 0xA5, 0xBB,
@@ -1183,5 +1183,5 @@
    0x01, 0x0C, 0x5D, 0x7D, 0xB8, 0xBE, 0x6A, 0x16 };
 
-unsigned char table_53[256] = {
+static const unsigned char table_53[256] = {
    0xE3, 0xF4, 0x8D, 0x72, 0x45, 0x32, 0x9D, 0xCE,
    0x1F, 0x6B, 0xBC, 0xDC, 0xF1, 0xEC, 0x5A, 0x3B,
@@ -1217,5 +1217,5 @@
    0xAB, 0x64, 0xE0, 0xBE, 0xDA, 0xBD, 0x96, 0x94 };
 
-unsigned char table_54[32] = {
+static const unsigned char table_54[32] = {
    0x01, 0x02, 0x1D, 0x10, 0x0E, 0x11, 0x08, 0x14,
    0x12, 0x09, 0x15, 0x17, 0x16, 0x04, 0x06, 0x1B,
@@ -1223,5 +1223,5 @@
    0x0C, 0x0B, 0x0D, 0x05, 0x0F, 0x00, 0x19, 0x03 };
 
-unsigned char table_55[32] = {
+static const unsigned char table_55[32] = {
    0x01, 0x12, 0x13, 0x09, 0x0B, 0x19, 0x03, 0x0E,
    0x02, 0x1F, 0x1D, 0x1B, 0x1E, 0x11, 0x06, 0x05,
@@ -1229,5 +1229,5 @@
    0x18, 0x10, 0x0F, 0x17, 0x1C, 0x0A, 0x04, 0x14 };
 
-unsigned char table_56[256] = {
+static const unsigned char table_56[256] = {
    0xEF, 0x06, 0x5F, 0x11, 0x4B, 0x60, 0x13, 0xBB,
    0x79, 0xD7, 0xE4, 0x6D, 0x22, 0xB4, 0x15, 0x50,
@@ -1263,5 +1263,5 @@
    0x96, 0xD5, 0xEB, 0x64, 0x8A, 0xC8, 0x7A, 0xBE };
 
-unsigned char table_57[256] = {
+static const unsigned char table_57[256] = {
    0xD1, 0x9B, 0x15, 0x06, 0xB4, 0xF6, 0x97, 0xF0,
    0xC6, 0x5B, 0x88, 0x12, 0x25, 0xFA, 0x7B, 0x79,
@@ -1297,5 +1297,5 @@
    0x4E, 0x3C, 0x84, 0x14, 0x28, 0x3A, 0xE9, 0xC0 };
 
-unsigned char table_58[256] = {
+static const unsigned char table_58[256] = {
    0xE9, 0x81, 0x60, 0xA7, 0x18, 0xA0, 0x0F, 0x55,
    0x2B, 0x52, 0xE0, 0x8B, 0x9D, 0x85, 0xD2, 0xA3,
@@ -1331,5 +1331,5 @@
    0x68, 0x1E, 0xF6, 0xA6, 0x6C, 0xB2, 0xD1, 0x58 };
 
-unsigned char table_59[256] = {
+static const unsigned char table_59[256] = {
    0x4C, 0x85, 0x2B, 0x14, 0xCC, 0x4D, 0x5F, 0xD7,
    0xCE, 0x28, 0xC5, 0x0B, 0xA1, 0x99, 0x08, 0xDE,
@@ -1365,5 +1365,5 @@
    0x5D, 0x1A, 0x8D, 0xC1, 0x58, 0x48, 0xAD, 0x0F };
 
-unsigned char table_60[32] = {
+static const unsigned char table_60[32] = {
    0x1C, 0x06, 0x1E, 0x10, 0x1D, 0x05, 0x00, 0x0E,
    0x0C, 0x02, 0x11, 0x19, 0x15, 0x18, 0x16, 0x07,
@@ -1371,5 +1371,5 @@
    0x03, 0x08, 0x12, 0x04, 0x1B, 0x0A, 0x17, 0x1A };
 
-unsigned char table_61[256] = {
+static const unsigned char table_61[256] = {
    0xC5, 0xA6, 0xF2, 0x6B, 0x4B, 0x58, 0xE0, 0x41,
    0xC6, 0x2F, 0x13, 0xFE, 0xC1, 0x34, 0x3F, 0x24,
@@ -1405,5 +1405,5 @@
    0xCF, 0x60, 0xAA, 0xA4, 0xEB, 0xC4, 0x4E, 0xC2 };
 
-unsigned char table_62[256] = {
+static const unsigned char table_62[256] = {
    0x01, 0x59, 0xEC, 0xFC, 0x51, 0xD2, 0xE4, 0x9D,
    0xAA, 0x61, 0xD5, 0xCA, 0x63, 0x5D, 0xCE, 0x36,
@@ -1439,5 +1439,5 @@
    0xCF, 0xE9, 0xDB, 0xD3, 0x02, 0x9A, 0x0E, 0x5F };
 
-unsigned char table_63[256] = {
+static const unsigned char table_63[256] = {
    0x0C, 0x02, 0xEE, 0x94, 0x2D, 0x76, 0x96, 0x75,
    0x21, 0xDC, 0x37, 0x03, 0xC0, 0xF7, 0xDF, 0xEF,
@@ -1473,5 +1473,5 @@
    0x8C, 0xE2, 0x83, 0xA7, 0xD6, 0x0E, 0xB3, 0xDD };
 
-unsigned char table_64[32] = {
+static const unsigned char table_64[32] = {
    0x03, 0x05, 0x0D, 0x09, 0x1A, 0x16, 0x08, 0x10,
    0x06, 0x1E, 0x1C, 0x15, 0x02, 0x04, 0x17, 0x0C,
@@ -1479,5 +1479,5 @@
    0x0E, 0x00, 0x1D, 0x1F, 0x01, 0x0F, 0x07, 0x12 };
 
-unsigned char table_65[32] = {
+static const unsigned char table_65[32] = {
    0x01, 0x0A, 0x1E, 0x14, 0x10, 0x1D, 0x0D, 0x17,
    0x0E, 0x0C, 0x0F, 0x12, 0x04, 0x1A, 0x05, 0x02,
@@ -1485,5 +1485,5 @@
    0x11, 0x00, 0x16, 0x06, 0x03, 0x18, 0x15, 0x07 };
 
-unsigned char table_66[32] = {
+static const unsigned char table_66[32] = {
    0x1C, 0x18, 0x0C, 0x09, 0x05, 0x03, 0x15, 0x12,
    0x0D, 0x02, 0x08, 0x0E, 0x19, 0x07, 0x13, 0x17,
@@ -1491,5 +1491,5 @@
    0x0F, 0x10, 0x01, 0x1B, 0x00, 0x04, 0x1A, 0x16 };
 
-unsigned char table_67[256] = {
+static const unsigned char table_67[256] = {
    0x6B, 0x49, 0xC8, 0x86, 0xFF, 0xC0, 0x5D, 0xEF,
    0xF7, 0x06, 0xE0, 0x98, 0xA9, 0x72, 0x71, 0xD5,
@@ -1525,5 +1525,5 @@
    0x24, 0x43, 0x21, 0x83, 0xFB, 0xFD, 0x8B, 0x96 };
 
-unsigned char table_68[256] = {
+static const unsigned char table_68[256] = {
    0x93, 0xFF, 0x83, 0x70, 0x12, 0x2D, 0x1C, 0xD6,
    0xF9, 0xEE, 0xCF, 0x94, 0x7B, 0xB5, 0xA4, 0x84,
@@ -1559,5 +1559,5 @@
    0x8C, 0x6D, 0x91, 0x63, 0x3A, 0x4D, 0xC1, 0x01 };
 
-unsigned char table_69[256] = {
+static const unsigned char table_69[256] = {
    0x21, 0x6B, 0x9B, 0xAE, 0x11, 0x5A, 0x91, 0xC2,
    0x47, 0x8E, 0x87, 0x86, 0x4F, 0xFC, 0x8F, 0x66,
@@ -1593,5 +1593,5 @@
    0x73, 0xDB, 0xB6, 0x83, 0xCE, 0x1E, 0xC1, 0x3C };
 
-unsigned char table_70[256] = {
+static const unsigned char table_70[256] = {
    0x54, 0x23, 0xF1, 0x09, 0x9D, 0xEB, 0x26, 0xD9,
    0x6C, 0xC1, 0xBC, 0x3D, 0x6E, 0xB0, 0x5F, 0xE2,
@@ -1627,5 +1627,5 @@
    0x49, 0x84, 0x38, 0xC7, 0xE3, 0xD4, 0x1A, 0xBF };
 
-unsigned char table_71[32] = {
+static const unsigned char table_71[32] = {
    0x17, 0x13, 0x0E, 0x1A, 0x0D, 0x18, 0x19, 0x10,
    0x14, 0x11, 0x16, 0x05, 0x04, 0x00, 0x12, 0x0A,
@@ -1633,5 +1633,5 @@
    0x0C, 0x06, 0x1B, 0x08, 0x1D, 0x01, 0x15, 0x1E };
 
-unsigned char table_72[256] = {
+static const unsigned char table_72[256] = {
    0xC9, 0xA7, 0x1B, 0xEC, 0x2B, 0x8B, 0xB0, 0xEB,
    0x7F, 0x39, 0x25, 0xD9, 0x1D, 0xD5, 0x67, 0xA0,
@@ -1667,5 +1667,5 @@
    0x08, 0x53, 0xF2, 0xB9, 0x5A, 0x3E, 0xE9, 0xD2 };
 
-unsigned char table_73[256] = {
+static const unsigned char table_73[256] = {
    0x36, 0x37, 0xED, 0xD8, 0xBF, 0xD7, 0x12, 0xB7,
    0x40, 0x32, 0x19, 0x4A, 0x44, 0x2A, 0xCE, 0xA5,
@@ -1701,5 +1701,5 @@
    0xFF, 0x90, 0x6B, 0xBC, 0x54, 0x95, 0xBD, 0x07 };
 
-unsigned char table_74[256] = {
+static const unsigned char table_74[256] = {
    0xA7, 0xCF, 0x99, 0x1A, 0x13, 0xC7, 0xE9, 0xC4,
    0xB6, 0x0E, 0x15, 0x09, 0xFF, 0xDF, 0xBE, 0x03,
@@ -1735,5 +1735,5 @@
    0x2F, 0xD8, 0xC3, 0x7C, 0x9C, 0x98, 0xEA, 0x71 };
 
-unsigned char table_75[256] = {
+static const unsigned char table_75[256] = {
    0xE7, 0xA5, 0x30, 0xE1, 0x9D, 0x81, 0xBE, 0x83,
    0xB2, 0x1E, 0xE4, 0x69, 0x2F, 0x2B, 0x0D, 0xEB,
@@ -1769,5 +1769,5 @@
    0x89, 0x46, 0x78, 0xDC, 0x32, 0x8B, 0x67, 0x36 };
 
-unsigned char table_76[256] = {
+static const unsigned char table_76[256] = {
    0x3D, 0x66, 0x40, 0xC5, 0x1D, 0xF5, 0xE7, 0xB7,
    0x2C, 0x23, 0x09, 0xC2, 0x68, 0xE6, 0xD3, 0x8D,
@@ -1803,5 +1803,5 @@
    0xD1, 0x95, 0xC3, 0xA0, 0x0F, 0xCA, 0xAC, 0xFC };
 
-unsigned char table_77[32] = {
+static const unsigned char table_77[32] = {
    0x1C, 0x0D, 0x1E, 0x01, 0x06, 0x16, 0x18, 0x17,
    0x0B, 0x1F, 0x04, 0x0F, 0x00, 0x19, 0x08, 0x0A,
@@ -1809,5 +1809,5 @@
    0x1A, 0x12, 0x13, 0x0E, 0x1D, 0x10, 0x02, 0x1B };
 
-unsigned char table_78[32] = {
+static const unsigned char table_78[32] = {
    0x0E, 0x02, 0x17, 0x12, 0x1E, 0x09, 0x15, 0x03,
    0x01, 0x0B, 0x0F, 0x11, 0x10, 0x0A, 0x16, 0x06,
@@ -1815,5 +1815,5 @@
    0x13, 0x0D, 0x1B, 0x08, 0x19, 0x14, 0x05, 0x1A };
 
-unsigned char table_79[32] = {
+static const unsigned char table_79[32] = {
    0x12, 0x0B, 0x11, 0x01, 0x07, 0x0E, 0x1A, 0x0D,
    0x1E, 0x18, 0x14, 0x1F, 0x0A, 0x17, 0x19, 0x1B,
@@ -1821,5 +1821,5 @@
    0x09, 0x06, 0x04, 0x16, 0x15, 0x1C, 0x05, 0x03 };
 
-unsigned char table_80[256] = {
+static const unsigned char table_80[256] = {
    0x14, 0xE7, 0x31, 0x0F, 0xD1, 0x5F, 0xED, 0x1E,
    0xA6, 0x77, 0x20, 0x57, 0x34, 0x64, 0x33, 0x0B,
@@ -1855,5 +1855,5 @@
    0x39, 0xB9, 0xC0, 0x22, 0xF1, 0x4D, 0x90, 0xFC };
 
-unsigned char table_81[32] = {
+static const unsigned char table_81[32] = {
    0x03, 0x02, 0x1D, 0x0E, 0x09, 0x1A, 0x0C, 0x11,
    0x1C, 0x0D, 0x08, 0x12, 0x19, 0x10, 0x04, 0x17,
@@ -1861,5 +1861,5 @@
    0x1E, 0x0B, 0x0F, 0x01, 0x07, 0x14, 0x1F, 0x06 };
 
-unsigned char table_82[256] = {
+static const unsigned char table_82[256] = {
    0x53, 0xD3, 0x64, 0x89, 0x7D, 0xA5, 0x66, 0xA4,
    0x09, 0x46, 0x17, 0x2C, 0xAF, 0x8C, 0x21, 0x5F,
@@ -1895,5 +1895,5 @@
    0x6A, 0x78, 0xB5, 0x71, 0x56, 0x87, 0x7F, 0x86 };
 
-unsigned char table_83[32] = {
+static const unsigned char table_83[32] = {
    0x1B, 0x0A, 0x1F, 0x01, 0x10, 0x08, 0x0E, 0x18,
    0x06, 0x04, 0x00, 0x1C, 0x0C, 0x19, 0x0D, 0x16,
@@ -1901,5 +1901,5 @@
    0x17, 0x1E, 0x1A, 0x1D, 0x0B, 0x11, 0x14, 0x15 };
 
-unsigned char table_84[32] = {
+static const unsigned char table_84[32] = {
    0x02, 0x1A, 0x0D, 0x15, 0x01, 0x16, 0x1E, 0x00,
    0x08, 0x1B, 0x04, 0x10, 0x1C, 0x18, 0x19, 0x14,
@@ -1907,5 +1907,5 @@
    0x1D, 0x17, 0x13, 0x06, 0x0F, 0x05, 0x09, 0x1F };
 
-unsigned char table_85[256] = {
+static const unsigned char table_85[256] = {
    0xC6, 0x7C, 0xCE, 0xBD, 0x84, 0x3E, 0x0B, 0xD8,
    0xFE, 0xCC, 0x46, 0x50, 0xD1, 0xFB, 0xA0, 0x6D,
@@ -1941,5 +1941,5 @@
    0x2D, 0x57, 0xE7, 0x82, 0x1E, 0x37, 0x63, 0x43 };
 
-unsigned char table_86[32] = {
+static const unsigned char table_86[32] = {
    0x11, 0x07, 0x0F, 0x0A, 0x19, 0x1D, 0x0B, 0x09,
    0x1C, 0x1E, 0x14, 0x06, 0x0C, 0x16, 0x13, 0x04,
@@ -1947,5 +1947,5 @@
    0x10, 0x1A, 0x1F, 0x01, 0x17, 0x0E, 0x03, 0x1B };
 
-unsigned char table_87[32] = {
+static const unsigned char table_87[32] = {
    0x17, 0x0E, 0x1D, 0x13, 0x0B, 0x19, 0x03, 0x06,
    0x09, 0x01, 0x0D, 0x15, 0x1C, 0x16, 0x18, 0x1B,
@@ -1953,5 +1953,5 @@
    0x02, 0x04, 0x07, 0x1A, 0x14, 0x0A, 0x0C, 0x05 };
 
-unsigned char table_88[32] = {
+static const unsigned char table_88[32] = {
    0x09, 0x08, 0x17, 0x10, 0x0A, 0x07, 0x1C, 0x1F,
    0x04, 0x0E, 0x01, 0x0C, 0x0D, 0x1B, 0x03, 0x15,
@@ -1959,5 +1959,5 @@
    0x05, 0x11, 0x14, 0x00, 0x16, 0x1D, 0x12, 0x13 };
 
-unsigned char table_89[32] = {
+static const unsigned char table_89[32] = {
    0x15, 0x1C, 0x1D, 0x14, 0x0F, 0x1A, 0x05, 0x02,
    0x07, 0x09, 0x06, 0x08, 0x1F, 0x00, 0x10, 0x13,
@@ -1965,5 +1965,5 @@
    0x12, 0x04, 0x11, 0x0A, 0x01, 0x0B, 0x17, 0x19 };
 
-unsigned char table_90[256] = {
+static const unsigned char table_90[256] = {
    0x62, 0x36, 0x64, 0x0E, 0x4C, 0x6C, 0xBE, 0xCF,
    0x25, 0x5A, 0x3D, 0x12, 0x54, 0x9F, 0xE7, 0xA5,
@@ -1999,5 +1999,5 @@
    0x20, 0x94, 0x45, 0xED, 0xDC, 0xBD, 0x7E, 0x50 };
 
-unsigned char table_91[32] = {
+static const unsigned char table_91[32] = {
    0x03, 0x04, 0x0C, 0x18, 0x10, 0x0D, 0x13, 0x1B,
    0x1F, 0x07, 0x11, 0x17, 0x1C, 0x1D, 0x05, 0x06,
@@ -2005,5 +2005,5 @@
    0x14, 0x16, 0x00, 0x15, 0x19, 0x09, 0x0F, 0x1E };
 
-unsigned char table_92[32] = {
+static const unsigned char table_92[32] = {
    0x1E, 0x10, 0x01, 0x07, 0x11, 0x16, 0x15, 0x17,
    0x1F, 0x14, 0x0C, 0x1C, 0x06, 0x03, 0x00, 0x18,
@@ -2011,5 +2011,5 @@
    0x0F, 0x12, 0x0B, 0x13, 0x0A, 0x04, 0x1D, 0x1A };
 
-unsigned char table_93[256] = {
+static const unsigned char table_93[256] = {
    0x76, 0x78, 0xA2, 0x94, 0x0E, 0x7F, 0xDF, 0xC1,
    0xB9, 0xE1, 0x3D, 0x59, 0x6F, 0x1E, 0x53, 0x99,
@@ -2045,5 +2045,5 @@
    0x24, 0x34, 0xE2, 0xEC, 0x85, 0x47, 0xF4, 0xB2 };
 
-unsigned char table_94[32] = {
+static const unsigned char table_94[32] = {
    0x1C, 0x07, 0x05, 0x1A, 0x10, 0x1D, 0x14, 0x12,
    0x08, 0x0F, 0x0C, 0x01, 0x04, 0x1B, 0x16, 0x0A,
@@ -2051,5 +2051,5 @@
    0x0E, 0x09, 0x15, 0x19, 0x03, 0x18, 0x00, 0x0B };
 
-unsigned char table_95[32] = {
+static const unsigned char table_95[32] = {
    0x12, 0x10, 0x11, 0x15, 0x03, 0x0A, 0x14, 0x05,
    0x1D, 0x07, 0x17, 0x0D, 0x09, 0x08, 0x1B, 0x1F,
@@ -2057,5 +2057,5 @@
    0x1E, 0x1C, 0x01, 0x0C, 0x1A, 0x0F, 0x13, 0x16 };
 
-unsigned char table_96[256] = {
+static const unsigned char table_96[256] = {
    0x1C, 0x6E, 0xCD, 0xB4, 0xB3, 0x93, 0xA8, 0x2E,
    0x4F, 0x09, 0xE3, 0x72, 0x64, 0x13, 0x21, 0xF5,
@@ -2091,5 +2091,5 @@
    0x59, 0xCE, 0xE1, 0x57, 0x20, 0x58, 0x51, 0xD8 };
 
-unsigned char table_97[256] = {
+static const unsigned char table_97[256] = {
    0x15, 0x2D, 0xAF, 0x36, 0xCF, 0xD3, 0xD0, 0xED,
    0xB2, 0x1B, 0xFE, 0x92, 0xBD, 0xAD, 0x58, 0x0F,
@@ -2125,5 +2125,5 @@
    0x83, 0x25, 0x9F, 0xD9, 0x99, 0xC1, 0xFD, 0xB3 };
 
-unsigned char table_98[256] = {
+static const unsigned char table_98[256] = {
    0xC8, 0xE6, 0x38, 0x93, 0xE5, 0x03, 0x18, 0x1F,
    0xE9, 0x5A, 0xB6, 0xAF, 0xC3, 0x95, 0x00, 0x51,
@@ -2159,5 +2159,5 @@
    0x54, 0x3A, 0x13, 0x09, 0x2C, 0xB5, 0xC7, 0x63 };
 
-unsigned char table_99[32] = {
+static const unsigned char table_99[32] = {
    0x19, 0x00, 0x10, 0x18, 0x09, 0x11, 0x13, 0x1D,
    0x08, 0x1A, 0x02, 0x05, 0x03, 0x17, 0x12, 0x01,
@@ -2165,5 +2165,5 @@
    0x0E, 0x16, 0x1E, 0x04, 0x1B, 0x0A, 0x0C, 0x1C };
 
-unsigned char table_100[256] = {
+static const unsigned char table_100[256] = {
    0x9B, 0x3A, 0xAE, 0x60, 0x27, 0x67, 0x1E, 0x4E,
    0x91, 0xDA, 0x85, 0x43, 0x5C, 0xCC, 0x89, 0x55,
@@ -2199,5 +2199,5 @@
    0x30, 0x0C, 0xB2, 0x7B, 0xBE, 0xFB, 0x23, 0x2C };
 
-unsigned char table_101[32] = {
+static const unsigned char table_101[32] = {
    0x18, 0x08, 0x14, 0x17, 0x03, 0x10, 0x19, 0x04,
    0x0D, 0x1C, 0x06, 0x1D, 0x1E, 0x12, 0x11, 0x0B,
@@ -2205,5 +2205,5 @@
    0x15, 0x0A, 0x0C, 0x1A, 0x00, 0x01, 0x1F, 0x09 };
 
-unsigned char table_102[32] = {
+static const unsigned char table_102[32] = {
    0x17, 0x1F, 0x0E, 0x05, 0x13, 0x0C, 0x14, 0x1A,
    0x0F, 0x01, 0x12, 0x1C, 0x00, 0x07, 0x0D, 0x02,
@@ -2211,5 +2211,5 @@
    0x06, 0x15, 0x0A, 0x19, 0x09, 0x08, 0x1B, 0x0B };
 
-unsigned char table_103[32] = {
+static const unsigned char table_103[32] = {
    0x0F, 0x09, 0x1E, 0x11, 0x0D, 0x08, 0x10, 0x00,
    0x01, 0x1F, 0x1D, 0x1C, 0x12, 0x04, 0x07, 0x05,
@@ -2217,5 +2217,5 @@
    0x18, 0x0B, 0x0A, 0x13, 0x0C, 0x0E, 0x03, 0x06 };
 
-unsigned char table_104[256] = {
+static const unsigned char table_104[256] = {
    0xA4, 0x9F, 0x78, 0x39, 0x3D, 0x81, 0x51, 0x24,
    0x46, 0x2A, 0x56, 0xE8, 0xDF, 0x73, 0xA8, 0xA2,
@@ -2251,5 +2251,5 @@
    0x97, 0xBB, 0x37, 0x8C, 0x54, 0x53, 0x9E, 0x8F };
 
-unsigned char table_105[256] = {
+static const unsigned char table_105[256] = {
    0x7B, 0x35, 0x11, 0x79, 0x07, 0x2F, 0xF6, 0x82,
    0x8E, 0xB4, 0x6E, 0xD2, 0x6D, 0xC5, 0x8C, 0x1C,
@@ -2285,5 +2285,5 @@
    0xBA, 0x1E, 0x44, 0x87, 0x45, 0x9F, 0xC9, 0x94 };
 
-unsigned char table_106[32] = {
+static const unsigned char table_106[32] = {
    0x03, 0x11, 0x07, 0x1B, 0x0F, 0x14, 0x0C, 0x01,
    0x04, 0x02, 0x09, 0x0A, 0x05, 0x12, 0x06, 0x1F,
@@ -2291,5 +2291,5 @@
    0x1E, 0x1D, 0x17, 0x19, 0x13, 0x16, 0x0B, 0x1A };
 
-unsigned char table_107[32] = {
+static const unsigned char table_107[32] = {
    0x13, 0x1B, 0x06, 0x11, 0x1C, 0x07, 0x08, 0x0E,
    0x10, 0x05, 0x09, 0x18, 0x04, 0x15, 0x1E, 0x0F,
@@ -2297,5 +2297,5 @@
    0x03, 0x0C, 0x0A, 0x1D, 0x14, 0x01, 0x16, 0x0B };
 
-unsigned char table_108[256] = {
+static const unsigned char table_108[256] = {
    0x99, 0xA3, 0x48, 0xE8, 0x5A, 0x7D, 0x97, 0xCA,
    0x7F, 0x06, 0x9B, 0x04, 0xE0, 0xF3, 0x18, 0xAE,
@@ -2331,5 +2331,5 @@
    0xCC, 0xE2, 0x44, 0x73, 0xBE, 0x26, 0x8C, 0x5B };
 
-unsigned char table_109[256] = {
+static const unsigned char table_109[256] = {
    0xE3, 0x95, 0xDB, 0x09, 0x82, 0x0A, 0x8F, 0x9E,
    0xC9, 0xDC, 0x28, 0x35, 0x0F, 0x8B, 0xA8, 0xA5,
@@ -2365,5 +2365,5 @@
    0x1E, 0xF4, 0xD5, 0xB1, 0x5C, 0x25, 0xE8, 0x1C };
 
-unsigned char table_110[256] = {
+static const unsigned char table_110[256] = {
    0xC3, 0x06, 0x3C, 0xCB, 0xD2, 0x44, 0x9D, 0x48,
    0x28, 0xAA, 0xA9, 0xD0, 0x64, 0x25, 0x56, 0xCA,
@@ -2399,5 +2399,5 @@
    0x4B, 0xCF, 0xB4, 0x2F, 0xBB, 0xEF, 0xDB, 0x33 };
 
-unsigned char table_111[32] = {
+static const unsigned char table_111[32] = {
    0x09, 0x0F, 0x00, 0x15, 0x12, 0x17, 0x1A, 0x0D,
    0x1C, 0x0B, 0x01, 0x0A, 0x05, 0x1E, 0x1D, 0x0C,
@@ -2405,5 +2405,5 @@
    0x10, 0x16, 0x11, 0x1F, 0x04, 0x06, 0x02, 0x13 };
 
-unsigned char table_112[256] = {
+static const unsigned char table_112[256] = {
    0xF9, 0x7D, 0xBE, 0xD5, 0x9F, 0xB8, 0x95, 0x43,
    0xDB, 0xAE, 0x7E, 0xEC, 0x5B, 0x58, 0x18, 0x49,
@@ -2439,5 +2439,5 @@
    0xA1, 0xCC, 0xDF, 0x60, 0xD8, 0x5A, 0xE6, 0xD4 };
 
-unsigned char table_113[256] = {
+static const unsigned char table_113[256] = {
    0x46, 0x9D, 0x39, 0xB2, 0x8D, 0x3B, 0x59, 0x5A,
    0xD0, 0x9C, 0xE4, 0x04, 0x01, 0xE2, 0xB3, 0xD2,
@@ -2473,5 +2473,5 @@
    0xFE, 0x7B, 0x67, 0xFF, 0x10, 0xEC, 0xC6, 0x86 };
 
-unsigned char table_114[32] = {
+static const unsigned char table_114[32] = {
    0x11, 0x10, 0x04, 0x1D, 0x08, 0x15, 0x1A, 0x1B,
    0x14, 0x18, 0x0F, 0x17, 0x16, 0x07, 0x1E, 0x0E,
@@ -2479,5 +2479,5 @@
    0x1F, 0x19, 0x09, 0x1C, 0x01, 0x0D, 0x03, 0x05 };
 
-unsigned char table_115[256] = {
+static const unsigned char table_115[256] = {
    0xB7, 0xBB, 0x63, 0x0D, 0xF0, 0x33, 0x5A, 0x05,
    0xF2, 0x7F, 0x64, 0xDB, 0x51, 0xC9, 0x2C, 0x85,
@@ -2513,5 +2513,5 @@
    0x8C, 0x17, 0xB5, 0xEB, 0xD5, 0xF3, 0x0B, 0x3C };
 
-unsigned char table_116[32] = {
+static const unsigned char table_116[32] = {
    0x00, 0x05, 0x10, 0x1C, 0x0C, 0x1A, 0x04, 0x1B,
    0x0A, 0x0D, 0x14, 0x0B, 0x07, 0x03, 0x12, 0x1E,
@@ -2519,5 +2519,5 @@
    0x19, 0x18, 0x16, 0x02, 0x13, 0x0E, 0x17, 0x1D };
 
-unsigned char table_117[256] = {
+static const unsigned char table_117[256] = {
    0xD0, 0x9A, 0xAB, 0xA8, 0xA7, 0xDF, 0x28, 0xCE,
    0x3E, 0x51, 0xBF, 0x76, 0x03, 0xA0, 0x53, 0x3F,
@@ -2553,5 +2553,5 @@
    0xC1, 0xFD, 0x92, 0xA1, 0xF7, 0xAE, 0xDC, 0x58 };
 
-unsigned char table_118[256] = {
+static const unsigned char table_118[256] = {
    0x38, 0xA0, 0xA6, 0xFC, 0x7C, 0x5A, 0x97, 0x1D,
    0xFD, 0x00, 0x20, 0xA2, 0x72, 0x10, 0x1F, 0x48,
@@ -2587,5 +2587,5 @@
    0xD9, 0x2F, 0x02, 0xAC, 0x30, 0x6A, 0xD6, 0x95 };
 
-unsigned char table_119[32] = {
+static const unsigned char table_119[32] = {
    0x14, 0x0A, 0x1C, 0x00, 0x0C, 0x1F, 0x1E, 0x0B,
    0x12, 0x1D, 0x17, 0x08, 0x07, 0x04, 0x09, 0x10,
@@ -2593,5 +2593,5 @@
    0x18, 0x02, 0x06, 0x01, 0x19, 0x16, 0x13, 0x0F };
 
-unsigned char table_120[256] = {
+static const unsigned char table_120[256] = {
    0xCE, 0x89, 0xB2, 0x72, 0x04, 0x77, 0x64, 0xAE,
    0x80, 0x99, 0xB5, 0x00, 0x7B, 0x50, 0x9D, 0xE3,
@@ -2627,5 +2627,5 @@
    0x5E, 0xCA, 0xFD, 0x11, 0xA3, 0xC7, 0xC0, 0x91 };
 
-unsigned char table_121[32] = {
+static const unsigned char table_121[32] = {
    0x1E, 0x12, 0x06, 0x1D, 0x15, 0x1F, 0x13, 0x0B,
    0x10, 0x0D, 0x1C, 0x01, 0x0A, 0x0E, 0x02, 0x19,
@@ -2633,5 +2633,5 @@
    0x14, 0x08, 0x18, 0x05, 0x09, 0x0F, 0x1B, 0x07 };
 
-unsigned char table_122[256] = {
+static const unsigned char table_122[256] = {
    0x85, 0xDF, 0x7F, 0x7C, 0x56, 0xF0, 0x0C, 0x7D,
    0x76, 0xA8, 0x58, 0x31, 0x25, 0x8A, 0x0D, 0x23,
@@ -2667,5 +2667,5 @@
    0xCE, 0x2D, 0x4E, 0x83, 0xC3, 0x69, 0xEE, 0xB2 };
 
-unsigned char table_123[256] = {
+static const unsigned char table_123[256] = {
    0x9D, 0xFB, 0x3C, 0x81, 0xAA, 0x05, 0xB2, 0xBE,
    0xD1, 0x5F, 0x4C, 0xE0, 0xA3, 0xF4, 0xDE, 0x35,
@@ -2701,5 +2701,5 @@
    0x48, 0x77, 0xD0, 0x0A, 0x8A, 0x3A, 0x43, 0x79 };
 
-unsigned char table_124[256] = {
+static const unsigned char table_124[256] = {
    0x6C, 0xC3, 0x28, 0x2F, 0x42, 0x4B, 0x7C, 0x3C,
    0xCE, 0x24, 0xC8, 0x51, 0x25, 0x3F, 0x49, 0x8D,
@@ -2735,5 +2735,5 @@
    0x62, 0x1B, 0xDE, 0x91, 0x87, 0x97, 0x05, 0x2E };
 
-unsigned char table_125[32] = {
+static const unsigned char table_125[32] = {
    0x1A, 0x18, 0x12, 0x15, 0x00, 0x1C, 0x01, 0x0B,
    0x19, 0x1B, 0x1F, 0x11, 0x07, 0x10, 0x1E, 0x06,
@@ -2741,5 +2741,5 @@
    0x02, 0x03, 0x13, 0x14, 0x09, 0x1D, 0x05, 0x0F };
 
-unsigned char table_126[32] = {
+static const unsigned char table_126[32] = {
    0x1C, 0x1D, 0x07, 0x12, 0x18, 0x1A, 0x19, 0x09,
    0x0F, 0x14, 0x1F, 0x0B, 0x13, 0x04, 0x0E, 0x1E,
@@ -2747,5 +2747,5 @@
    0x15, 0x10, 0x11, 0x08, 0x00, 0x03, 0x06, 0x02 };
 
-unsigned char table_127[256] = {
+static const unsigned char table_127[256] = {
    0xA0, 0x66, 0xD8, 0x08, 0xEA, 0x39, 0x78, 0xAB,
    0x61, 0x4E, 0xC7, 0xD1, 0xA3, 0x1C, 0x9F, 0xCB,
@@ -2781,5 +2781,5 @@
    0x70, 0xF8, 0x17, 0xCD, 0xB0, 0xCC, 0x82, 0x2D };
 
-unsigned char table_128[32] = {
+static const unsigned char table_128[32] = {
    0x1A, 0x1C, 0x09, 0x17, 0x1B, 0x0B, 0x16, 0x1E,
    0x14, 0x0C, 0x12, 0x0E, 0x05, 0x03, 0x1F, 0x15,
@@ -2787,5 +2787,5 @@
    0x02, 0x08, 0x0F, 0x18, 0x07, 0x04, 0x1D, 0x06 };
 
-unsigned char table_129[256] = {
+static const unsigned char table_129[256] = {
    0x9D, 0x5F, 0xE8, 0x99, 0x57, 0x07, 0x16, 0xA6,
    0x9F, 0xB6, 0xDE, 0xED, 0x2D, 0xB3, 0xC0, 0x8E,
@@ -2821,5 +2821,5 @@
    0x09, 0x45, 0x6B, 0xD7, 0x0B, 0x89, 0x4F, 0x2A };
 
-unsigned char table_130[32] = {
+static const unsigned char table_130[32] = {
    0x07, 0x03, 0x15, 0x0B, 0x02, 0x11, 0x17, 0x14,
    0x05, 0x10, 0x0A, 0x0F, 0x01, 0x1C, 0x1D, 0x0E,
@@ -2827,5 +2827,5 @@
    0x1B, 0x00, 0x08, 0x0D, 0x0C, 0x1E, 0x04, 0x1F };
 
-unsigned char table_131[32] = {
+static const unsigned char table_131[32] = {
    0x1D, 0x13, 0x1B, 0x10, 0x07, 0x03, 0x0A, 0x02,
    0x00, 0x0C, 0x0E, 0x0B, 0x0D, 0x18, 0x12, 0x1F,
@@ -2833,5 +2833,5 @@
    0x19, 0x05, 0x0F, 0x17, 0x06, 0x01, 0x09, 0x16 };
 
-unsigned char table_132[256] = {
+static const unsigned char table_132[256] = {
    0x33, 0x8D, 0x45, 0x6F, 0xFF, 0xF5, 0xB6, 0x53,
    0x3B, 0xF3, 0x07, 0xA4, 0x97, 0xEB, 0x6B, 0xA5,
@@ -2867,5 +2867,5 @@
    0xC4, 0x7F, 0xA0, 0xD8, 0xEF, 0x03, 0x70, 0xF6 };
 
-unsigned char table_133[256] = {
+static const unsigned char table_133[256] = {
    0x02, 0xF0, 0xED, 0xC4, 0xE4, 0x67, 0x60, 0x8B,
    0xF3, 0x77, 0x92, 0xE0, 0x85, 0x93, 0x1E, 0x8E,
@@ -2901,5 +2901,5 @@
    0x5A, 0x35, 0xB0, 0xAE, 0x82, 0x79, 0x1D, 0x52 };
 
-unsigned char table_134[32] = {
+static const unsigned char table_134[32] = {
    0x09, 0x0F, 0x10, 0x0C, 0x03, 0x15, 0x07, 0x17,
    0x0E, 0x0B, 0x1D, 0x08, 0x19, 0x11, 0x00, 0x0A,
@@ -2907,5 +2907,5 @@
    0x02, 0x1B, 0x1A, 0x04, 0x05, 0x1F, 0x1C, 0x1E };
 
-unsigned char table_135[256] = {
+static const unsigned char table_135[256] = {
    0x14, 0x34, 0xEA, 0x02, 0x2B, 0x5A, 0x10, 0x51,
    0xF3, 0x8F, 0x28, 0xB2, 0x50, 0x8B, 0x01, 0xCC,
@@ -2941,5 +2941,5 @@
    0x00, 0x63, 0xD9, 0xBE, 0xF2, 0x60, 0x25, 0x62 };
 
-unsigned char table_136[256] = {
+static const unsigned char table_136[256] = {
    0xD3, 0x1A, 0x00, 0xED, 0x59, 0x24, 0xA3, 0xF2,
    0xBA, 0x58, 0x4C, 0x5C, 0x75, 0x48, 0x98, 0xB0,
@@ -2975,5 +2975,5 @@
    0x93, 0x1D, 0x9B, 0x5B, 0x40, 0xEE, 0x42, 0x19 };
 
-unsigned char table_137[32] = {
+static const unsigned char table_137[32] = {
    0x0F, 0x09, 0x02, 0x06, 0x18, 0x0B, 0x1E, 0x05,
    0x11, 0x1D, 0x16, 0x01, 0x13, 0x10, 0x0E, 0x1A,
@@ -2981,5 +2981,5 @@
    0x03, 0x1F, 0x0A, 0x12, 0x0C, 0x07, 0x04, 0x1C };
 
-unsigned char table_138[32] = {
+static const unsigned char table_138[32] = {
    0x0D, 0x1C, 0x1F, 0x15, 0x0F, 0x14, 0x1B, 0x12,
    0x09, 0x0B, 0x19, 0x07, 0x11, 0x16, 0x0C, 0x04,
@@ -2987,5 +2987,5 @@
    0x01, 0x06, 0x18, 0x17, 0x10, 0x1A, 0x02, 0x00 };
 
-unsigned char table_139[32] = {
+static const unsigned char table_139[32] = {
    0x05, 0x15, 0x1D, 0x02, 0x0F, 0x03, 0x17, 0x1A,
    0x0A, 0x00, 0x1F, 0x12, 0x0E, 0x11, 0x1B, 0x13,
@@ -2993,5 +2993,5 @@
    0x0C, 0x04, 0x16, 0x19, 0x1C, 0x06, 0x10, 0x01 };
 
-unsigned char table_140[32] = {
+static const unsigned char table_140[32] = {
    0x06, 0x1E, 0x0C, 0x11, 0x13, 0x08, 0x15, 0x01,
    0x1D, 0x03, 0x0F, 0x19, 0x18, 0x04, 0x00, 0x14,
@@ -2999,5 +2999,5 @@
    0x1F, 0x17, 0x09, 0x0A, 0x0D, 0x16, 0x10, 0x1C };
 
-unsigned char table_141[256] = {
+static const unsigned char table_141[256] = {
    0xE1, 0x0A, 0x28, 0xCD, 0x8A, 0x1E, 0x26, 0x10,
    0xC0, 0x6F, 0x06, 0x2C, 0xF8, 0x51, 0x6C, 0x8F,
@@ -3033,5 +3033,5 @@
    0x98, 0x54, 0xB8, 0xDC, 0x46, 0xDF, 0x87, 0xE5 };
 
-unsigned char table_142[256] = {
+static const unsigned char table_142[256] = {
    0x90, 0x94, 0xBE, 0x14, 0x99, 0xEB, 0x45, 0x0F,
    0x34, 0x4A, 0xE3, 0x79, 0xD2, 0x64, 0x4D, 0x69,
@@ -3067,5 +3067,5 @@
    0xCC, 0x1E, 0x87, 0xD7, 0x01, 0x1F, 0x51, 0x95 };
 
-unsigned char table_143[32] = {
+static const unsigned char table_143[32] = {
    0x0E, 0x16, 0x18, 0x11, 0x0C, 0x01, 0x12, 0x1F,
    0x08, 0x15, 0x0A, 0x06, 0x1C, 0x1E, 0x02, 0x1A,
@@ -3073,5 +3073,5 @@
    0x0D, 0x14, 0x09, 0x0B, 0x1B, 0x00, 0x1D, 0x04 };
 
-unsigned char table_144[32] = {
+static const unsigned char table_144[32] = {
    0x00, 0x1B, 0x17, 0x19, 0x1D, 0x11, 0x0D, 0x1A,
    0x13, 0x03, 0x1E, 0x09, 0x10, 0x0E, 0x15, 0x05,
@@ -3079,5 +3079,5 @@
    0x16, 0x14, 0x02, 0x04, 0x07, 0x18, 0x12, 0x0C };
 
-unsigned char table_145[256] = {
+static const unsigned char table_145[256] = {
    0xF9, 0x2C, 0x38, 0x74, 0xDA, 0x65, 0x85, 0x0E,
    0xBA, 0x64, 0xDB, 0xE3, 0xB6, 0x8B, 0x0B, 0x5E,
@@ -3113,5 +3113,5 @@
    0x69, 0xF6, 0xEF, 0xC2, 0xAD, 0x03, 0xB3, 0x1E };
 
-unsigned char table_146[256] = {
+static const unsigned char table_146[256] = {
    0x1C, 0xF5, 0x16, 0xD2, 0xCC, 0xDC, 0x1E, 0x29,
    0xE3, 0x17, 0x3B, 0x66, 0x6A, 0xF7, 0x03, 0xB2,
@@ -3147,5 +3147,5 @@
    0x7D, 0x96, 0x76, 0x99, 0xB5, 0x48, 0x98, 0x10 };
 
-unsigned char table_147[32] = {
+static const unsigned char table_147[32] = {
    0x17, 0x07, 0x0D, 0x16, 0x00, 0x1B, 0x1F, 0x09,
    0x10, 0x11, 0x14, 0x0A, 0x02, 0x06, 0x13, 0x0C,
@@ -3153,5 +3153,5 @@
    0x1C, 0x1A, 0x03, 0x18, 0x04, 0x0B, 0x1D, 0x0E };
 
-unsigned char table_148[256] = {
+static const unsigned char table_148[256] = {
    0xFB, 0x23, 0xBC, 0x5A, 0x8C, 0x02, 0x42, 0x3B,
    0x95, 0x0C, 0x21, 0x0E, 0x14, 0xDF, 0x11, 0xC0,
@@ -3187,5 +3187,5 @@
    0x09, 0x43, 0xBF, 0xD0, 0x55, 0xDD, 0x3F, 0x24 };
 
-unsigned char table_149[32] = {
+static const unsigned char table_149[32] = {
    0x1B, 0x0B, 0x0C, 0x06, 0x1F, 0x17, 0x04, 0x1A,
    0x1E, 0x02, 0x0F, 0x16, 0x0E, 0x09, 0x10, 0x01,
@@ -3193,5 +3193,5 @@
    0x18, 0x1D, 0x14, 0x0D, 0x07, 0x08, 0x15, 0x12 };
 
-unsigned char table_150[256] = {
+static const unsigned char table_150[256] = {
    0x57, 0xBC, 0x9D, 0x46, 0x14, 0xD0, 0x94, 0x95,
    0x1B, 0x12, 0xB8, 0xD4, 0x53, 0x73, 0x83, 0xE6,
@@ -3227,5 +3227,5 @@
    0x97, 0xC9, 0xF3, 0x04, 0xD8, 0xF4, 0x80, 0x44 };
 
-unsigned char table_151[256] = {
+static const unsigned char table_151[256] = {
    0x78, 0x6C, 0xC5, 0x0C, 0x2D, 0xA7, 0x97, 0x9C,
    0x22, 0x76, 0x3E, 0x81, 0x51, 0x47, 0x59, 0x71,
@@ -3261,5 +3261,5 @@
    0x43, 0x3A, 0x53, 0x9E, 0x80, 0x88, 0x07, 0x9D };
 
-unsigned char table_152[32] = {
+static const unsigned char table_152[32] = {
    0x02, 0x1A, 0x17, 0x1D, 0x01, 0x03, 0x13, 0x1E,
    0x05, 0x18, 0x06, 0x0A, 0x0C, 0x04, 0x1B, 0x00,
@@ -3267,5 +3267,5 @@
    0x14, 0x12, 0x0D, 0x10, 0x19, 0x11, 0x08, 0x15 };
 
-unsigned char table_153[32] = {
+static const unsigned char table_153[32] = {
    0x0E, 0x14, 0x12, 0x1E, 0x1C, 0x02, 0x06, 0x16,
    0x18, 0x0D, 0x17, 0x0C, 0x1D, 0x11, 0x08, 0x19,
@@ -3273,5 +3273,5 @@
    0x1A, 0x0A, 0x05, 0x10, 0x00, 0x01, 0x15, 0x09 };
 
-unsigned char table_154[256] = {
+static const unsigned char table_154[256] = {
    0x27, 0x5A, 0x08, 0x5B, 0xF4, 0x39, 0x13, 0x6F,
    0x67, 0xEA, 0x22, 0xCA, 0x5C, 0xCF, 0x18, 0x7C,
@@ -3307,5 +3307,5 @@
    0x53, 0xE1, 0xDD, 0x72, 0x95, 0x52, 0x34, 0xB5 };
 
-unsigned char table_155[256] = {
+static const unsigned char table_155[256] = {
    0x75, 0x58, 0xC5, 0xA5, 0x83, 0x16, 0xF3, 0x7F,
    0x94, 0xDE, 0xA0, 0xF6, 0xFD, 0x89, 0xA8, 0x06,
@@ -3341,5 +3341,5 @@
    0x8B, 0x33, 0xFC, 0xBB, 0x00, 0xA2, 0xDF, 0xDA };
 
-unsigned char table_156[256] = {
+static const unsigned char table_156[256] = {
    0x31, 0x25, 0xB1, 0xD3, 0xAF, 0xAE, 0x84, 0x2C,
    0x71, 0x5E, 0xD8, 0x80, 0x6F, 0x3E, 0x48, 0x86,
@@ -3375,5 +3375,5 @@
    0xF1, 0x68, 0xBE, 0x35, 0x40, 0x8C, 0xD4, 0x47 };
 
-unsigned char table_157[32] = {
+static const unsigned char table_157[32] = {
    0x00, 0x0D, 0x03, 0x02, 0x11, 0x04, 0x18, 0x0B,
    0x14, 0x1D, 0x1C, 0x13, 0x1B, 0x17, 0x10, 0x15,
@@ -3381,5 +3381,5 @@
    0x08, 0x06, 0x0C, 0x0E, 0x1F, 0x0F, 0x0A, 0x05 };
 
-unsigned char table_158[256] = {
+static const unsigned char table_158[256] = {
    0x68, 0x26, 0x80, 0x0B, 0xB8, 0xD5, 0x8C, 0xB7,
    0x65, 0xEF, 0xBC, 0x94, 0x28, 0xB9, 0xB2, 0xD2,
@@ -3415,5 +3415,5 @@
    0x9A, 0x57, 0xA2, 0x74, 0xC6, 0xFE, 0x9B, 0x58 };
 
-unsigned char table_159[256] = {
+static const unsigned char table_159[256] = {
    0xE5, 0xBF, 0x84, 0x56, 0xD6, 0x43, 0x3E, 0xA5,
    0x64, 0x87, 0x44, 0x63, 0x4A, 0x4C, 0x8D, 0x24,
@@ -3449,5 +3449,5 @@
    0xCB, 0x9B, 0x13, 0x8F, 0xA4, 0x28, 0x23, 0x85 };
 
-unsigned char table_160[256] = {
+static const unsigned char table_160[256] = {
    0x35, 0x44, 0x0E, 0x92, 0x75, 0x83, 0x9D, 0x53,
    0xA5, 0x90, 0xF8, 0xF7, 0x54, 0x74, 0xDF, 0x3D,
@@ -3483,5 +3483,5 @@
    0xBB, 0x2C, 0xE5, 0xC3, 0x67, 0xA1, 0x10, 0xB9 };
 
-unsigned char table_161[256] = {
+static const unsigned char table_161[256] = {
    0x8F, 0x1A, 0x81, 0xA2, 0x2C, 0x56, 0x6D, 0xCD,
    0x4A, 0x33, 0x50, 0xE9, 0xE0, 0x12, 0x5A, 0x43,
@@ -3517,5 +3517,5 @@
    0xBE, 0x0A, 0x36, 0x41, 0xC0, 0x8C, 0xE4, 0xAA };
 
-unsigned char table_162[256] = {
+static const unsigned char table_162[256] = {
    0xF7, 0x1B, 0xC0, 0x31, 0x5A, 0x23, 0xEA, 0xE9,
    0xFB, 0x14, 0x6A, 0xE8, 0x04, 0x65, 0x5B, 0x2C,
@@ -3551,5 +3551,5 @@
    0x38, 0xCC, 0x58, 0x44, 0xBF, 0x93, 0x5D, 0xC7 };
 
-unsigned char table_163[32] = {
+static const unsigned char table_163[32] = {
    0x1B, 0x14, 0x12, 0x15, 0x11, 0x1D, 0x17, 0x19,
    0x10, 0x09, 0x08, 0x06, 0x1A, 0x16, 0x07, 0x13,
@@ -3557,5 +3557,5 @@
    0x04, 0x01, 0x03, 0x0C, 0x0D, 0x1E, 0x02, 0x0F };
 
-unsigned char table_164[32] = {
+static const unsigned char table_164[32] = {
    0x15, 0x00, 0x10, 0x0B, 0x1D, 0x0A, 0x06, 0x1C,
    0x0D, 0x1F, 0x17, 0x0F, 0x03, 0x14, 0x13, 0x12,
@@ -3563,5 +3563,5 @@
    0x02, 0x0C, 0x0E, 0x01, 0x07, 0x19, 0x11, 0x05 };
 
-unsigned char table_165[256] = {
+static const unsigned char table_165[256] = {
    0x98, 0xF5, 0x1D, 0xFB, 0x13, 0x20, 0x41, 0xA3,
    0xE3, 0x76, 0x49, 0x7E, 0x60, 0xD8, 0x68, 0x30,
@@ -3597,5 +3597,5 @@
    0x1A, 0x26, 0xCC, 0xB1, 0xF9, 0xFA, 0x97, 0xE9 };
 
-unsigned char table_166[256] = {
+static const unsigned char table_166[256] = {
    0xCB, 0xEA, 0x2A, 0x36, 0x6D, 0x93, 0x4E, 0xD5,
    0xBC, 0x6A, 0xD4, 0x68, 0xF7, 0x18, 0xAB, 0x8B,
@@ -3631,5 +3631,5 @@
    0x1C, 0xE0, 0x51, 0x16, 0x43, 0x07, 0x0A, 0x3F };
 
-unsigned char table_167[256] = {
+static const unsigned char table_167[256] = {
    0x91, 0xEA, 0x4F, 0x6A, 0x6E, 0x2D, 0x27, 0x22,
    0x44, 0xA5, 0x6D, 0xE3, 0x45, 0x06, 0xE2, 0x87,
@@ -3665,5 +3665,5 @@
    0x14, 0x15, 0x25, 0x32, 0x6C, 0x69, 0x1A, 0xCF };
 
-unsigned char table_168[256] = {
+static const unsigned char table_168[256] = {
    0x28, 0xEE, 0xB1, 0xFD, 0xB3, 0xEF, 0x36, 0x8E,
    0x85, 0x5D, 0x1C, 0x53, 0x1E, 0xDA, 0xBA, 0x3C,
@@ -3699,5 +3699,5 @@
    0x66, 0x2E, 0x08, 0x32, 0x4C, 0x33, 0x7E, 0xE1 };
 
-unsigned char table_169[256] = {
+static const unsigned char table_169[256] = {
    0xA4, 0x31, 0xA9, 0x3F, 0x13, 0x4D, 0x1B, 0x29,
    0x73, 0x43, 0xF1, 0xE7, 0x9C, 0xC2, 0xF6, 0xCD,
@@ -3733,5 +3733,5 @@
    0x6B, 0x0A, 0x59, 0x9E, 0x5E, 0x38, 0x45, 0x80 };
 
-unsigned char table_170[256] = {
+static const unsigned char table_170[256] = {
    0xE3, 0x00, 0x99, 0x03, 0xF6, 0xDD, 0xD1, 0x41,
    0x58, 0x7E, 0xD9, 0x46, 0x04, 0xAF, 0x5C, 0x43,
@@ -3767,5 +3767,5 @@
    0x48, 0x30, 0x87, 0x83, 0x12, 0x4D, 0x65, 0xDF };
 
-unsigned char table_171[32] = {
+static const unsigned char table_171[32] = {
    0x07, 0x06, 0x11, 0x08, 0x0C, 0x1F, 0x19, 0x02,
    0x14, 0x04, 0x0D, 0x18, 0x1A, 0x05, 0x17, 0x13,
@@ -3773,5 +3773,5 @@
    0x1D, 0x10, 0x00, 0x12, 0x0B, 0x0E, 0x09, 0x0A };
 
-unsigned char table_172[32] = {
+static const unsigned char table_172[32] = {
    0x11, 0x01, 0x1F, 0x06, 0x1A, 0x04, 0x02, 0x09,
    0x05, 0x0D, 0x0B, 0x18, 0x0E, 0x12, 0x1B, 0x17,
@@ -3779,5 +3779,5 @@
    0x03, 0x0C, 0x00, 0x10, 0x0A, 0x1C, 0x0F, 0x13 };
 
-unsigned char table_173[32] = {
+static const unsigned char table_173[32] = {
    0x1F, 0x0B, 0x13, 0x00, 0x16, 0x15, 0x14, 0x0A,
    0x1D, 0x05, 0x1E, 0x1A, 0x0F, 0x04, 0x0E, 0x01,
@@ -3785,5 +3785,5 @@
    0x03, 0x11, 0x18, 0x10, 0x1C, 0x1B, 0x06, 0x0D };
 
-unsigned char table_174[32] = {
+static const unsigned char table_174[32] = {
    0x02, 0x1B, 0x0C, 0x17, 0x1F, 0x05, 0x15, 0x1E,
    0x16, 0x09, 0x1A, 0x12, 0x0F, 0x1C, 0x18, 0x0A,
@@ -3791,5 +3791,5 @@
    0x1D, 0x0E, 0x06, 0x00, 0x01, 0x07, 0x0B, 0x03 };
 
-unsigned char table_175[32] = {
+static const unsigned char table_175[32] = {
    0x00, 0x06, 0x0B, 0x08, 0x0C, 0x04, 0x1A, 0x1C,
    0x05, 0x1E, 0x14, 0x03, 0x0A, 0x18, 0x12, 0x1D,
@@ -3797,5 +3797,5 @@
    0x11, 0x19, 0x10, 0x0D, 0x1B, 0x02, 0x01, 0x15 };
 
-unsigned char table_176[32] = {
+static const unsigned char table_176[32] = {
    0x12, 0x03, 0x1A, 0x15, 0x04, 0x19, 0x0B, 0x1B,
    0x17, 0x1E, 0x0D, 0x05, 0x11, 0x14, 0x1C, 0x00,
@@ -3803,5 +3803,5 @@
    0x13, 0x09, 0x16, 0x1D, 0x0F, 0x0C, 0x01, 0x1F };
 
-unsigned char table_177[256] = {
+static const unsigned char table_177[256] = {
    0x5E, 0x4D, 0x76, 0xFE, 0xB5, 0x50, 0x83, 0x23,
    0x72, 0xDD, 0x93, 0x08, 0x69, 0xAD, 0xEC, 0x3B,
@@ -3837,5 +3837,5 @@
    0x5A, 0xC5, 0xE0, 0x58, 0x41, 0x4E, 0x4A, 0xAF };
 
-unsigned char table_178[256] = {
+static const unsigned char table_178[256] = {
    0x33, 0xBA, 0x98, 0xDA, 0x07, 0x2C, 0x22, 0x9B,
    0xE0, 0xED, 0xB7, 0xA1, 0x93, 0xEB, 0xDC, 0x49,
@@ -3871,5 +3871,5 @@
    0x95, 0x9E, 0xBF, 0xEF, 0xF8, 0x45, 0x00, 0xB4 };
 
-unsigned char table_179[256] = {
+static const unsigned char table_179[256] = {
    0x50, 0x3D, 0x41, 0x42, 0x06, 0x5B, 0xD6, 0x34,
    0x9D, 0x3C, 0x7B, 0x14, 0xE2, 0x9B, 0x80, 0x15,
@@ -3905,5 +3905,5 @@
    0x2A, 0x04, 0x18, 0xA5, 0xA2, 0x6E, 0x07, 0xE3 };
 
-unsigned char table_180[256] = {
+static const unsigned char table_180[256] = {
    0xDA, 0xCC, 0x72, 0xA6, 0xE7, 0x07, 0xFD, 0x25,
    0x92, 0x39, 0x49, 0x02, 0xD6, 0x09, 0xA8, 0x65,
@@ -3939,5 +3939,5 @@
    0x62, 0x4F, 0xCF, 0xB2, 0xC2, 0x59, 0xDB, 0x67 };
 
-unsigned char table_181[256] = {
+static const unsigned char table_181[256] = {
    0x2B, 0xED, 0x14, 0x05, 0x80, 0xCC, 0x5A, 0xF8,
    0x43, 0xB7, 0x86, 0xC6, 0xEE, 0xA6, 0xD7, 0xD6,
@@ -3973,5 +3973,5 @@
    0x32, 0x24, 0x7D, 0x9B, 0xD2, 0x83, 0x35, 0xCD };
 
-unsigned char table_182[256] = {
+static const unsigned char table_182[256] = {
    0x06, 0x7F, 0x66, 0xB5, 0xBA, 0x1E, 0xFD, 0x51,
    0x81, 0x8D, 0x28, 0xA3, 0x15, 0x37, 0xDC, 0x58,
@@ -4007,5 +4007,5 @@
    0x7B, 0x17, 0x0B, 0x0A, 0x41, 0x03, 0xD4, 0x4B };
 
-unsigned char table_183[32] = {
+static const unsigned char table_183[32] = {
    0x1E, 0x1B, 0x11, 0x07, 0x08, 0x06, 0x18, 0x17,
    0x0D, 0x0F, 0x12, 0x03, 0x1D, 0x04, 0x0A, 0x1A,
@@ -4013,5 +4013,5 @@
    0x16, 0x05, 0x1C, 0x0E, 0x02, 0x00, 0x09, 0x15 };
 
-unsigned char table_184[32] = {
+static const unsigned char table_184[32] = {
    0x0F, 0x1D, 0x17, 0x16, 0x0D, 0x05, 0x13, 0x1F,
    0x1B, 0x09, 0x1C, 0x1E, 0x15, 0x01, 0x06, 0x08,
@@ -4019,5 +4019,5 @@
    0x18, 0x0E, 0x03, 0x11, 0x12, 0x14, 0x19, 0x00 };
 
-unsigned char table_185[256] = {
+static const unsigned char table_185[256] = {
    0xA5, 0xEE, 0x2E, 0x28, 0xA7, 0xAC, 0xD9, 0xB2,
    0x6E, 0x04, 0xB4, 0x03, 0xE8, 0x92, 0x5F, 0x4D,
@@ -4053,5 +4053,5 @@
    0x2B, 0xC5, 0x98, 0x18, 0x66, 0x15, 0x9C, 0xBC };
 
-unsigned char table_186[256] = {
+static const unsigned char table_186[256] = {
    0xB7, 0xFA, 0x03, 0x7C, 0x76, 0x43, 0xA7, 0x15,
    0x4B, 0x4F, 0x04, 0xAA, 0x4E, 0xD2, 0x52, 0xC8,
@@ -4087,5 +4087,5 @@
    0x11, 0x3B, 0x94, 0xE8, 0x7D, 0x7B, 0xD9, 0x5A };
 
-unsigned char table_187[32] = {
+static const unsigned char table_187[32] = {
    0x0F, 0x04, 0x1D, 0x1B, 0x15, 0x10, 0x01, 0x0B,
    0x00, 0x17, 0x13, 0x07, 0x1E, 0x1F, 0x08, 0x0A,
@@ -4093,5 +4093,5 @@
    0x0E, 0x18, 0x03, 0x1C, 0x12, 0x11, 0x0D, 0x02 };
 
-struct yahoo_fn yahoo_fntable[5][96] = 
+static const struct yahoo_fn yahoo_fntable[5][96] = 
    {{{ IDENT, 0, 0 },
      { IDENT, 0, 0 },
@@ -4582,5 +4582,5 @@
 int yahoo_xfrm( int table, int depth, int seed )
 {
-   struct yahoo_fn *xfrm;
+   const struct yahoo_fn *xfrm;
    int i, j, z;
    unsigned int n = seed;
Index: otocols/yahoo/yahoo_list.c
===================================================================
--- protocols/yahoo/yahoo_list.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ 	(revision )
@@ -1,236 +1,0 @@
-/*
- * yahoo_list.c: linked list routines
- *
- * Some code copyright (C) 2002-2004, Philip S Tellis <philip.tellis AT gmx.net>
- * Other code copyright Meredydd Luff <meredydd AT everybuddy.com>
- *
- * 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
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Some of this code was borrowed from elist.c in the eb-lite sources
- *
- */
-
-#include <stdlib.h>
-
-#include "yahoo_list.h"
-
-YList *y_list_append(YList * list, void *data)
-{
-	YList *n;
-	YList *new_list = malloc(sizeof(YList));
-	YList *attach_to = NULL;
-
-	new_list->next = NULL;
-	new_list->data = data;
-
-	for (n = list; n != NULL; n = n->next) {
-		attach_to = n;
-	}
-
-	if (attach_to == NULL) {
-		new_list->prev = NULL;
-		return new_list;
-	} else {
-		new_list->prev = attach_to;
-		attach_to->next = new_list;
-		return list;
-	}
-}
-
-YList *y_list_prepend(YList * list, void *data)
-{
-	YList *n = malloc(sizeof(YList));
-
-	n->next = list;
-	n->prev = NULL;
-	n->data = data;
-	if (list)
-		list->prev = n;
-
-	return n;
-}
-
-YList *y_list_concat(YList * list, YList * add)
-{
-	YList *l;
-
-	if(!list)
-		return add;
-
-	if(!add)
-		return list;
-
-	for (l = list; l->next; l = l->next)
-		;
-
-	l->next = add;
-	add->prev = l;
-
-	return list;
-}
-
-YList *y_list_remove(YList * list, void *data)
-{
-	YList *n;
-
-	for (n = list; n != NULL; n = n->next) {
-		if (n->data == data) {
-			list=y_list_remove_link(list, n);
-			y_list_free_1(n);
-			break;
-		}
-	}
-
-	return list;
-}
-
-/* Warning */
-/* link MUST be part of list */
-/* caller must free link using y_list_free_1 */
-YList *y_list_remove_link(YList * list, const YList * link)
-{
-	if (!link)
-		return list;
-
-	if (link->next)
-		link->next->prev = link->prev;
-	if (link->prev)
-		link->prev->next = link->next;
-
-	if (link == list)
-		list = link->next;
-	
-	return list;
-}
-
-int y_list_length(const YList * list)
-{
-	int retval = 0;
-	const YList *n = list;
-
-	for (n = list; n != NULL; n = n->next) {
-		retval++;
-	}
-
-	return retval;
-}
-
-/* well, you could just check for list == NULL, but that would be
- * implementation dependent
- */
-int y_list_empty(const YList * list)
-{
-	if(!list)
-		return 1;
-	else
-		return 0;
-}
-
-int y_list_singleton(const YList * list)
-{
-	if(!list || list->next)
-		return 0;
-	return 1;
-}
-
-YList *y_list_copy(YList * list)
-{
-	YList *n;
-	YList *copy = NULL;
-
-	for (n = list; n != NULL; n = n->next) {
-		copy = y_list_append(copy, n->data);
-	}
-
-	return copy;
-}
-
-void y_list_free_1(YList * list)
-{
-	free(list);
-}
-
-void y_list_free(YList * list)
-{
-	YList *n = list;
-
-	while (n != NULL) {
-		YList *next = n->next;
-		free(n);
-		n = next;
-	}
-}
-
-YList *y_list_find(YList * list, const void *data)
-{
-	YList *l;
-	for (l = list; l && l->data != data; l = l->next)
-		;
-
-	return l;
-}
-
-void y_list_foreach(YList * list, YListFunc fn, void * user_data)
-{
-	for (; list; list = list->next)
-		fn(list->data, user_data);
-}
-
-YList *y_list_find_custom(YList * list, const void *data, YListCompFunc comp)
-{
-	YList *l;
-	for (l = list; l; l = l->next)
-		if (comp(l->data, data) == 0)
-			return l;
-
-	return NULL;
-}
-
-YList *y_list_nth(YList * list, int n)
-{
-	int i=n;
-	for ( ; list && i; list = list->next, i--)
-		;
-
-	return list;
-}
-
-YList *y_list_insert_sorted(YList * list, void *data, YListCompFunc comp)
-{
-	YList *l, *n, *prev = NULL;
-	if (!list)
-		return y_list_append(list, data);
-
-       	n = malloc(sizeof(YList));
-	n->data = data;
-	for (l = list; l && comp(l->data, n->data) <= 0; l = l->next)
-		prev = l;
-
-	if (l) {
-		n->prev = l->prev;
-		l->prev = n;
-	} else
-		n->prev = prev;
-
-	n->next = l;
-
-	if(n->prev) {
-		n->prev->next = n;
-		return list;
-	} else {
-		return n;
-	}
-		
-}
Index: protocols/yahoo/yahoo_list.h
===================================================================
--- protocols/yahoo/yahoo_list.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/yahoo/yahoo_list.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -21,54 +21,28 @@
  */
 
-/*
- * This is a replacement for the GList.  It only provides functions that 
- * we use in Ayttm.  Thanks to Meredyyd from everybuddy dev for doing 
- * most of it.
- */
-
 #ifndef __YLIST_H__
 #define __YLIST_H__
 
-#ifdef __cplusplus
-extern "C" {
+/* GLib has linked list already, so I don't see why libyahoo2 has to copy this... */
+
+typedef GList YList;
+
+#define y_list_append g_list_append
+#define y_list_concat g_list_concat
+#define y_list_copy g_list_copy
+#define y_list_empty g_list_empty
+#define y_list_find g_list_find
+#define y_list_find_custom g_list_find_custom
+#define y_list_foreach g_list_foreach
+#define y_list_free g_list_free
+#define y_list_free_1 g_list_free_1
+#define y_list_insert_sorted g_list_insert_sorted
+#define y_list_length g_list_length
+#define y_list_next g_list_next
+#define y_list_nth g_list_nth
+#define y_list_prepend g_list_prepend
+#define y_list_remove g_list_remove
+#define y_list_remove_link g_list_remove_link
+#define y_list_singleton g_list_singleton
+
 #endif
-
-typedef struct _YList {
-	struct _YList *next;
-	struct _YList *prev;
-	void *data;
-} YList;
-
-typedef int (*YListCompFunc) (const void *, const void *);
-typedef void (*YListFunc) (void *, void *);
-
-YList *y_list_append(YList * list, void *data);
-YList *y_list_prepend(YList * list, void *data);
-YList *y_list_remove_link(YList * list, const YList * link);
-YList *y_list_remove(YList * list, void *data);
-
-YList *y_list_insert_sorted(YList * list, void * data, YListCompFunc comp);
-
-YList *y_list_copy(YList * list);
-
-YList *y_list_concat(YList * list, YList * add);
-
-YList *y_list_find(YList * list, const void *data);
-YList *y_list_find_custom(YList * list, const void *data, YListCompFunc comp);
-
-YList *y_list_nth(YList * list, int n);
-
-void y_list_foreach(YList * list, YListFunc fn, void *user_data);
-
-void y_list_free_1(YList * list);
-void y_list_free(YList * list);
-int  y_list_length(const YList * list);
-int  y_list_empty(const YList * list);
-int  y_list_singleton(const YList * list);
-
-#define y_list_next(list)	list->next
-
-#ifdef __cplusplus
-}
-#endif
-#endif
Index: protocols/yahoo/yahoo_util.c
===================================================================
--- protocols/yahoo/yahoo_util.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ protocols/yahoo/yahoo_util.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -50,54 +50,4 @@
 
 	return new_string;
-}
-
-char * y_str_to_utf8(const char *in)
-{
-	unsigned int n, i = 0;
-	char *result = NULL;
-
-	if(in == NULL || *in == '\0')
-		return "";
-	
-	result = y_new(char, strlen(in) * 2 + 1);
-
-	/* convert a string to UTF-8 Format */
-	for (n = 0; n < strlen(in); n++) {
-		unsigned char c = (unsigned char)in[n];
-
-		if (c < 128) {
-			result[i++] = (char) c;
-		} else {
-			result[i++] = (char) ((c >> 6) | 192);
-			result[i++] = (char) ((c & 63) | 128);
-		}
-	}
-	result[i] = '\0';
-	return result;
-}
-
-char * y_utf8_to_str(const char *in)
-{
-	int i = 0;
-	unsigned int n;
-	char *result = NULL;
-
-	if(in == NULL || *in == '\0')
-		return "";
-	
-	result = y_new(char, strlen(in) + 1);
-
-	/* convert a string from UTF-8 Format */
-	for (n = 0; n < strlen(in); n++) {
-		unsigned char c = in[n];
-
-		if (c < 128) {
-			result[i++] = (char) c;
-		} else {
-			result[i++] = (c << 6) | (in[++n] & 63);
-		}
-	}
-	result[i] = '\0';
-	return result;
 }
 
Index: root_commands.c
===================================================================
--- root_commands.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
+++ root_commands.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -0,0 +1,803 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/* User manager (root) commands                                         */
+
+/*
+  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 "commands.h"
+#include "crypting.h"
+#include "bitlbee.h"
+#include "help.h"
+
+#include <string.h>
+
+void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
+{
+	char *cmd[IRC_MAX_ARGS];
+	char *s;
+	int k;
+	char q = 0;
+	
+	memset( cmd, 0, sizeof( cmd ) );
+	cmd[0] = command;
+	k = 1;
+	for( s = command; *s && k < ( IRC_MAX_ARGS - 1 ); s ++ )
+		if( *s == ' ' && !q )
+		{
+			*s = 0;
+			while( *++s == ' ' );
+			if( *s == '"' || *s == '\'' )
+			{
+				q = *s;
+				s ++;
+			}
+			if( *s )
+			{
+				cmd[k++] = s;
+				s --;
+			}
+		}
+		else if( *s == q )
+		{
+			q = *s = 0;
+		}
+	cmd[k] = NULL;
+	
+	root_command( irc, cmd );
+}
+
+void root_command( irc_t *irc, char *cmd[] )
+{	
+	int i;
+	
+	if( !cmd[0] )
+		return;
+	
+	for( i = 0; commands[i].command; i++ )
+		if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
+		{
+			if( !cmd[commands[i].required_parameters] )
+			{
+				irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters );
+				return;
+			}
+			commands[i].execute( irc, cmd );
+			return;
+		}
+	
+	irc_usermsg( irc, "Unknown command: %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[0] );
+}
+
+static void cmd_help( irc_t *irc, char **cmd )
+{
+	char param[80];
+	int i;
+	char *s;
+	
+	memset( param, 0, sizeof(param) );
+	for ( i = 1; (cmd[i] != NULL && ( strlen(param) < (sizeof(param)-1) ) ); i++ ) {
+		if ( i != 1 )	// prepend space except for the first parameter
+			strcat(param, " ");
+		strncat( param, cmd[i], sizeof(param) - strlen(param) - 1 );
+	}
+
+	s = help_get( &(global.help), param );
+	if( !s ) s = help_get( &(global.help), "" );
+	
+	if( s )
+	{
+		irc_usermsg( irc, "%s", s );
+		g_free( s );
+	}
+	else
+	{
+		irc_usermsg( irc, "Error opening helpfile." );
+	}
+}
+
+static void cmd_identify( irc_t *irc, char **cmd )
+{
+	storage_status_t status = storage_load( irc->nick, cmd[1], irc );
+	
+	switch (status) {
+	case STORAGE_INVALID_PASSWORD:
+		irc_usermsg( irc, "Incorrect password" );
+		break;
+	case STORAGE_NO_SUCH_USER:
+		irc_usermsg( irc, "The nick is (probably) not registered" );
+		break;
+	case STORAGE_OK:
+		irc_usermsg( irc, "Password accepted" );
+		irc_umode_set( irc, "+R", 1 );
+		break;
+	default:
+		irc_usermsg( irc, "Something very weird happened" );
+		break;
+	}
+}
+
+static void cmd_register( irc_t *irc, char **cmd )
+{
+	if( global.conf->authmode == AUTHMODE_REGISTERED )
+	{
+		irc_usermsg( irc, "This server does not allow registering new accounts" );
+		return;
+	}
+
+	irc_setpass( irc, cmd[1] );
+	switch( storage_save( irc, FALSE )) {
+		case STORAGE_ALREADY_EXISTS:
+			irc_usermsg( irc, "Nick is already registered" );
+			break;
+			
+		case STORAGE_OK:
+			irc->status = USTATUS_IDENTIFIED;
+			irc_umode_set( irc, "+R", 1 );
+			break;
+
+		default:
+			irc_usermsg( irc, "Error registering" );
+			break;
+	}
+}
+
+static void cmd_drop( irc_t *irc, char **cmd )
+{
+	storage_status_t status;
+	
+	status = storage_remove (irc->nick, cmd[1]);
+	switch (status) {
+	case STORAGE_NO_SUCH_USER:
+		irc_usermsg( irc, "That account does not exist" );
+		break;
+	case STORAGE_INVALID_PASSWORD:
+		irc_usermsg( irc, "Password invalid" );
+		break;
+	case STORAGE_OK:
+		irc_setpass( irc, NULL );
+		irc->status = USTATUS_LOGGED_IN;
+		irc_umode_set( irc, "-R", 1 );
+		irc_usermsg( irc, "Account `%s' removed", irc->nick );
+		break;
+	default:
+		irc_usermsg( irc, "Error: '%d'", status );
+		break;
+	}
+}
+
+static void cmd_account( irc_t *irc, char **cmd )
+{
+	account_t *a;
+	
+	if( global.conf->authmode == AUTHMODE_REGISTERED && irc->status < USTATUS_IDENTIFIED )
+	{
+		irc_usermsg( irc, "This server only accepts registered users" );
+		return;
+	}
+	
+	if( g_strcasecmp( cmd[1], "add" ) == 0 )
+	{
+		struct prpl *prpl;
+		
+		if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL )
+		{
+			irc_usermsg( irc, "Not enough parameters" );
+			return;
+		}
+		
+		prpl = find_protocol(cmd[2]);
+		
+		if( prpl == NULL )
+		{
+			irc_usermsg( irc, "Unknown protocol" );
+			return;
+		}
+
+		a = account_add( irc, prpl, cmd[3], cmd[4] );
+		
+		if( cmd[5] )
+			a->server = g_strdup( cmd[5] );
+		
+		irc_usermsg( irc, "Account successfully added" );
+	}
+	else if( g_strcasecmp( cmd[1], "del" ) == 0 )
+	{
+		if( !cmd[2] )
+		{
+			irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
+		}
+		else if( !( a = account_get( irc, cmd[2] ) ) )
+		{
+			irc_usermsg( irc, "Invalid account" );
+		}
+		else if( a->gc )
+		{
+			irc_usermsg( irc, "Account is still logged in, can't delete" );
+		}
+		else
+		{
+			account_del( irc, a );
+			irc_usermsg( irc, "Account deleted" );
+		}
+	}
+	else if( g_strcasecmp( cmd[1], "list" ) == 0 )
+	{
+		int i = 0;
+		
+		for( a = irc->accounts; a; a = a->next )
+		{
+			char *con;
+			
+			if( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) )
+				con = " (connected)";
+			else if( a->gc )
+				con = " (connecting)";
+			else if( a->reconnect )
+				con = " (awaiting reconnect)";
+			else
+				con = "";
+			
+			irc_usermsg( irc, "%2d. %s, %s%s", i, a->prpl->name, a->user, con );
+			
+			i ++;
+		}
+		irc_usermsg( irc, "End of account list" );
+	}
+	else if( g_strcasecmp( cmd[1], "on" ) == 0 )
+	{
+		if( cmd[2] )
+		{
+			if( ( a = account_get( irc, cmd[2] ) ) )
+			{
+				if( a->gc )
+				{
+					irc_usermsg( irc, "Account already online" );
+					return;
+				}
+				else
+				{
+					account_on( irc, a );
+				}
+			}
+			else
+			{
+				irc_usermsg( irc, "Invalid account" );
+				return;
+			}
+		}
+		else
+		{
+			if ( irc->accounts ) {
+				irc_usermsg( irc, "Trying to get all accounts connected..." );
+			
+				for( a = irc->accounts; a; a = a->next )
+					if( !a->gc )
+						account_on( irc, a );
+			} 
+			else
+			{
+				irc_usermsg( irc, "No accounts known. Use 'account add' to add one." );
+			}
+		}
+	}
+	else if( g_strcasecmp( cmd[1], "off" ) == 0 )
+	{
+		if( !cmd[2] )
+		{
+			irc_usermsg( irc, "Deactivating all active (re)connections..." );
+			
+			for( a = irc->accounts; a; a = a->next )
+			{
+				if( a->gc )
+					account_off( irc, a );
+				else if( a->reconnect )
+					cancel_auto_reconnect( a );
+			}
+		}
+		else if( ( a = account_get( irc, cmd[2] ) ) )
+		{
+			if( a->gc )
+			{
+				account_off( irc, a );
+			}
+			else if( a->reconnect )
+			{
+				cancel_auto_reconnect( a );
+				irc_usermsg( irc, "Reconnect cancelled" );
+			}
+			else
+			{
+				irc_usermsg( irc, "Account already offline" );
+				return;
+			}
+		}
+		else
+		{
+			irc_usermsg( irc, "Invalid account" );
+			return;
+		}
+	}
+	else
+	{
+		irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] );
+	}
+}
+
+static void cmd_add( irc_t *irc, char **cmd )
+{
+	account_t *a;
+	
+	if( !( a = account_get( irc, cmd[1] ) ) )
+	{
+		irc_usermsg( irc, "Invalid account" );
+		return;
+	}
+	else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) )
+	{
+		irc_usermsg( irc, "That account is not on-line" );
+		return;
+	}
+	
+	if( cmd[3] )
+	{
+		if( !nick_ok( cmd[3] ) )
+		{
+			irc_usermsg( irc, "The requested nick `%s' is invalid", cmd[3] );
+			return;
+		}
+		else if( user_find( irc, cmd[3] ) )
+		{
+			irc_usermsg( irc, "The requested nick `%s' already exists", cmd[3] );
+			return;
+		}
+		else
+		{
+			nick_set( irc, cmd[2], a->gc->prpl, cmd[3] );
+		}
+	}
+	a->gc->prpl->add_buddy( a->gc, cmd[2] );
+	add_buddy( a->gc, NULL, cmd[2], cmd[2] );
+	
+	irc_usermsg( irc, "User `%s' added to your contact list as `%s'", cmd[2], user_findhandle( a->gc, cmd[2] )->nick );
+}
+
+static void cmd_info( irc_t *irc, char **cmd )
+{
+	struct gaim_connection *gc;
+	account_t *a;
+	
+	if( !cmd[2] )
+	{
+		user_t *u = user_find( irc, cmd[1] );
+		if( !u || !u->gc )
+		{
+			irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
+			return;
+		}
+		gc = u->gc;
+		cmd[2] = u->handle;
+	}
+	else 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( !gc->prpl->get_info )
+	{
+		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
+	}
+	else
+	{
+		gc->prpl->get_info( gc, cmd[2] );
+	}
+}
+
+static void cmd_rename( irc_t *irc, char **cmd )
+{
+	user_t *u;
+	
+	if( g_strcasecmp( cmd[1], irc->nick ) == 0 )
+	{
+		irc_usermsg( irc, "Nick `%s' can't be changed", cmd[1] );
+	}
+	else if( user_find( irc, cmd[2] ) && ( nick_cmp( cmd[1], cmd[2] ) != 0 ) )
+	{
+		irc_usermsg( irc, "Nick `%s' already exists", cmd[2] );
+	}
+	else if( !nick_ok( cmd[2] ) )
+	{
+		irc_usermsg( irc, "Nick `%s' is invalid", cmd[2] );
+	}
+	else if( !( u = user_find( irc, cmd[1] ) ) )
+	{
+		irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
+	}
+	else
+	{
+		user_rename( irc, cmd[1], cmd[2] );
+		irc_write( irc, ":%s!%s@%s NICK %s", cmd[1], u->user, u->host, cmd[2] );
+		if( g_strcasecmp( cmd[1], irc->mynick ) == 0 )
+		{
+			g_free( irc->mynick );
+			irc->mynick = g_strdup( cmd[2] );
+		}
+		else if( u->send_handler == buddy_send_handler )
+		{
+			nick_set( irc, u->handle, u->gc->prpl, cmd[2] );
+		}
+		
+		irc_usermsg( irc, "Nick successfully changed" );
+	}
+}
+
+static void cmd_remove( irc_t *irc, char **cmd )
+{
+	user_t *u;
+	char *s;
+	
+	if( !( u = user_find( irc, cmd[1] ) ) || !u->gc )
+	{
+		irc_usermsg( irc, "Buddy `%s' not found", cmd[1] );
+		return;
+	}
+	s = g_strdup( u->handle );
+	
+	u->gc->prpl->remove_buddy( u->gc, u->handle, NULL );
+	user_del( irc, cmd[1] );
+	nick_del( irc, cmd[1] );
+	
+	irc_usermsg( irc, "Buddy `%s' (nick %s) removed from contact list", s, cmd[1] );
+	g_free( s );
+	
+	return;
+}
+
+static void cmd_block( irc_t *irc, char **cmd )
+{
+	struct gaim_connection *gc;
+	account_t *a;
+	
+	if( !cmd[2] )
+	{
+		user_t *u = user_find( irc, cmd[1] );
+		if( !u || !u->gc )
+		{
+			irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
+			return;
+		}
+		gc = u->gc;
+		cmd[2] = u->handle;
+	}
+	else 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( !gc->prpl->add_deny || !gc->prpl->rem_permit )
+	{
+		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
+	}
+	else
+	{
+		gc->prpl->rem_permit( gc, cmd[2] );
+		gc->prpl->add_deny( gc, cmd[2] );
+		irc_usermsg( irc, "Buddy `%s' moved from your permit- to your deny-list", cmd[2] );
+	}
+}
+
+static void cmd_allow( irc_t *irc, char **cmd )
+{
+	struct gaim_connection *gc;
+	account_t *a;
+	
+	if( !cmd[2] )
+	{
+		user_t *u = user_find( irc, cmd[1] );
+		if( !u || !u->gc )
+		{
+			irc_usermsg( irc, "Nick `%s' does not exist", cmd[1] );
+			return;
+		}
+		gc = u->gc;
+		cmd[2] = u->handle;
+	}
+	else 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( !gc->prpl->rem_deny || !gc->prpl->add_permit )
+	{
+		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
+	}
+	else
+	{
+		gc->prpl->rem_deny( gc, cmd[2] );
+		gc->prpl->add_permit( gc, cmd[2] );
+		
+		irc_usermsg( irc, "Buddy `%s' moved from your deny- to your permit-list", cmd[2] );
+	}
+}
+
+static void cmd_yesno( irc_t *irc, char **cmd )
+{
+	query_t *q = NULL;
+	int numq = 0;
+	
+	if( irc->queries == NULL )
+	{
+		irc_usermsg( irc, "Did I ask you something?" );
+		return;
+	}
+	
+	/* If there's an argument, the user seems to want to answer another question than the
+	   first/last (depending on the query_order setting) one. */
+	if( cmd[1] )
+	{
+		if( sscanf( cmd[1], "%d", &numq ) != 1 )
+		{
+			irc_usermsg( irc, "Invalid query number" );
+			return;
+		}
+		
+		for( q = irc->queries; q; q = q->next, numq -- )
+			if( numq == 0 )
+				break;
+		
+		if( !q )
+		{
+			irc_usermsg( irc, "Uhm, I never asked you something like that..." );
+			return;
+		}
+	}
+	
+	if( g_strcasecmp( cmd[0], "yes" ) == 0 )
+		query_answer( irc, q, 1 );
+	else if( g_strcasecmp( cmd[0], "no" ) == 0 )
+		query_answer( irc, q, 0 );
+}
+
+static void cmd_set( irc_t *irc, char **cmd )
+{
+	if( cmd[1] && cmd[2] )
+	{
+		set_setstr( irc, cmd[1], cmd[2] );
+		
+		if( ( strcmp( cmd[2], "=" ) ) == 0 && cmd[3] )
+			irc_usermsg( irc, "Warning: Correct syntax: \002set <variable> <value>\002 (without =)" );
+	}
+	if( cmd[1] ) /* else 'forgotten' on purpose.. Must show new value after changing */
+	{
+		char *s = set_getstr( irc, cmd[1] );
+		if( s )
+			irc_usermsg( irc, "%s = `%s'", cmd[1], s );
+	}
+	else
+	{
+		set_t *s = irc->set;
+		while( s )
+		{
+			if( s->value || s->def )
+				irc_usermsg( irc, "%s = `%s'", s->key, s->value?s->value:s->def );
+			s = s->next;
+		}
+	}
+}
+
+static void cmd_save( irc_t *irc, char **cmd )
+{
+	if( storage_save( irc, TRUE ) == STORAGE_OK )
+		irc_usermsg( irc, "Configuration saved" );
+	else
+		irc_usermsg( irc, "Configuration could not be saved!" );
+}
+
+static void cmd_blist( irc_t *irc, char **cmd )
+{
+	int online = 0, away = 0, offline = 0;
+	user_t *u;
+	char s[64];
+	int n_online = 0, n_away = 0, n_offline = 0;
+	
+	if( cmd[1] && g_strcasecmp( cmd[1], "all" ) == 0 )
+		online = offline = away = 1;
+	else if( cmd[1] && g_strcasecmp( cmd[1], "offline" ) == 0 )
+		offline = 1;
+	else if( cmd[1] && g_strcasecmp( cmd[1], "away" ) == 0 )
+		away = 1;
+	else if( cmd[1] && g_strcasecmp( cmd[1], "online" ) == 0 )
+		online = 1;
+	else
+		online =  away = 1;
+	
+	irc_usermsg( irc, "%-16.16s  %-40.40s  %s", "Nick", "User/Host/Network", "Status" );
+	
+	if( online == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && !u->away )
+	{
+		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
+		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Online" );
+		n_online ++;
+	}
+
+	if( away == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && u->online && u->away )
+	{
+		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
+		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, u->away );
+		n_away ++;
+	}
+	
+	if( offline == 1 ) for( u = irc->users; u; u = u->next ) if( u->gc && !u->online )
+	{
+		g_snprintf( s, 63, "%s@%s (%s)", u->user, u->host, u->gc->user->prpl->name );
+		irc_usermsg( irc, "%-16.16s  %-40.40s  %s", u->nick, s, "Offline" );
+		n_offline ++;
+	}
+	
+	irc_usermsg( irc, "%d buddies (%d available, %d away, %d offline)", n_online + n_away + n_offline, n_online, n_away, n_offline );
+}
+
+static void cmd_nick( irc_t *irc, char **cmd ) 
+{
+	account_t *a;
+
+	if( !cmd[1] || !( a = account_get( irc, cmd[1] ) ) )
+	{
+		irc_usermsg( irc, "Invalid account");
+	}
+	else if( !( a->gc && ( a->gc->flags & OPT_LOGGED_IN ) ) )
+	{
+		irc_usermsg( irc, "That account is not on-line" );
+	}
+	else if ( !cmd[2] ) 
+	{
+		irc_usermsg( irc, "Your name is `%s'" , a->gc->displayname ? a->gc->displayname : "NULL" );
+	}
+	else if ( !a->gc->prpl->set_info ) 
+	{
+		irc_usermsg( irc, "Command `%s' not supported by this protocol", cmd[0] );
+	}
+	else
+	{
+		char utf8[1024];
+		
+		irc_usermsg( irc, "Setting your name to `%s'", cmd[2] );
+		
+		if( g_strncasecmp( set_getstr( irc, "charset" ), "none", 4 ) != 0 &&
+		    do_iconv( set_getstr( irc, "charset" ), "UTF-8", cmd[2], utf8, 0, 1024 ) != -1 )
+			a->gc->prpl->set_info( a->gc, utf8 );
+		else
+			a->gc->prpl->set_info( a->gc, cmd[2] );
+	}
+}
+
+static void cmd_qlist( irc_t *irc, char **cmd )
+{
+	query_t *q = irc->queries;
+	int num;
+	
+	if( !q )
+	{
+		irc_usermsg( irc, "There are no pending questions." );
+		return;
+	}
+	
+	irc_usermsg( irc, "Pending queries:" );
+	
+	for( num = 0; q; q = q->next, num ++ )
+		if( q->gc ) /* Not necessary yet, but it might come later */
+			irc_usermsg( irc, "%d, %s(%s): %s", num, q->gc->prpl->name, q->gc->username, q->question );
+		else
+			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;
+			
+			for( u = irc->users; u; u = u->next )
+				if( u->gc == gc )
+				{
+					u->gc->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->prpl && !user_findhandle( gc, n->handle ) )
+		{
+	                gc->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 },
+	{ "register",       1, cmd_register,       0 },
+	{ "drop",           1, cmd_drop,           0 },
+	{ "account",        1, cmd_account,        0 },
+	{ "add",            2, cmd_add,            0 },
+	{ "info",           1, cmd_info,           0 },
+	{ "rename",         2, cmd_rename,         0 },
+	{ "remove",         1, cmd_remove,         0 },
+	{ "block",          1, cmd_block,          0 },
+	{ "allow",          1, cmd_allow,          0 },
+	{ "save",           0, cmd_save,           0 },
+	{ "set",            0, cmd_set,            0 },
+	{ "yes",            0, cmd_yesno,          0 },
+	{ "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 }
+};
Index: sock.h
===================================================================
--- sock.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ sock.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -1,4 +1,11 @@
 #include <errno.h>
 #include <fcntl.h>
+
+/* To cut down on the ifdef stuff a little bit in other places */
+#ifdef IPV6
+#define AF_INETx AF_INET6
+#else
+#define AF_INETx AF_INET
+#endif
 
 #ifndef _WIN32
Index: storage_text.c
===================================================================
--- storage_text.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ storage_text.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -71,5 +71,5 @@
 	user_t *ru = user_find( irc, ROOT_NICK );
 	
-	if( irc->status == USTATUS_IDENTIFIED )
+	if( irc->status >= USTATUS_IDENTIFIED )
 		return( 1 );
 	
Index: unix.c
===================================================================
--- unix.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ unix.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -29,7 +29,9 @@
 #include "protocols/nogaim.h"
 #include "help.h"
+#include "ipc.h"
 #include <signal.h>
 #include <unistd.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 
 global_t global;	/* Against global namespace pollution */
@@ -37,7 +39,8 @@
 static void sighandler( int signal );
 
-int main( int argc, char *argv[] )
+int main( int argc, char *argv[], char **envp )
 {
 	int i = 0;
+	char *old_cwd = NULL;
 	struct sigaction sig, old;
 	
@@ -46,5 +49,5 @@
 	global.loop = g_main_new( FALSE );
 	
-	log_init( );
+	log_init();
 
 	nogaim_init();
@@ -70,9 +73,22 @@
 		log_message( LOGLVL_INFO, "Bitlbee %s starting in daemon mode.", BITLBEE_VERSION );
 	}
+	else if( global.conf->runmode == RUNMODE_FORKDAEMON )
+	{
+		/* In case the operator requests a restart, we need this. */
+		old_cwd = g_malloc( 256 );
+		if( getcwd( old_cwd, 255 ) == NULL )
+		{
+			log_message( LOGLVL_WARNING, "Could not save current directory: %s", strerror( errno ) );
+			g_free( old_cwd );
+			old_cwd = NULL;
+		}
+		
+		i = bitlbee_daemon_init();
+		log_message( LOGLVL_INFO, "Bitlbee %s starting in forking daemon mode.", BITLBEE_VERSION );
+	}
 	if( i != 0 )
 		return( i );
 
-	global.storage = storage_init( global.conf->primary_storage, 
-								   global.conf->migrate_storage );
+	global.storage = storage_init( global.conf->primary_storage, global.conf->migrate_storage );
 	if ( global.storage == NULL) {
 		log_message( LOGLVL_ERROR, "Unable to load storage backend '%s'", global.conf->primary_storage );
@@ -84,4 +100,5 @@
 	memset( &sig, 0, sizeof( sig ) );
 	sig.sa_handler = sighandler;
+	sigaction( SIGCHLD, &sig, &old );
 	sigaction( SIGPIPE, &sig, &old );
 	sig.sa_flags = SA_RESETHAND;
@@ -102,4 +119,33 @@
 	g_main_run( global.loop );
 	
+	if( global.restart )
+	{
+		char *fn = ipc_master_save_state();
+		char **args;
+		int n, i;
+		
+		chdir( old_cwd );
+		
+		n = 0;
+		args = g_new0( char *, argc + 3 );
+		args[n++] = argv[0];
+		if( fn )
+		{
+			args[n++] = "-R";
+			args[n++] = fn;
+		}
+		for( i = 1; argv[i] && i < argc; i ++ )
+		{
+			if( strcmp( argv[i], "-R" ) == 0 )
+				i += 2;
+			
+			args[n++] = argv[i];
+		}
+		
+		close( global.listen_socket );
+		
+		execve( args[0], args, envp );
+	}
+	
 	return( 0 );
 }
@@ -107,5 +153,5 @@
 static void sighandler( int signal )
 {
-	/* FIXME: In fact, calling log_message() here can be dangerous. But well, let's take the risk for now. */
+	/* FIXME: Calling log_message() here is not a very good idea! */
 	
 	if( signal == SIGTERM )
@@ -133,4 +179,17 @@
 		}
 	}
+	else if( signal == SIGCHLD )
+	{
+		pid_t pid;
+		int st;
+		
+		while( ( pid = waitpid( 0, &st, WNOHANG ) ) > 0 )
+		{
+			if( WIFSIGNALED( st ) )
+				log_message( LOGLVL_INFO, "Client %d terminated normally. (status = %d)", pid, WEXITSTATUS( st ) );
+			else if( WIFEXITED( st ) )
+				log_message( LOGLVL_INFO, "Client %d killed by signal %d.", pid, WTERMSIG( st ) );
+		}
+	}
 	else if( signal != SIGPIPE )
 	{
Index: url.c
===================================================================
--- url.c	(revision a323a22773714a19254db34156500a67e5916451)
+++ url.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -40,8 +40,8 @@
 	else
 	{
-		if( g_strncasecmp( set_url, "https", i - set_url ) == 0 )
+		if( g_strncasecmp( set_url, "http", i - set_url ) == 0 )
+			url->proto = PROTO_HTTP;
+		else if( g_strncasecmp( set_url, "https", i - set_url ) == 0 )
 			url->proto = PROTO_HTTPS;
-		else if( g_strncasecmp( set_url, "http", i - set_url ) == 0 )
-			url->proto = PROTO_HTTP;
 		else if( g_strncasecmp( set_url, "socks4", i - set_url ) == 0 )
 			url->proto = PROTO_SOCKS4;
Index: user.h
===================================================================
--- user.h	(revision a323a22773714a19254db34156500a67e5916451)
+++ user.h	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -45,5 +45,5 @@
     	int sendbuf_flags;
 	
-	int (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags );
+	void (*send_handler) ( irc_t *irc, struct __USER *u, char *msg, int flags );
 	
 	struct __USER *next;
Index: util.c
===================================================================
--- util.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
+++ util.c	(revision 5ebe625399d5116e222d6389434f645e906265ec)
@@ -0,0 +1,446 @@
+  /********************************************************************\
+  * BitlBee -- An IRC to other IM-networks gateway                     *
+  *                                                                    *
+  * Copyright 2002-2004 Wilmer van der Gaast and others                *
+  \********************************************************************/
+
+/*
+ * Various utility functions. Some are copied from Gaim to support the
+ * IM-modules, most are from BitlBee.
+ *
+ * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
+ *                          (and possibly other members of the Gaim team)
+ * Copyright 2002-2005 Wilmer van der Gaast <wilmer@gaast.net>
+ */
+
+/*
+  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 "nogaim.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include <time.h>
+
+void strip_linefeed(gchar *text)
+{
+	int i, j;
+	gchar *text2 = g_malloc(strlen(text) + 1);
+
+	for (i = 0, j = 0; text[i]; i++)
+		if (text[i] != '\r')
+			text2[j++] = text[i];
+	text2[j] = '\0';
+
+	strcpy(text, text2);
+	g_free(text2);
+}
+
+char *add_cr(char *text)
+{
+	char *ret = NULL;
+	int count = 0, j;
+	unsigned int i;
+
+	if (text[0] == '\n')
+		count++;
+	for (i = 1; i < strlen(text); i++)
+		if (text[i] == '\n' && text[i - 1] != '\r')
+			count++;
+
+	if (count == 0)
+		return g_strdup(text);
+
+	ret = g_malloc0(strlen(text) + count + 1);
+
+	i = 0; j = 0;
+	if (text[i] == '\n')
+		ret[j++] = '\r';
+	ret[j++] = text[i++];
+	for (; i < strlen(text); i++) {
+		if (text[i] == '\n' && text[i - 1] != '\r')
+			ret[j++] = '\r';
+		ret[j++] = text[i];
+	}
+
+	return ret;
+}
+
+static char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/";
+
+/* XXX Find bug */
+char *tobase64(const char *text)
+{
+	char *out = NULL;
+	const char *c;
+	unsigned int tmp = 0;
+	int len = 0, n = 0;
+
+	c = text;
+
+	while (*c) {
+		tmp = tmp << 8;
+		tmp += *c;
+		n++;
+
+		if (n == 3) {
+			out = g_realloc(out, len + 4);
+			out[len] = alphabet[(tmp >> 18) & 0x3f];
+			out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
+			out[len + 2] = alphabet[(tmp >> 6) & 0x3f];
+			out[len + 3] = alphabet[tmp & 0x3f];
+			len += 4;
+			tmp = 0;
+			n = 0;
+		}
+		c++;
+	}
+	switch (n) {
+
+	case 2:
+		tmp <<= 8;
+		out = g_realloc(out, len + 5);
+		out[len] = alphabet[(tmp >> 18) & 0x3f];
+		out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
+		out[len + 2] = alphabet[(tmp >> 6) & 0x3f];
+		out[len + 3] = '=';
+		out[len + 4] = 0;
+		break;
+	case 1:
+		tmp <<= 16;
+		out = g_realloc(out, len + 5);
+		out[len] = alphabet[(tmp >> 18) & 0x3f];
+		out[len + 1] = alphabet[(tmp >> 12) & 0x3f];
+		out[len + 2] = '=';
+		out[len + 3] = '=';
+		out[len + 4] = 0;
+		break;
+	case 0:
+		out = g_realloc(out, len + 1);
+		out[len] = 0;
+		break;
+	}
+	return out;
+}
+
+char *normalize(const char *s)
+{
+	static char buf[BUF_LEN];
+	char *t, *u;
+	int x = 0;
+
+	g_return_val_if_fail((s != NULL), NULL);
+
+	u = t = g_strdup(s);
+
+	strcpy(t, s);
+	g_strdown(t);
+
+	while (*t && (x < BUF_LEN - 1)) {
+		if (*t != ' ') {
+			buf[x] = *t;
+			x++;
+		}
+		t++;
+	}
+	buf[x] = '\0';
+	g_free(u);
+	return buf;
+}
+
+time_t get_time(int year, int month, int day, int hour, int min, int sec)
+{
+	struct tm tm;
+
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec >= 0 ? sec : time(NULL) % 60;
+	return mktime(&tm);
+}
+
+typedef struct htmlentity
+{
+	char code[8];
+	char is[4];
+} htmlentity_t;
+
+/* FIXME: This is ISO8859-1(5) centric, so might cause problems with other charsets. */
+
+static const htmlentity_t ent[] =
+{
+	{ "lt",     "<" },
+	{ "gt",     ">" },
+	{ "amp",    "&" },
+	{ "quot",   "\"" },
+	{ "aacute", "á" },
+	{ "eacute", "é" },
+	{ "iacute", "é" },
+	{ "oacute", "ó" },
+	{ "uacute", "ú" },
+	{ "agrave", "à" },
+	{ "egrave", "è" },
+	{ "igrave", "ì" },
+	{ "ograve", "ò" },
+	{ "ugrave", "ù" },
+	{ "acirc",  "â" },
+	{ "ecirc",  "ê" },
+	{ "icirc",  "î" },
+	{ "ocirc",  "ô" },
+	{ "ucirc",  "û" },
+	{ "auml",   "ä" },
+	{ "euml",   "ë" },
+	{ "iuml",   "ï" },
+	{ "ouml",   "ö" },
+	{ "uuml",   "ü" },
+	{ "nbsp",   " " },
+	{ "",        ""  }
+};
+
+void strip_html( char *in )
+{
+	char *start = in;
+	char *out = g_malloc( strlen( in ) + 1 );
+	char *s = out, *cs;
+	int i, matched;
+	
+	memset( out, 0, strlen( in ) + 1 );
+	
+	while( *in )
+	{
+		if( *in == '<' && ( isalpha( *(in+1) ) || *(in+1) == '/' ) )
+		{
+			/* If in points at a < and in+1 points at a letter or a slash, this is probably
+			   a HTML-tag. Try to find a closing > and continue there. If the > can't be
+			   found, assume that it wasn't a HTML-tag after all. */
+			
+			cs = in;
+			
+			while( *in && *in != '>' )
+				in ++;
+			
+			if( *in )
+			{
+				if( g_strncasecmp( cs+1, "br", 2) == 0 )
+					*(s++) = '\n';
+				in ++;
+			}
+			else
+			{
+				in = cs;
+				*(s++) = *(in++);
+			}
+		}
+		else if( *in == '&' )
+		{
+			cs = ++in;
+			while( *in && isalpha( *in ) )
+				in ++;
+			
+			if( *in == ';' ) in ++;
+			matched = 0;
+			
+			for( i = 0; *ent[i].code; i ++ )
+				if( g_strncasecmp( ent[i].code, cs, strlen( ent[i].code ) ) == 0 )
+				{
+					int j;
+					
+					for( j = 0; ent[i].is[j]; j ++ )
+						*(s++) = ent[i].is[j];
+					
+					matched = 1;
+					break;
+				}
+
+			/* None of the entities were matched, so return the string */
+			if( !matched )
+			{
+				in = cs - 1;
+				*(s++) = *(in++);
+			}
+		}
+		else
+		{
+			*(s++) = *(in++);
+		}
+	}
+	
+	strcpy( start, out );
+	g_free( out );
+}
+
+char *escape_html( const char *html )
+{
+	const char *c = html;
+	GString *ret;
+	char *str;
+	
+	if( html == NULL )
+		return( NULL );
+	
+	ret = g_string_new( "" );
+	
+	while( *c )
+	{
+		switch( *c )
+		{
+			case '&':
+				ret = g_string_append( ret, "&amp;" );
+				break;
+			case '<':
+				ret = g_string_append( ret, "&lt;" );
+				break;
+			case '>':
+				ret = g_string_append( ret, "&gt;" );
+				break;
+			case '"':
+				ret = g_string_append( ret, "&quot;" );
+				break;
+			default:
+				ret = g_string_append_c( ret, *c );
+		}
+		c ++;
+	}
+	
+	str = ret->str;
+	g_string_free( ret, FALSE );
+	return( str );
+}
+
+void info_string_append(GString *str, char *newline, char *name, char *value)
+{
+	if( value && value[0] )
+		g_string_sprintfa( str, "%s%s: %s", newline, name, value );
+}
+
+/* Decode%20a%20file%20name						*/
+void http_decode( char *s )
+{
+	char *t;
+	int i, j, k;
+	
+	t = g_new( char, strlen( s ) + 1 );
+	
+	for( i = j = 0; s[i]; i ++, j ++ )
+	{
+		if( s[i] == '%' )
+		{
+			if( sscanf( s + i + 1, "%2x", &k ) )
+			{
+				t[j] = k;
+				i += 2;
+			}
+			else
+			{
+				*t = 0;
+				break;
+			}
+		}
+		else
+		{
+			t[j] = s[i];
+		}
+	}
+	t[j] = 0;
+	
+	strcpy( s, t );
+	g_free( t );
+}
+
+/* Warning: This one explodes the string. Worst-cases can make the string 3x its original size! */
+/* This fuction is safe, but make sure you call it safely as well! */
+void http_encode( char *s )
+{
+	char *t;
+	int i, j;
+	
+	t = g_strdup( s );
+	
+	for( i = j = 0; t[i]; i ++, j ++ )
+	{
+		/* if( t[i] <= ' ' || ((unsigned char *)t)[i] >= 128 || t[i] == '%' ) */
+		if( !isalnum( t[i] ) )
+		{
+			sprintf( s + j, "%%%02X", ((unsigned char*)t)[i] );
+			j += 2;
+		}
+		else
+		{
+			s[j] = t[i];
+		}
+	}
+	s[j] = 0;
+	
+	g_free( t );
+}
+
+/* Strip newlines from a string. Modifies the string passed to it. */ 
+char *strip_newlines( char *source )
+{
+	int i;	
+
+	for( i = 0; source[i] != '\0'; i ++ )
+		if( source[i] == '\n' || source[i] == '\r' )
+			source[i] = ' ';
+	
+	return source;
+}
+
+#ifdef IPV6
+/* Wrap an IPv4 address into IPv6 space. Not thread-safe... */
+char *ipv6_wrap( char *src )
+{
+	static char dst[64];
+	int i;
+	
+	for( i = 0; src[i]; i ++ )
+		if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' )
+			break;
+	
+	/* Hmm, it's not even an IP... */
+	if( src[i] )
+		return src;
+	
+	g_snprintf( dst, sizeof( dst ), "::ffff:%s", src );
+	
+	return dst;
+}
+
+/* Unwrap an IPv4 address into IPv6 space. Thread-safe, because it's very simple. :-) */
+char *ipv6_unwrap( char *src )
+{
+	int i;
+	
+	if( g_strncasecmp( src, "::ffff:", 7 ) != 0 )
+		return src;
+	
+	for( i = 7; src[i]; i ++ )
+		if( ( src[i] < '0' || src[i] > '9' ) && src[i] != '.' )
+			break;
+	
+	/* Hmm, it's not even an IP... */
+	if( src[i] )
+		return src;
+	
+	return ( src + 7 );
+}
+#endif
