/*
 * numbers.c:handles all those strange numeric response dished out by that
 * wacky, nutty program we call ircd 
 *
 *
 * written by michael sandrof
 *
 * copyright(c) 1990 
 *
 * see the copyright file, or do a help ircii copyright 
 */


#include "irc.h"
#include "dcc.h"
#include "input.h"
#include "commands.h"
#include "ircaux.h"
#include "vars.h"
#include "lastlog.h"
#include "list.h"
#include "hook.h"
#include "server.h"
#include "whois.h"
#include "numbers.h"
#include "window.h"
#include "screen.h"
#include "output.h"
#include "names.h"
#include "whois.h"
#include "funny.h"
#include "parse.h"
#include "misc.h"
#include "status.h"
#include "struct.h"
#include "timer.h"
#include "tcl_bx.h"

static	void	channel_topic		_((char *, char **, int));
static	void	not_valid_channel	_((char *, char **));
static	void	cannot_join_channel	_((char *, char **));

static	int	number_of_bans = 0;

#ifdef WANT_DLL
/* this is kinda like a hook */
NumericFunction *numeric_dll = NULL;
#endif

extern void	parse_364		_((char *, char *, char *));
extern void	parse_365		_((char *, char *, char *));
extern void	add_to_irc_map		_((char *, char *));
extern void	show_server_map		_((void));
extern int	stats_k_grep		_((char **));
extern void	who_handlekill		_((char *, char *, char *));
extern void	handle_tracekill	_((int, char *, char *, char *));
extern int	no_hook_notify;
extern int	who_on_join;
extern int	doing_who;
extern AJoinList *ajoin_list;
extern	void	remove_from_server_list _((int));

char	*thing_ansi = NULL;

#ifdef HAVE_GETTIMEOFDAY
extern struct timeval in_sping;
#else
extern time_t in_sping;
#endif


/*
 * numeric_banner: This returns in a static string of either "xxx" where
 * xxx is the current numeric, or "***" if SHOW_NUMBERS is OFF 
 */
char	*numeric_banner(void)
{
	static	char	thing[4];
	if (!get_int_var(SHOW_NUMERICS_VAR))
		return (thing_ansi?thing_ansi:empty_string);
	sprintf(thing, "%3.3u", -current_numeric);
	return (thing);
}

int check_sync(int comm, char *channel, char *nick, char *whom, char *bantime, ChannelList *chan)
{
ChannelList *tmp = NULL;
BanList *new;

	context;	

	if (!chan)
		if (!(tmp = lookup_channel(channel, from_server, CHAN_NOUNLINK)))
			return -1; /* channel lookup problem */
	if (!in_join_list(channel, from_server))
		return -1;

	if (tmp == NULL)
		tmp = chan;	

	switch (comm)
	{
		case 367: /* bans on channel */
		{
			if (tmp)
			{
				new = (BanList *)new_malloc(sizeof(BanList));
				malloc_strcpy(&new->ban, nick);
				if (bantime)
					new->time = strtoul(bantime, NULL, 10);
				else
					new->time = time(NULL);
				if (whom)
					new->setby = m_strdup(whom);
				add_to_list((List **)&tmp->bans,(List *)new); 
			}
		}
		default:
			break;
	}	
	return 0;
}

static int handle_stats(int comm, char *from, char **ArgList)
{
char *format_str = NULL;
char *format2_str = NULL;
char *args;
	args = PasteArgs(ArgList, 0);
	switch (comm)
	{
/*
 ^on ^raw_irc "% 211 *" {suecho \(L:line\) $[20]sklnick($3) : $4|$5|$6|$7|$8|$strip(: 9)|$strip(: $10);suecho $[8]11 $[30]sklhost($3)}
 ^on ^raw_irc "% 212 *" {suecho $[9]3: $4 $5}
 ^on ^raw_irc "% 213 *" {suecho \($3:line\) \($[20]4\)\($[20]6\) \($[5]7\)\($strip(: $[4]8)\)}
 ^on ^raw_irc "% 214 *" {suecho \($3:line\) \($[20]4\)\($[20]6\) \($[5]7\)\($strip(: $[4]8)\)}
 ^on ^raw_irc "% 215 *" {suecho \($3:line\) \($[20]4\)\($[20]6\) \($[5]7\)\($strip(: $[4]8)\)}
 ^on ^raw_irc "% 216 *" {suecho \($3:line\) \($[20]4\) \($[15]6\)}
 ^on ^raw_irc "% 218 *" {suecho \($3:line\) \($[5]4\) \($[5]5\) \($[5]6\) \($[5]7\) \($strip(: $[8]8)\)}
 ^on ^raw_irc "% 242 *" {suecho $0 has been up for $5- }
 ^on ^raw_irc "% 243 *" {suecho \($3:line\) \($[20]4\) \($[9]6\)}
 ^on ^raw_irc "% 244 *" {suecho \($3:line\) \($[25]4\) \($[25]6\)}
*/
		case 211:
			format_str = "L:line $[20]left($rindex([ $1) $1)  :$[-5]2 $[-5]3 $[-6]4 $[-5]5 $[-6]6 $[-8]strip(: $7) $strip(: $8)";
			format2_str = "$[8]9 $[30]mid(${rindex([ $1)+1} ${rindex(] $1) - $rindex([ $1) + 1} $1)";
			break;
		case 212:
			format_str = "$[10]1 $[-10]2 $[-10]3";
			break;
		case 213:
		case 214:
		case 215:
 			format_str = "$1:line $[25]2 $[25]4 $[-5]5 $[-5]6";
			break;
		case 216:
			format_str = "$1:line $[25]2 $[20]4  $3";
			break;
		case 218:
			format_str = "$1:line $[-5]2 $[-6]3 $[-6]4 $[-6]5 $[-10]6";
			break;
		case 241:
			format_str = "$1:line $2-";
			break;
		case 242:
			format_str = "%G$0%n has been up for %W$3-";
			break;
		case 243:
			format_str = "$1:line $[25]2 $[9]4";
			break;
		case 244:
			format_str = "$1:line $[25]2 $[25]4";
		default:
			break;
	}
	if (format_str && args)
		put_it("%s", convert_output_format(format_str, "%s %s", from, args)); 
	if (format2_str && args)
		put_it("%s", convert_output_format(format2_str, "%s %s", from, args)); 
	return 0;
}

static int trace_oper(char *from, char **ArgList)
{
char *rest = PasteArgs(ArgList, 0);
	put_it("%s", convert_output_format(fget_string_var(FORMAT_TRACE_OPER_FSET), "%s %s", from, rest));
	return 0;
}

static int trace_server(char *from, char **ArgList)
{
char *rest = PasteArgs(ArgList, 0);
	put_it("%s", convert_output_format(fget_string_var(FORMAT_TRACE_SERVER_FSET), "%s %s", from, rest));
	return 0;
}

static int trace_user(char *from, char **ArgList)
{
char *rest = PasteArgs(ArgList, 0);
	put_it("%s", convert_output_format(fget_string_var(FORMAT_TRACE_USER_FSET), "%s %s", from, rest));
	return 0;
}

static int check_server_sync(char *from, char **ArgList)
{
static char *desync = NULL;

	context;
	if (!desync || (desync && !match(desync, from)))
	{
		if (!match(from, get_server_name(from_server)))
		{
			malloc_strcpy(&desync, from);
			if (do_hook(DESYNC_MESSAGE_LIST, "%s %s", from, ArgList[0]))
				put_it("%s", convert_output_format(fget_string_var(FORMAT_DESYNC_FSET), "%s %s %s", update_clock(GET_TIME), ArgList[0], from));
			return 1;
		}	 
	} 
	return 0;
}

/*
 * display_msg: handles the displaying of messages from the variety of
 * possible formats that the irc server spits out.  you'd think someone would
 * simplify this 
 */
void display_msg(char *from, char **ArgList)
{
	char	*ptr;
	char	*rest;
	int	drem;
	
	context;
	rest = PasteArgs(ArgList, 0);
	if (from && (my_strnicmp(get_server_itsname(from_server), from,
			strlen(get_server_itsname(from_server))) == 0))
		from = NULL;
	if ((ptr = strchr(rest, ':')))
		*ptr++ = 0;
        drem = (int)(from) /*&& (!get_int_var(SUPPRESS_FROM_REMOTE_SERVER))*/;
     
        put_it("%s %s%s%s%s%s%s",
                numeric_banner(),
                strlen(rest)        ? rest     : empty_string,
/*                strlen(rest) && ptr ? ":"      : empty_string,*/
                strlen(rest)        ? space    : empty_string,
                ptr                 ? ptr      : empty_string,
                drem                ? "(from " : empty_string,
                drem                ? from     : empty_string,
                drem                ? ")"      : empty_string
              );
}

static	void channel_topic(char *from, char **ArgList, int what)
{
	char	*topic, *channel;
	ChannelList *chan;
	
	context;
	if (ArgList[1] && is_channel(ArgList[0]))
	{
		channel = ArgList[0];
		topic = ArgList[1];
		message_from(channel, LOG_CRAP);
		if (what == 333 && ArgList[2])
			put_it("%s", convert_output_format(fget_string_var(FORMAT_TOPIC_SETBY_FSET), "%s %s %s %l", update_clock(GET_TIME), channel, topic, strtoul(ArgList[2], NULL, 10)));
		else if (what != 333)
		{
			if ((chan = lookup_channel(channel, from_server, 0)))
				malloc_strcpy(&chan->topic, topic);
			put_it("%s", convert_output_format(fget_string_var(FORMAT_TOPIC_FSET), "%s %s %s", update_clock(GET_TIME), channel, topic));

		}		
	}
	else
	{
		PasteArgs(ArgList, 0);
		message_from(NULL, LOG_CURRENT);
		put_it("%s", convert_output_format(fget_string_var(FORMAT_TOPIC_FSET), "%s %s", update_clock(GET_TIME), ArgList[0]));
	}
}

static	void not_valid_channel(char *from, char **ArgList)
{
	char	*channel;
	char	*s;

	context;
	if (!(channel = ArgList[0]) || !ArgList[1])
		return;
	PasteArgs(ArgList, 1);
	s = get_server_name(from_server);
	if (0 == my_strnicmp(s, from, strlen(s)))
	{
		remove_channel(channel, from_server);
		put_it("%s", convert_output_format(fget_string_var(FORMAT_SERVER_MSG2_FSET), "%s %s %s", update_clock(GET_TIME), channel, ArgList[1]));
	}
}

/* from ircd .../include/numeric.h */
/*
#define ERR_CHANNELISFULL    471
#define ERR_INVITEONLYCHAN   473
#define ERR_BANNEDFROMCHAN   474
#define ERR_BADCHANNELKEY    475
#define ERR_BADCHANMASK      476
*/
static	void cannot_join_channel(char *from, char **ArgList)
{
	char	buffer[BIG_BUFFER_SIZE + 1];
	char	*f = NULL;
	char	*chan;		
	context;

	if (ArgList[0])
		chan = ArgList[0];
	else
		chan = get_chan_from_join_list(from_server);

	remove_from_join_list(chan, from_server);
	if (!is_on_channel(chan, from_server, get_server_nickname(from_server)))
		remove_channel(chan, from_server);
	else
		return;


	PasteArgs(ArgList, 0);
	strcpy(buffer, ArgList[0]);
	switch(-current_numeric)
	{
	case 437: 
		strcat(buffer, " (Channel is temporarily unavailable)");
		break;
	case 471:
		strcat(buffer, " (Channel is full)");
		f = fget_string_var(FORMAT_471_FSET);
		break;
	case 473:
		strcat(buffer, " (You must be invited)");
		f = fget_string_var(FORMAT_473_FSET);
		break;
	case 474:
		strcat(buffer, " (You are banned)");
		f = fget_string_var(FORMAT_474_FSET);
		break;
	case 475:
		strcat(buffer, " (Bad channel key)");
		f = fget_string_var(FORMAT_475_FSET);
		break;
	case 476:
		strcat(buffer, " (Bad channel mask)");
		f = fget_string_var(FORMAT_476_FSET);
		break;
	default:
		return;
	}
	if (f)
		put_it("%s", convert_output_format(f, "%s %s", update_clock(GET_TIME), ArgList[0]));
	else
		put_it("%s %s", numeric_banner(), buffer);
}

int handle_server_ping(int comm, char *from, char **ArgList)
{
#ifdef HAVE_GETTIMEOFDAY
struct timeval diff = {0};
#else
time_t diff = 0;
#endif
char buf[80];
	
	get_time(&diff);
	*buf = 0;
	
#ifdef HAVE_GETTIMEOFDAY
	if (!in_sping.tv_sec)
		return 0;
	if (comm == 351)
	{
		sprintf(buf, "%2.4f second%s", time_diff(in_sping, diff), (int)time_diff(in_sping, diff)?"s":empty_string);
#else
	if (!in_sping)
		return 0;
	if (comm == 351)
	{
		sprintf(buf, "%d second%s", diff - in_sping, diff-in_sping?"s":empty_string);
#endif
		
		put_it("%s", convert_output_format("$G Server PONG from %W$0%n $1-", "%s %s", from, buf));
#ifdef HAVE_GETTIMEOFDAY
		memset(&in_sping, 0, sizeof(struct timeval));
#else
		in_sping = 0;
#endif
	}
	else
		put_it("%s", convert_output_format("No such server to ping", NULL, NULL));
	return 1;
}

int handle_server_stats(char *from, char **ArgList, int comm)
{
static	int 	norm = 0, 
		invisible = 0, 
		servers = 0, 
		ircops = 0, 
		unknown = 0, 
		chans = 0, 
		local_users = 0,
		total_users;
char tmp[80];
int	ret = 1;
char *line = alloca(strlen(ArgList[0])+1);
	strcpy(line, ArgList[0]);
	switch(comm)
	{
		case 251: /* number of users */
			BreakArgs(line, NULL, ArgList, 1);
			if (ArgList[2] && ArgList[5] && ArgList[8])
			{
				servers = ircops = unknown = chans = 0;
				norm = my_atol(ArgList[2]);
				invisible = my_atol(ArgList[5]);
				servers = my_atol(ArgList[8]);
			}
			break;
		case 252: /* number of ircops */
			if (ArgList[0])
			{
				ircops = my_atol(ArgList[0]);
			}
			break;
		case 253: /* number of unknown */
			if (ArgList[0])
			{
				unknown = my_atol(ArgList[0]);
			}
			break;
			
		case 254: /* number of channels */
			if (ArgList[0])
			{
				chans = my_atol(ArgList[0]);
			}
			break;
		case 255: /* number of local print it out */
			BreakArgs(line, NULL, ArgList, 1);
			if (ArgList[2])
				local_users = my_atol(ArgList[2]);
			total_users = norm + invisible;
			if (total_users)
			{
				sprintf(tmp, "%3.0f", (float)(((float)local_users / (float)total_users) * 100));
				put_it("%s", convert_output_format("$G %K[%nlocal users on irc%K(%n\002$0\002%K)]%n $1%%", "%d %s", local_users, tmp));
				sprintf(tmp, "%3.0f", (float)(((float)norm / (float)total_users) * 100));
				put_it("%s", convert_output_format("$G %K[%nglobal users on irc%K(%n\002$0\002%K)]%n $1%%", "%d %s", norm, tmp));
				sprintf(tmp, "%3.0f", (float)(((float)invisible / (float)total_users) * 100));
				put_it("%s", convert_output_format("$G %K[%ninvisible users on irc%K(%n\002$0\002%K)]%n $1%%", "%d %s", invisible, tmp));
				sprintf(tmp, "%3.0f", (float)(((float)ircops / (float)total_users) * 100));
				put_it("%s", convert_output_format("$G %K[%nircops on irc%K(%n\002$0\002%K)]%n $1%%", "%d %s", ircops, tmp));
			}
			put_it("%s", convert_output_format("$G %K[%ntotal users on irc%K(%n\002$0\002%K)]%n", "%d", total_users));
			put_it("%s", convert_output_format("$G %K[%nunknown connections%K(%n\002$0\002%K)]%n", "%d", unknown));

			put_it("%s", convert_output_format("$G %K[%ntotal servers on irc%K(%n\002$0\002%K)]%n %K(%navg. $1 users per server%K)", "%d %d", servers, (servers) ? (int)(total_users/servers) : 0));

			put_it("%s", convert_output_format("$G %K[%ntotal channels created%K(%n\002$0\002%K)]%n %K(%navg. $1 users per channel%K)", "%d %d", chans, (chans) ? (int)(total_users/chans) : 0));
			break;
		case 250:
		{
			char *p;
			BreakArgs(line, NULL, ArgList, 1);
			if (ArgList[3] && ArgList[4])
			{
				p = ArgList[4]; p++;
				put_it("%s", convert_output_format("$G %K[%nHighest client connection count%K(%n\002$0\002%K) %K(%n\002$1\002%K)]%n", "%s %s", ArgList[3], p));
			}
			break;
		}
		default:
			ret = 0;
			break;
	}
	return ret;
}

void whohas_nick (WhoisStuff *stuff, char *nick, char *args)
{
	if (!stuff || !stuff->nick || !nick || !strcmp(stuff->user, "<UNKNOWN>"))
		return;
	put_it("%s", convert_output_format("$G Your nick %R[%n$0%R]%n is owned by %W$1@$2", "%s %s %s", nick, stuff->user, stuff->host));
	return;
}


/*
 * numbered_command: does (hopefully) the right thing with the numbered
 * responses from the server.  I wasn't real careful to be sure I got them
 * all, but the default case should handle any I missed (sorry) 
 */
void numbered_command(char *from, int comm, char **ArgList)
{
	char	*user;
	char	none_of_these = 0;
	int	flag,
		lastlog_level;
	int	i;
	
	AJoinList *tmp = NULL;
#ifdef WANT_DLL
	NumericFunction *dll = NULL;
	int	code = 0;
#endif		

	context;
	if (!ArgList[1] || !from || !*from)
		return;
	
	user = (*ArgList[0]) ? ArgList[0] : NULL;

	lastlog_level = set_lastlog_msg_level(LOG_CRAP);
	message_from(NULL, LOG_CRAP);
	ArgList++;
	current_numeric = -comm;	/* must be negative of numeric! */

#ifdef WANT_DLL
	if (numeric_dll)
	{
		for (dll = numeric_dll; dll; dll = dll->next)
		{
			if (dll->number == comm)
				if ((code = (dll->func) (from, user, ArgList)))
					return;
		}
	}
#endif
	switch (comm)
	{
	case 001:	/* #define RPL_WELCOME          001 */
	{		
		bitchsay("For more information about \002BitchX\002 type \002/about\002");
		set_server2_8(from_server, 1);
		accept_server_nickname(from_server, user);
		attempting_to_connect--;
		set_server_motd(from_server, 1);
 		server_is_connected(from_server, 1);
		load_scripts();
		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList)) 
			display_msg(from, ArgList);
		if (get_int_var(AUTO_REJOIN_VAR))
		{
			char *channels = NULL, *keys = NULL;
			for(tmp = ajoin_list, i = 0; tmp; tmp = tmp->next, i+=3)
			{
				m_s3cat(&channels, ",", tmp->name);
				if (tmp->key)
					m_s3cat(&keys, ",", tmp->key);
				else
					malloc_strcat(&keys, ",");
			}
			if (channels)
				send_to_server("JOIN %s%s%s", channels, keys?" ":empty_string,keys?keys:empty_string);
			new_free(&channels); new_free(&keys);
		}
		if (send_umode && *send_umode == '+')
			send_to_server("MODE %s %s", user, send_umode);
		break;
	}		
/* should do something with this some day, 2.8 had channel/user mode switches */
	case 004:	/* #define RPL_MYINFO           004 */
	{
		got_initial_version_28(ArgList);
		load_scripts();
		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
			display_msg(from, ArgList);
		break;
	}
	case 250:
	case 251:
	case 252:
	case 253:
	case 254:
	case 255:
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
		{
			
			if (!handle_server_stats(from, ArgList, comm))
				display_msg(from, ArgList);
		}
		break;

	case 301:		/* #define RPL_AWAY             301 */
		user_is_away(from, ArgList);
		break;

	case 302:		/* #define RPL_USERHOST         302 */
		userhost_returned(from, ArgList);
		break;

	case 303:		/* #define RPL_ISON             303 */
		ison_returned(from, ArgList);
		break;

	case 311:		/* #define RPL_WHOISUSER        311 */
		whois_name(from, ArgList);
		break;

	case 312:		/* #define RPL_WHOISSERVER      312 */
		whois_server(from, ArgList);
		break;

	case 313:		/* #define RPL_WHOISOPERATOR    313 */
		whois_oper(from, ArgList);
		break;

	case 314:		/* #define RPL_WHOWASUSER       314 */
		whowas_name(from, ArgList);
		break;

	case 316:		/* #define RPL_WHOISCHANOP      316 */
		break;

	case 317:		/* #define RPL_WHOISIDLE        317 */
		whois_lastcom(from, ArgList);
		break;

	case 318:		/* #define RPL_ENDOFWHOIS       318 */
		end_of_whois(from, ArgList);
		break;

	case 319:		/* #define RPL_WHOISCHANNELS    319 */
		whois_channels(from, ArgList);
		break;

	case 321:		/* #define RPL_LISTSTART        321 */
		ArgList[0] = "Channel\0Users\0Topic";
		ArgList[1] = ArgList[0] + 8;
		ArgList[2] = ArgList[1] + 6;
		ArgList[3] = NULL;
		funny_list(from, ArgList);
		break;

	case 322:		/* #define RPL_LIST             322 */
		if (is_server_connected(from_server) && strcmp(from, server_list[from_server].itsname)) 
		{
			say("322 crash attempt from hacked server %s", from);
			break;
		}
		funny_list(from, ArgList);
		break;

	case 324:		/* #define RPL_CHANNELMODEIS    324 */
		funny_mode(from, ArgList);
		break;

	case 340:		/* #define RPL_INVITING_OTHER	340 */
	{
		if (ArgList[2])
		{
			message_from(ArgList[0], LOG_CRAP);
			if (do_hook(current_numeric, "%s %s %s %s", from, ArgList[0], ArgList[1], ArgList[2]))
				put_it("%s %s has invited %s to channel %s", numeric_banner(), ArgList[0], ArgList[1], ArgList[2]);
		}
		break;
	}

	case 341:		/* #define RPL_INVITING         341 */
		if (ArgList[1])
		{
			message_from(ArgList[1], LOG_CRAP);
			if (do_hook(current_numeric, "%s %s %s", from, ArgList[0], ArgList[1]))
				put_it("%s", convert_output_format(fget_string_var(FORMAT_INVITE_USER_FSET), "%s %s %s", update_clock(GET_TIME), ArgList[0], ArgList[1]));
		}
		break;

	case 352:		/* #define RPL_WHOREPLY         352 */
		if (server_list[from_server].in_who_kill)
		{
			who_handlekill(ArgList[4], ArgList[1], ArgList[2]);
			break;
		}
		whoreply(NULL, ArgList);
		break;

	case 353:		/* #define RPL_NAMREPLY         353 */
		funny_namreply(from, ArgList);
		break;

	case 366:		/* #define RPL_ENDOFNAMES       366 */
	{
		int	flag = 1;
		char	*tmp = NULL,
			*chan;
		PasteArgs(ArgList, 1);
		message_from(ArgList[0], LOG_CURRENT);
		if (get_int_var(SHOW_END_OF_MSGS_VAR))
			flag = do_hook(current_numeric, "%s %s %s", from, ArgList[0], ArgList[1]);
		message_from(NULL, LOG_CRAP);
		malloc_strcpy(&tmp, ArgList[0]);
		chan = strtok(tmp," ");
                               		
		if (!in_join_list(chan, from_server))
		{
			PasteArgs(ArgList, 0);
			if (get_int_var(SHOW_END_OF_MSGS_VAR) && flag)
				display_msg(from, ArgList);
		} else
			got_info(chan,from_server, GOTNAMES);
		new_free(&tmp);
	}
	break;

	case 381: 		/* #define RPL_YOUREOPER        381 */
		PasteArgs(ArgList, 0);
		if (!is_server_connected(from_server))
			say("Odd Server stuff from %s: %s",from, ArgList[0]);
		else if (do_hook(current_numeric, "%s %s", from, *ArgList))
		{
			if (fget_string_var(FORMAT_381_FSET))
				put_it("%s", 
					convert_output_format(
					fget_string_var(FORMAT_381_FSET), 
					"%s %s %s", 
					update_clock(GET_TIME),from, *ArgList));
			else
				display_msg(from, ArgList);
			server_list[from_server].ircop_flags = -1;
		}
		if (get_string_var(OPER_MODES_VAR))
			send_to_server("MODE %s %s", get_server_nickname(from_server), get_string_var(OPER_MODES_VAR));
		break;

	case 401:		/* #define ERR_NOSUCHNICK       401 */
		if (ArgList[0] && !check_dcc_list(ArgList[0]))
			no_such_nickname(from, ArgList);
		break;

	case 421:		/* #define ERR_UNKNOWNCOMMAND   421 */
		if (check_screen_redirect(ArgList[0]))
			break;
		if (check_wait_command(ArgList[0]))
			break;
		if (!strcmp(ArgList[0], "WAITFORNOTIFY"))
		{
			no_hook_notify = 0;
			break;
		}
		PasteArgs(ArgList, 0);
		
		if ((flag = do_hook(current_numeric, "%s %s", from, *ArgList)))
			display_msg(from, ArgList);
		break;

	case 432:		/* #define ERR_ERRONEUSNICKNAME 432 */
		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
			display_msg(from, ArgList);
		fudge_nickname(from_server);
		break;
	case 433:		/* #define ERR_NICKNAMEINUSE    433 */ 
		if (is_server_connected(from_server) && server_list[from_server].itsname && strcmp(from, server_list[from_server].itsname))
		{
			say("433 nicknameinuse attempt from hacked server %s", from);
			break;
		}
		fudge_nickname(from_server);
		add_to_whois_queue(ArgList[0], whohas_nick, "%s", ArgList[0]);
		PasteArgs(ArgList, 0);
		if (!never_connected && do_hook(current_numeric, "%s", *ArgList))
			display_msg(from, ArgList);
		break;
	case 451:		/* #define ERR_NOTREGISTERED    451 */
	/*
	 * Sometimes the server doesn't catch the USER line, so
	 * here we send a simplified version again  -lynx 
	 */
		register_server(from_server, NULL);

		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
			display_msg(from, ArgList);
		break;

	case 462:		/* #define ERR_ALREADYREGISTRED 462 */
		change_server_nickname(from_server, NULL);
		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
			display_msg(from, ArgList);
		break;

	case 463:  /* CDE added for ERR_NOPERMFORHOST */
		{
			PasteArgs(ArgList, 0);
			if (do_hook(current_numeric, "%s %s", from, *ArgList))
				display_msg(from, ArgList);
			close_server(from_server, empty_string);
			window_check_servers();
			if (from_server == primary_server)
				get_connected(from_server + 1);
			break;
		}
	case 464:		/* #define ERR_PASSWDMISMATCH   464 */
		if (is_server_connected(from_server)  && server_list[from_server].itsname && strcmp(from, server_list[from_server].itsname)) 
		{
			say("464 crash attempt from hacked server %s", from);
			break;
		}
		PasteArgs(ArgList, 0);
		if (!is_server_connected(from_server))
		{
			say("Odd Server stuff from %s: %s",from, ArgList[0]);
			return; 
		}
		flag = do_hook(current_numeric, "%s %s", from, ArgList[0]);
		if (oper_command)
		{
			if (flag)
				display_msg(from, ArgList);
			oper_command = 0;
		}
		else
		{
			char	server_num[8];

			say("Password required for connection to server %s",
				get_server_name(from_server));
			close_server(from_server, empty_string);
			if (!dumb)
			{
				strcpy(server_num, ltoa(from_server));
				add_wait_prompt("Server Password:", password_sendline,
				       server_num, WAIT_PROMPT_LINE);
			}
		}
		break;

	case 465:		/* #define ERR_YOUREBANNEDCREEP 465 */
	{
		int klined = from_server;
		
		if (is_server_connected(from_server)  && server_list[from_server].itsname && strcmp(from, server_list[from_server].itsname)) 
		{
			say("465 crash attempt from hacked server %s", from);
			break;
		}
		PasteArgs(ArgList, 0);
		if (!is_server_connected(from_server))
			return;
		if (do_hook(current_numeric, "%s %s", from, ArgList[0]))
			display_msg(from, ArgList);
				
		close_server(from_server, empty_string);
		window_check_servers();
		if (server_list_size() > 1)
			remove_from_server_list(klined);
		if (klined == primary_server && (server_list_size() > 0))
			get_connected(klined);
		break;
	}

	case 484:
	{
		if (do_hook(current_numeric, "%s %s", from, ArgList[0]))
			display_msg(from, ArgList);
		set_server_flag(from_server, USER_MODE_R, 1);
		break;
	}
	case 367:
		number_of_bans++;
		if (check_sync(comm, ArgList[0], ArgList[1], ArgList[2], ArgList[3], NULL) == 0)
			break;
		if (ArgList[2])
		{
			time_t tme = (time_t) strtoul(ArgList[3], NULL, 10);
			if (do_hook(current_numeric, "%s %s %s %s %s", 
				from, ArgList[0], ArgList[1], ArgList[2], ArgList[3]))
				put_it("%s", convert_output_format(fget_string_var(FORMAT_BANS_FSET), "%d %s %s %s %l", number_of_bans, ArgList[0], ArgList[1], ArgList[2], tme));
		}
		else
			if (do_hook(current_numeric, "%s %s %s", from, ArgList[0], ArgList[1]))
				put_it("%s", convert_output_format(fget_string_var(FORMAT_BANS_FSET), "%d %s %s %s %l", number_of_bans, ArgList[0], ArgList[1], "unknown", time(NULL)));
		break;
	case 368:		/* #define RPL_ENDOFBANLIST     368 */
	{
		if (!got_info(ArgList[0], from_server, GOTBANS))
			break;

		if (get_int_var(SHOW_END_OF_MSGS_VAR))
		{
			if (do_hook(current_numeric, "%s %d %s", from, number_of_bans, *ArgList))
			{
				put_it("%s Total Number of Bans on %s [%d]",
					numeric_banner(), ArgList[0],
					number_of_bans);
			}
		}
		number_of_bans = 0;
		break;
	}
	case 364:
#if 0
		if (is_server_connected(from_server)  && server_list[from_server].itsname && strcmp(from, server_list[from_server].itsname))
		{
			say("364 links attempt from hacked server %s", from);
			break;
		}
#endif
		if (comm == 364)
		{
			if (get_int_var(LLOOK_VAR) && (server_list[from_server].link_look == 1)) 
			{
				parse_364(ArgList[0], ArgList[1], ArgList[2] ? ArgList[2] : "0");
				break;
			} 
			else if (server_list[from_server].link_look == 2)	
			{
				add_to_irc_map(ArgList[0], ArgList[2]);
				break;
			}
			if ((do_hook(current_numeric, "%s %s %s", ArgList[0], ArgList[1], ArgList[2])))
			{
				if (fget_string_var(FORMAT_LINKS_FSET))
				{
					put_it("%s", convert_output_format(fget_string_var(FORMAT_LINKS_FSET), "%s %s %s", ArgList[0], ArgList[1], ArgList[2] ? ArgList[2] : "0"));
					break;
				}
			}
		}
	case 365:		/* #define RPL_ENDOFLINKS       365 */
		if (comm == 365)
		{
			if (get_int_var(LLOOK_VAR) && (server_list[from_server].link_look == 1)) 
			{
				parse_365(ArgList[0], ArgList[1],NULL);
				server_list[from_server].link_look = 0;
				break;
			} 
			else if (server_list[from_server].link_look == 2)	
			{
				show_server_map();
				server_list[from_server].link_look = 0;
				break;
			}
		}
	case 404:
	case 442:
	case 482:
		if (comm == 404 || comm == 482 || comm == 442)
		{
			if (check_server_sync(from, ArgList))
			{
				send_to_server("WHO -server %s %s", from, ArgList[0]);
				break;
			}
		}
	case 204:
		if (server_list[from_server].trace_flags & TRACE_OPER)
		{
			trace_oper(from, ArgList);
			break;
		} else if (server_list[from_server].trace_flags)
			break;
	case 203:
	case 205:
		if (server_list[from_server].trace_flags & TRACE_USER)
		{
			trace_user(from, ArgList);
			break;
		} else if (server_list[from_server].trace_flags)
			break;
	case 206:
		if (server_list[from_server].trace_flags & TRACE_SERVER)
		{
			trace_server(from, ArgList);
			break;
		} else if (server_list[from_server].trace_flags)
			break;
	case 200:
	case 207:
	case 209:
		if (server_list[from_server].trace_flags)
			break;

	case 262:
	case 402:
		if (comm == 402 && handle_server_ping(comm, from, ArgList))
			break;
		if ((comm == 262 || comm == 402) && server_list[from_server].trace_flags)
		{
			server_list[from_server].trace_flags = 0;
			break;
		}
		if (server_list[from_server].in_trace_kill)
		{
			if (comm == 200 || comm == 204 || comm == 206 || comm == 207)
				break;
			if (comm == 205 || comm == 203)
			{
				handle_tracekill(comm, ArgList[2], NULL, NULL);
				break;
			}
			if (comm == 209 || comm == 262 || comm == 402)
			{
				handle_tracekill(comm, NULL, NULL, NULL);
				break;
			}
		}
#if 0
	case 216: /* STATS k */
		if (comm == 216 && stats_k_grep(ArgList))
			break;
#endif
	/*
	 * The following accumulates the remaining arguments
	 * in ArgSpace for hook detection. We can't use
	 * PasteArgs here because we still need the arguments
	 * separated for use elsewhere.
	 */
	default:
		{
			char	*ArgSpace = NULL;
			int	i,
				len,
				do_message_from = 0;

			
			for (i = len = 0; ArgList[i]; len += strlen(ArgList[i++]))
				;
			len += (i - 1);
			ArgSpace = new_malloc(len + 1);
			ArgSpace[0] = '\0';
			/* this is cheating */

			if (ArgList[0] && is_channel(ArgList[0]))
				do_message_from = 1;
			for (i = 0; ArgList[i]; i++)
			{
				if (i)
					strcat(ArgSpace, " ");
				strcat(ArgSpace, ArgList[i]);
			}
			if (do_message_from)
				message_from(ArgList[0], LOG_CRAP);
			if (!do_hook(current_numeric, "%s %s", from, ArgSpace))
			{
				new_free(&ArgSpace);
				if (do_message_from)
					message_from(NULL, lastlog_level);
				return;
			}
			if (do_message_from)
				message_from(NULL, lastlog_level);
			new_free(&ArgSpace);
			none_of_these = 1;
		}
	}
	/* the following do not hurt the ircII if intercepted by a hook */
	if (none_of_these)
	{
		switch (comm)
		{
		case 211:
		case 212:
		case 213:
		case 214:
		case 215:
		case 216: 
		case 218:
		case 241:
		case 242:
		case 243:
		case 244:
			if (server_list[from_server].stats_flags && ((comm > 210 && comm < 219) || (comm > 240 && comm < 245)))
			{
				handle_stats(comm, from, ArgList);
				break;
			}
			else if (!server_list[from_server].stats_flags && comm == 242)
			{
/*		case 242:		 #define RPL_STATSUPTIME      242 */
				PasteArgs(ArgList, 0);
				if (from && !my_strnicmp(get_server_itsname(from_server),
				    from, strlen(get_server_itsname(from_server))))
					from = NULL;
				if (from)
					put_it("%s %s from (%s)", numeric_banner(),
						*ArgList, from);
				else
					put_it("%s %s", numeric_banner(), *ArgList);
				break;
			}
			else
			{
				PasteArgs(ArgList, 0);
				put_it("%s %s %s", numeric_banner(), from, *ArgList);
			}
			break;
		case 219:		/* #define RPL_ENDOFSTATS       219 */
#if 0
			if (!server_list[from_server].stats_flags && comm == 219)
				stats_k_grep_end();
#endif
			if (server_list[from_server].stats_flags && comm == 219)
				server_list[from_server].stats_flags = 0;
			break;
		case 221: 		/* #define RPL_UMODEIS          221 */
			put_it("%s Your user mode is [%s]", numeric_banner(), ArgList?ArgList[0]:" ");
			break;

		case 272:/* ENDOFSILENCE */
			PasteArgs(ArgList, 0);
			put_it("%s", convert_output_format(fget_string_var(FORMAT_SILENCE_FSET), update_clock(GET_TIME), ArgList[0]));
			break;

		case 329:		/* #define CREATION_TIME	329 */
		{
			time_t tme;
			char *this_sucks;
			ChannelList *chan = NULL;
			
			if (!ArgList[1] || !*ArgList[1])
				break;
			sscanf(ArgList[1], "%lu", &tme);
			this_sucks = ctime(&tme);
			this_sucks[strlen(this_sucks)-1] = '\0';		

			message_from(ArgList[0], LOG_CRAP);
			put_it("%s Channel %s was created at %s",numeric_banner(),
				ArgList[0], this_sucks);
			if ((chan = lookup_channel(ArgList[0], from_server, 0)))
				chan->channel_create.tv_sec = tme;
			message_from(NULL, LOG_CURRENT);
			break;
		}
		case 332:		/* #define RPL_TOPIC            332 */
			channel_topic(from, ArgList, 332);
			break;
		case 333:
			channel_topic(from, ArgList, 333);
			break;
			
		case 351:		/* #define RPL_VERSION          351 */
			if (!handle_server_ping(comm, from, ArgList))
			{
				PasteArgs(ArgList, 2);
				put_it("%s", convert_output_format(fget_string_var(FORMAT_SERVER_FSET), "Server %s %s %s", ArgList[0], ArgList[1], ArgList[2]));
			}
			break;

		case 364:		/* #define RPL_LINKS            364 */
		{

			if (ArgList[2])
			{
				PasteArgs(ArgList, 2);
				put_it("%s %-20s %-20s %s", numeric_banner(),
					ArgList[0], ArgList[1], ArgList[2]);
			}
			else
			{
				PasteArgs(ArgList, 1);
				put_it("%s %-20s %s", numeric_banner(),
					ArgList[0], ArgList[1]);
			}
		}
		break;
		case 377:
		case 372:		/* #define RPL_MOTD             372 */
			if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
			    !get_server_motd(from_server))
			{
				PasteArgs(ArgList, 0);
				put_it("%s %s", numeric_banner(), ArgList[0]);
			}
			break;

		case 375:		/* #define RPL_MOTDSTART        375 */
			if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
			    !get_server_motd(from_server))
			{
				PasteArgs(ArgList, 0);
				put_it("%s %s", numeric_banner(), ArgList[0]);
			}
			break;

		case 376:		/* #define RPL_ENDOFMOTD        376 */
			if (get_int_var(SHOW_END_OF_MSGS_VAR) &&
			    (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
			    !get_server_motd(from_server)))
			{
				PasteArgs(ArgList, 0);
				put_it("%s %s", numeric_banner(), ArgList[0]);
			}
			set_server_motd(from_server, 0);
			break;

		case 384:		/* #define RPL_MYPORTIS         384 */
			PasteArgs(ArgList, 0);
			put_it("%s %s %s", numeric_banner(), ArgList[0], user);
			break;

		case 385:		/* #define RPL_NOTOPERANYMORE   385 */
			set_server_operator(from_server, 0);
			display_msg(from, ArgList);
			update_all_status(curr_scr_win, NULL, 0);
			break;

		case 403:		/* #define ERR_NOSUCHCHANNEL    403 */
			not_valid_channel(from, ArgList);
			break;

		case 432:		/* #define ERR_ERRONEUSNICKNAME 432 */
			display_msg(from, ArgList);
			reset_nickname();
			break;

		case 471:		/* #define ERR_CHANNELISFULL    471 */
		case 473:		/* #define ERR_INVITEONLYCHAN   473 */
		case 474:		/* #define ERR_BANNEDFROMCHAN   474 */
		case 475: 		/* #define ERR_BADCHANNELKEY    475 */
		case 476:		/* #define ERR_BADCHANMASK      476 */
			cannot_join_channel(from, ArgList);
			break;

#define RPL_CLOSEEND         363
#define RPL_SERVLISTEND      235
		case 315:		/* #define RPL_ENDOFWHO         315 */
			{
				if (in_join_list(ArgList[0], from_server))
				{
					if (who_on_join) 
						who_on_join = 0;
					got_info(ArgList[0], from_server, GOTWHO);
					break;
				} else if (who_on_join)
				{
					who_on_join--;
					break;
				}
				if (doing_who)
					doing_who--;
				if (server_list[from_server].in_who_kill)
				{
					who_handlekill(NULL, NULL, NULL);
					break;
				}
				if (get_int_var(SHOW_END_OF_MSGS_VAR))
					if (do_hook(current_numeric, "%s %s", from, ArgList[0]))
						put_it("%s %s %s",numeric_banner(), from, ArgList[0]);
			}
		case 316:
			break;

		case 323:               /* #define RPL_LISTEND          323 */
			funny_print_widelist();

		case 232:		/* #define RPL_ENDOFSERVICES    232 */
		case 365:		/* #define RPL_ENDOFLINKS       365 */
			if (comm == 365 && get_int_var(LLOOK_VAR) && server_list[from_server].link_look) 
			{
				parse_365(ArgList[0], ArgList[1],NULL);
				server_list[from_server].link_look--;
				break;
			}
		case 369:		/* #define RPL_ENDOFWHOWAS      369 */
		case 374:		/* #define RPL_ENDOFINFO        374 */
		case 394:		/* #define RPL_ENDOFUSERS       394 */
			if (get_int_var(SHOW_END_OF_MSGS_VAR))
			{
				PasteArgs(ArgList, 0);
				if (do_hook(current_numeric, "%s %s", from, *ArgList))
					display_msg(from, ArgList);
			}
			break;
		default:
			display_msg(from, ArgList);
		}
	}
	set_lastlog_msg_level(lastlog_level);
}

