Index: Makefile
===================================================================
--- Makefile	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ Makefile	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -11,5 +11,5 @@
 # Program variables
 #objects = bitlbee.o chat.o dcc.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS)
-objects = bitlbee.o help.o ipc.o irc.o irc_channel.o irc_commands.o irc_send.o irc_user.o nick.o set.o
+objects = bitlbee.o help.o ipc.o irc.o irc_channel.o irc_commands.o irc_send.o irc_user.o nick.o root_commands.o set.o
 headers = account.h bitlbee.h commands.h conf.h config.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/ftutil.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/ft.h protocols/nogaim.h
 subdirs = lib protocols
Index: irc.c
===================================================================
--- irc.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ irc.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -114,8 +114,10 @@
 	iu->host = g_strdup( myhost );
 	iu->fullname = g_strdup( ROOT_FN );
+	iu->f = &irc_user_root_funcs;
 	
 	iu = irc_user_new( irc, NS_NICK );
 	iu->host = g_strdup( myhost );
 	iu->fullname = g_strdup( ROOT_FN );
+	iu->f = &irc_user_root_funcs;
 	
 	irc->user = g_new0( irc_user_t, 1 );
@@ -594,4 +596,5 @@
 			irc->user->host = iu->host;
 			irc->user->fullname = iu->fullname;
+			irc->user->f = &irc_user_self_funcs;
 			g_free( iu->nick );
 			g_free( iu );
Index: irc.h
===================================================================
--- irc.h	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ irc.h	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -107,5 +107,15 @@
 	
 	//struct user *b;
+	
+	const struct irc_user_funcs *f;
 } irc_user_t;
+
+struct irc_user_funcs
+{
+	gboolean (*privmsg)( irc_user_t *iu, const char *msg );
+};
+
+extern const struct irc_user_funcs irc_user_root_funcs;
+extern const struct irc_user_funcs irc_user_self_funcs;
 
 typedef enum
@@ -117,13 +127,22 @@
 {
 	irc_t *irc;
+	char *name;
+	char mode[8];
 	int flags;
-	char *name;
+	
 	char *topic;
 	char *topic_who;
 	time_t topic_time;
-	char mode[8];
+	
 	GSList *users;
 	struct set *set;
+	
+	const struct irc_channel_funcs *f;
 } irc_channel_t;
+
+struct irc_channel_funcs
+{
+	gboolean (*privmsg)( irc_channel_t *iu, const char *msg );
+};
 
 #include "user.h"
@@ -175,5 +194,5 @@
 irc_user_t *irc_user_new( irc_t *irc, const char *nick );
 int irc_user_free( irc_t *irc, const char *nick );
-irc_user_t *irc_user_find( irc_t *irc, const char *nick );
+irc_user_t *irc_user_by_name( irc_t *irc, const char *nick );
 int irc_user_rename( irc_t *irc, const char *old, const char *new );
 gint irc_user_cmp( gconstpointer a_, gconstpointer b_ );
Index: irc_channel.c
===================================================================
--- irc_channel.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ irc_channel.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -26,4 +26,6 @@
 #include "bitlbee.h"
 
+static const struct irc_channel_funcs control_channel_funcs;
+
 irc_channel_t *irc_channel_new( irc_t *irc, const char *name )
 {
@@ -34,4 +36,5 @@
 	
 	ic = g_new0( irc_channel_t, 1 );
+	ic->f = &control_channel_funcs;
 	ic->irc = irc;
 	ic->name = g_strdup( name );
@@ -132,2 +135,14 @@
 	return strchr( CTYPES, name[0] ) != NULL && nick_ok( name + 1 );
 }
+
+/* Channel-type dependent functions, for control channels: */
+static gboolean control_channel_privmsg( irc_channel_t *ic, const char *msg )
+{
+	root_command_string( ic->irc, msg );
+	
+	return TRUE;
+}
+
+static const struct irc_channel_funcs control_channel_funcs = {
+	control_channel_privmsg,
+};
Index: irc_commands.c
===================================================================
--- irc_commands.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ irc_commands.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -77,5 +77,5 @@
 		irc_send_num( irc, 438, ":The hand of the deity is upon thee, thy nick may not change" );
 	}
-	else if( irc_user_find( irc, cmd[1] ) )
+	else if( irc_user_by_name( irc, cmd[1] ) )
 	{
 		irc_send_num( irc, 433, ":This nick is already in use" );
@@ -160,5 +160,5 @@
 {
 	char *nick = cmd[1];
-	irc_user_t *iu = irc_user_find( irc, nick );
+	irc_user_t *iu = irc_user_by_name( irc, nick );
 	
 	if( iu )
@@ -220,6 +220,4 @@
 	char *channel = cmd[1];
 	irc_channel_t *ic;
-	struct groupchat *c;
-	GList *l;
 	
 	if( !channel || *channel == '0' || *channel == '*' || !*channel )
@@ -231,48 +229,33 @@
 }
 
+static void irc_cmd_privmsg( irc_t *irc, char **cmd )
+{
+	irc_channel_t *ic;
+	irc_user_t *iu;
+	
+	if( !cmd[2] ) 
+	{
+		irc_send_num( irc, 412, ":No text to send" );
+	}
+	else if( irc_channel_name_ok( cmd[1] ) &&
+	         ( ic = irc_channel_by_name( irc, cmd[1] ) ) )
+	{
+		if( ic->f->privmsg )
+			ic->f->privmsg( ic, cmd[2] );
+	}
+	else if( ( iu = irc_user_by_name( irc, cmd[1] ) ) )
+	{
+		if( iu->f->privmsg )
+			iu->f->privmsg( iu, cmd[2] );
+	}
+	else
+	{
+		irc_send_num( irc, 401, "%s :No such nick/channel", cmd[1] );
+	}
+
+
 #if 0
-//#if 0
-static void irc_cmd_oper( irc_t *irc, char **cmd )
-{
-	if( global.conf->oper_pass &&
-	    ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
-	        md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
-	        strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
-	{
-		irc_umode_set( irc, "+o", 1 );
-		irc_send_num( irc, 381, ":Password accepted" );
-	}
-	else
-	{
-		irc_send_num( irc, 432, ":Incorrect password" );
-	}
-}
-
-static void irc_cmd_invite( irc_t *irc, char **cmd )
-{
-	char *nick = cmd[1], *channel = cmd[2];
-	struct groupchat *c = irc_chat_by_channel( irc, channel );
-	user_t *u = user_find( irc, nick );
-	
-	if( u && c && ( u->ic == c->ic ) )
-		if( c->ic && c->ic->acc->prpl->chat_invite )
-		{
-			c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
-			irc_send_num( irc, 341, "%s %s", nick, channel );
-			return;
-		}
-	
-	irc_send_num( 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_send_num( 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 
@@ -315,4 +298,42 @@
 		irc_send( irc, cmd[1], cmd[2], ( g_strcasecmp( cmd[0], "NOTICE" ) == 0 ) ? OPT_AWAY : 0 );
 	}
+#endif
+}
+
+
+
+#if 0
+//#if 0
+static void irc_cmd_oper( irc_t *irc, char **cmd )
+{
+	if( global.conf->oper_pass &&
+	    ( strncmp( global.conf->oper_pass, "md5:", 4 ) == 0 ?
+	        md5_verify_password( cmd[2], global.conf->oper_pass + 4 ) == 0 :
+	        strcmp( cmd[2], global.conf->oper_pass ) == 0 ) )
+	{
+		irc_umode_set( irc, "+o", 1 );
+		irc_send_num( irc, 381, ":Password accepted" );
+	}
+	else
+	{
+		irc_send_num( irc, 432, ":Incorrect password" );
+	}
+}
+
+static void irc_cmd_invite( irc_t *irc, char **cmd )
+{
+	char *nick = cmd[1], *channel = cmd[2];
+	struct groupchat *c = irc_chat_by_channel( irc, channel );
+	user_t *u = user_find( irc, nick );
+	
+	if( u && c && ( u->ic == c->ic ) )
+		if( c->ic && c->ic->acc->prpl->chat_invite )
+		{
+			c->ic->acc->prpl->chat_invite( c, u->handle, NULL );
+			irc_send_num( irc, 341, "%s %s", nick, channel );
+			return;
+		}
+	
+	irc_send_num( irc, 482, "%s :Invite impossible; User/Channel non-existent or incompatible", channel );
 }
 
@@ -555,8 +576,8 @@
 	{ "mode",        1, irc_cmd_mode,        IRC_CMD_LOGGED_IN },
 	{ "who",         0, irc_cmd_who,         IRC_CMD_LOGGED_IN },
+	{ "privmsg",     1, irc_cmd_privmsg,     IRC_CMD_LOGGED_IN },
 #if 0
 	{ "oper",        2, irc_cmd_oper,        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 },
 	{ "userhost",    1, irc_cmd_userhost,    IRC_CMD_LOGGED_IN },
Index: irc_send.c
===================================================================
--- irc_send.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ irc_send.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -147,8 +147,6 @@
 {
 	GSList *l;
-	irc_user_t *iu;
 	char namelist[385] = "";
-	struct groupchat *c = NULL;
-	char *ops = set_getstr( &ic->irc->b->set, "ops" );
+	//char *ops = set_getstr( &ic->irc->b->set, "ops" );
 	
 	/* RFCs say there is no error reply allowed on NAMES, so when the
@@ -240,2 +238,8 @@
 	irc_send_num( irc, 315, "%s :End of /WHO list", channel );
 }
+
+void irc_send_msg( irc_user_t *iu, const char *type, const char *dst, const char *msg )
+{
+	irc_write( iu->irc, ":%s!%s@%s %s %s :%s",
+	           iu->nick, iu->user, iu->host, type, dst, msg );
+}
Index: irc_user.c
===================================================================
--- irc_user.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ irc_user.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -51,5 +51,5 @@
 	irc_user_t *iu;
 	
-	if( !( iu = irc_user_find( irc, nick ) ) )
+	if( !( iu = irc_user_by_name( irc, nick ) ) )
 		return 0;
 	
@@ -68,5 +68,5 @@
 }
 
-irc_user_t *irc_user_find( irc_t *irc, const char *nick )
+irc_user_t *irc_user_by_name( irc_t *irc, const char *nick )
 {
 	char key[strlen(nick)+1];
@@ -81,9 +81,9 @@
 int irc_user_rename( irc_t *irc, const char *old, const char *new )
 {
-	irc_user_t *iu = irc_user_find( irc, old );
+	irc_user_t *iu = irc_user_by_name( irc, old );
 	char key[strlen(new)+1];
 	
 	strcpy( key, new );
-	if( iu == NULL || !nick_lc( key ) || irc_user_find( irc, new ) )
+	if( iu == NULL || !nick_lc( key ) || irc_user_by_name( irc, new ) )
 		return 0;
 	
@@ -113,2 +113,26 @@
 	return strcmp( a->key, b->key );
 }
+
+/* User-type dependent functions, for root/NickServ: */
+static gboolean root_privmsg( irc_user_t *iu, const char *msg )
+{
+	root_command_string( iu->irc, msg );
+	
+	return TRUE;
+}
+
+const struct irc_user_funcs irc_user_root_funcs = {
+	root_privmsg,
+};
+
+/* Echo to yourself: */
+static gboolean self_privmsg( irc_user_t *iu, const char *msg )
+{
+	irc_send_msg( iu, "PRIVMSG", iu->nick, msg );
+	
+	return TRUE;
+}
+
+const struct irc_user_funcs irc_user_self_funcs = {
+	self_privmsg,
+};
Index: nick.c
===================================================================
--- nick.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ nick.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -96,5 +96,5 @@
 	/* Now, find out if the nick is already in use at the moment, and make
 	   subtle changes to make it unique. */
-	while( !nick_ok( nick ) || irc_user_find( acc->irc, nick ) )
+	while( !nick_ok( nick ) || irc_user_by_name( acc->irc, nick ) )
 	{
 		if( strlen( nick ) < ( MAX_NICK_LENGTH - 1 ) )
Index: root_commands.c
===================================================================
--- root_commands.c	(revision 2f53ada73d7d43b538c157563ab5eb39b7592137)
+++ root_commands.c	(revision 280c56a7b24dc08b35a1ecd98c8f4b61435d1100)
@@ -32,5 +32,5 @@
 #include <string.h>
 
-void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
+void root_command_string( irc_t *irc, char *command )
 {
 	char *cmd[IRC_MAX_ARGS];
@@ -136,4 +136,5 @@
 }
 
+#if 0
 static void cmd_account( irc_t *irc, char **cmd );
 
@@ -1217,7 +1218,9 @@
 	}
 }
+#endif
 
 const command_t commands[] = {
 	{ "help",           0, cmd_help,           0 }, 
+#if 0
 	{ "identify",       1, cmd_identify,       0 },
 	{ "register",       1, cmd_register,       0 },
@@ -1240,4 +1243,5 @@
 	{ "chat",           1, cmd_chat,           0 },
 	{ "transfer",       0, cmd_transfer,       0 },
+#endif
 	{ NULL }
 };
