/*
 * 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 
 */

#if 0
static	char	rcsid[] = "$Id: numbers.c,v 1.12 1993/12/30 12:45:35 mrgreen Exp $";
#endif

#include "irc.h"

#include "input.h"
#include "ircaux.h"
#include "vars.h"
#include "lastlog.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 "edit.h"
#include "notice.h"

static void fudge_nickname _((void));

static	int	already_doing_reset_nickname = 0;
static 	int	number_of_bans = 0;
extern	int	in_e_nick;

/*
 * numeric_banner: This returns in a static string of either "xxx" where
 * xxx is the current numeric, or "***" if SHOW_NUMBERS is OFF 
 */
extern char	*
numeric_banner _((void))
{
	static	char	thing[4];

	if (get_int_var(SHOW_NUMERICS_VAR))
		sprintf(thing, "%3.3u", -current_numeric);
	else
		strcpy(thing, "***");
	return (thing);
}


/*
 * 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 
 */
#ifdef __STDC__
extern void display_msg (char *from, char **ArgList)
#else
extern void
display_msg(from, ArgList)
	char	*from,
		**ArgList;
#endif
{
	char	*ptr;
	char	*rest;

	rest = PasteArgs(ArgList, 0);
	if (from && (my_strnicmp(get_server_itsname(from_server), from,
			strlen(get_server_itsname(from_server))) == 0))
		from = (char *) 0;
	if ((ptr = (char *) index(rest, ':')) != NULL)
	{
		*(ptr++) = (char) 0;
		if (strlen(rest))
		{
			if ((from) && (!get_int_var(SUPPRESS_FROM_REMOTE_SERVER)))
				put_it("%s %s: %s (from %s)", numeric_banner(),
					rest, ptr, from);
			else
				put_it("%s %s: %s", numeric_banner(), rest,
					ptr);
		}
		else
		{
			if ((from) && (!get_int_var(SUPPRESS_FROM_REMOTE_SERVER)))
				put_it("%s %s (from %s)", numeric_banner(),
					ptr, from);
			else
				put_it("%s %s", numeric_banner(), ptr);
		}
	}
	else
	{
		if ((from) && (!get_int_var(SUPPRESS_FROM_REMOTE_SERVER)))
			put_it("%s %s (from %s)", numeric_banner(), rest, from);
		else
			put_it("%s %s", numeric_banner(), rest);
	}
}

/*
 * password_sendline: called by send_line() in get_password() to handle
 * hitting of the return key, etc 
 */
#ifdef __STDC__
static void password_sendline (char *data, char *line)
#else
static	void
password_sendline(data, line)
	char	*data;
	char	*line;
#endif
{
	int	new_server;

	new_server = atoi(line);
	set_server_password(new_server, line);
	connect_to_server_by_refnum(new_server, -1);
}

/*
 * get_password: when a host responds that the user needs to supply a
 * password, it gets handled here!  the user is prompted for a password and
 * then reconnection is attempted with that password.  but, the reality of
 * the situation is that no one really uses user passwords.  ah well 
 */
static	void
get_password _((void))
{
	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);
	}
}

#ifdef __STDC__
extern void nickname_sendline (char *data, char *nick)
#else
extern	void
nickname_sendline(data, nick)
	char	*data;
	char	*nick;
#endif
{
	int	new_server, server;

	new_server = atoi(data);
	if ((nick = check_nickname(nick)) != NULL)
	{
		server = from_server;
		from_server = new_server;
		send_to_server("NICK %s", nick);
		if (new_server == primary_server)
			strmcpy(nickname, nick, 
#ifdef ALLOW_LONG_NICKNAMES
						LONG_NICKNAME_LEN
#else
						NICKNAME_LEN
#endif
								  );
		set_server_nickname(new_server, nick);
		from_server = server;
		already_doing_reset_nickname = 0;
		update_all_status();
	}
	else
	{
		say("illegal nickname, try again");
		if (!dumb)
			add_wait_prompt("Nickname: ", nickname_sendline, data,
					WAIT_PROMPT_LINE);
	}
}

/*
 * reset_nickname: when the server reports that the selected nickname is not
 * a good one, it gets reset here. 
 */
static void reset_nickname _((void))
{
	char	server_num[10];

	if (already_doing_reset_nickname)
		return;
	say("You have specified an illegal nickname");
	if (!dumb)
	{
		already_doing_reset_nickname = 1;
		say("Please enter your nickname");
		strcpy(server_num, ltoa(from_server));
		add_wait_prompt("Nickname: ", nickname_sendline, server_num,
			WAIT_PROMPT_LINE);
	}
	update_all_status();
}

#ifdef __STDC__
static void channel_topic (char *from, char **ArgList)
#else
static	void
channel_topic(from, ArgList)
	char	*from,
		**ArgList;
#endif
{
	message_from(ArgList[0], LOG_CRAP);
	put_it("%s Topic for %s: %s", numeric_banner(), ArgList[0], ArgList[1]);
}

#ifdef __STDC__
static void nickname_in_use (char *from, char **ArgList)
#else
static void
nickname_in_use(from, ArgList)
	char	*from,
		**ArgList;
#endif
{
	PasteArgs(ArgList, 0);
	fudge_nickname();
	if (!never_connected)
		if (do_hook(current_numeric, "%s", *ArgList))
			display_msg(from, ArgList);
}

#ifdef __STDC__
static void not_valid_channel (char *from, char **ArgList)
#else
static	void
not_valid_channel(from, ArgList)
	char	*from,
		**ArgList;
#endif
{
	char	*channel;
	char	*s;

	if (!(channel = ArgList[0]) || !ArgList[1])
		return;
	PasteArgs(ArgList, 1);
	s = get_server_name(from_server);
	if (0 == my_strnicmp(s, from, strlen(s)))
	{
/* hack cause channel may be null */
		if (channel)
		{
			remove_channel(channel, from_server);
			put_it("%s %s %s", numeric_banner(), channel, ArgList[1]);
		}
		else
			put_it("%s You did not specify a channel", numeric_banner());
	}
}

/* from ircd .../include/numeric.h */
/*
#define ERR_TOOMANYCHANN     405
#define ERR_CHANNELISFULL    471
#define ERR_INVITEONLYCHAN   473
#define ERR_BANNEDFROMCHAN   474
#define ERR_BADCHANNELKEY    475
#define ERR_BADCHANMASK      476
*/
#ifdef __STDC__
static void cannot_join_channel (char *from, char **ArgList)
#else
static	void
cannot_join_channel(from, ArgList)
	char	*from,	
		**ArgList;
#endif
{
	char buffer[BIG_BUFFER_SIZE + 1];

	if (ArgList[0])
		remove_channel(ArgList[0], from_server);
	PasteArgs(ArgList, 0);
	strcpy(buffer, ArgList[0]);
	switch(-current_numeric)
	{
	case 471:
		strcat(buffer, " (Channel is full)");
		break;
	case 473:
		strcat(buffer, " (You must be invited)");
		break;
	case 474:
		strcat(buffer, " (You are banned)");
		break;
	case 475:
		strcat(buffer, " (You must give the correct key)");
		break;
	case 476:
		strcat(buffer, " (Bad channel mask)");
		break;
	}
	put_it("%s %s", numeric_banner(), buffer);
}


#ifdef __STDC__
static void version (char *from, char **ArgList)
#else
static	void
version(from, ArgList)
	char	*from,
		**ArgList;
#endif
{
#ifdef COMPAT_27
	if (ArgList[2])
	{
#endif
		PasteArgs(ArgList, 2);
		put_it("%s Server %s: %s %s", numeric_banner(), ArgList[1],
			ArgList[0], ArgList[2]);
#ifdef COMPAT_27
	}
	else
	{
		PasteArgs(ArgList, 1);
		put_it("%s Server %s: %s", numeric_banner(), ArgList[1],
			ArgList[0]);
	}
#endif
}


#ifdef __STDC__
static void invite (char *from, char **ArgList)
#else
static	void
invite(from, ArgList)
	char	*from,
		**ArgList;
#endif
{
	char	*who,
		*channel;

	if ((who = ArgList[0]) && (channel = ArgList[1]))
	{
		message_from(channel, LOG_CRAP);
		if (do_hook(current_numeric, "%s %s %s", from, who, channel))
			put_it("%s Inviting %s to channel %s",
					numeric_banner(), who, channel);
	}
}


/*
 * 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) 
 */
#ifdef __STDC__
extern void numbered_command (char *from, int comm, char **ArgList)
#else
extern void
numbered_command(from, comm, ArgList)
	char	*from;
	int	comm;
	char	**ArgList;
#endif
{
	char	*user;
	char	none_of_these = 0;
	int	flag,
		lastlog_level;

	if (!ArgList[0] || !ArgList[1])
		return;

	user = (*ArgList[0]) ? ArgList[0] : NULL;

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

	switch (comm)
	{
	/*
	 * I added the "set_server_nickname" here because the client
	 * when auto-fudging your nick will sometimes be confused as
	 * what your nickname really is when you connect.  Since the
	 * server always tells us who the message was set to (ie, us)
	 * we just kind of take it at its word.
	 */
	case 001:	/* #define RPL_WELCOME          001 */
		set_server2_8(from_server, 1);
		set_server_nickname(from_server, user);
		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList)) 
			display_msg(from, ArgList);
		break;

	/* 
	 * Now instead of the terribly horrible hack using numeric 002
	 * to get the server name/server version info, we use the 004
	 * numeric which is what is the most logical choice for it.
	 */
	case 004:	/* #define RPL_MYINFO           004 */
		got_initial_version_28(ArgList);
		PasteArgs(ArgList, 0);
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
			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 315:		/* #define RPL_ENDOFWHO         315 */
	{
		extern int doing_who;

		if (cannot_open != (char *) 0)
			yell("Cannot open: %s", cannot_open);

		/* XXX oops.. forgot this. >;-) */
		doing_who = 0;

		/* Ooops. found by murple */
		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:		/* supported, but deprecated */
		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] = (char *) 0;
		funny_list(from, ArgList);
		break;

	case 322:		/* #define RPL_LIST             322 */
		funny_list(from, ArgList);
		break;

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

	case 341:		/* #define RPL_INVITING         341 */
		invite(from, ArgList);
		break;

	case 352:		/* #define RPL_WHOREPLY         352 */
		whoreply((char *) 0, ArgList);
		break;

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

	case 366:		/* #define RPL_ENDOFNAMES       366 */
	{
		int	flag = 1;

		PasteArgs(ArgList, 0);
		if (get_int_var(SHOW_END_OF_MSGS_VAR))
			flag = do_hook(current_numeric, "%s %s", from, ArgList[0]);
	
		if (!funny_is_ignore_channel())
		{
			if (get_int_var(SHOW_END_OF_MSGS_VAR) && flag)
				display_msg(from, ArgList);
		}
		else
			funny_set_ignore_mode();
		break;
	}

	case 367:		/* #define RPL_BANLIST */
	{
		number_of_bans++;
		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 %s %-25s set by %-10s %lu sec ago", 
				numeric_banner(), ArgList[0],
				ArgList[1], ArgList[2], 
				(unsigned long)(time(NULL) - tme));
		}
		else
			if (do_hook(current_numeric, "%s %s %s", from, ArgList[0], ArgList[1]))
				put_it("%s %s %s",numeric_banner(), ArgList[0], ArgList[1]);
		break;
	}
	case 368:		/* #define END_OF_BANLIST */
	{
		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;
	}
	/* I put these here so that if you have SUPPRESS_SERVER_MOTD set
	 * to on, then you cant hook 372, 375, 376, as advertised.
	 */
	case 372:		/* #define RPL_MOTD             372 */
		if (!get_int_var(SUPPRESS_SERVER_MOTD_VAR) ||
		    !get_server_motd(from_server))
		{
			PasteArgs(ArgList, 0);
			if (do_hook(current_numeric, "%s %s", from, 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);
			if (do_hook(current_numeric, "%s %s", from, 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);
			if (do_hook(current_numeric, "%s %s", from, ArgList[0]))
				put_it("%s %s", numeric_banner(), ArgList[0]);
		}
		set_server_motd(from_server, 0);
		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]);
			return;
		}
		if (do_hook(current_numeric, "%s %s", from, *ArgList))
			display_msg(from, ArgList);
		break;

	case 401:		/* #define ERR_NOSUCHNICK       401 */
		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;
		PasteArgs(ArgList, 0);
		flag = do_hook(current_numeric, "%s %s", from, *ArgList);
		if (flag)
			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();
		break;

	case 433:		/* #define ERR_NICKNAMEINUSE    433 */ 
		nickname_in_use(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 
	 */
		send_to_server("USER %s %s . :%s", username,
			(send_umode && *send_umode) ? send_umode : ".", realname);
		send_to_server("NICK %s", get_server_nickname(from_server));

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


	case 462:		/* #define ERR_ALREADYREGISTRED 462 */
	{
		send_to_server("NICK %s", get_server_nickname(from_server));

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

	case 464:		/* #define ERR_PASSWDMISMATCH   464 */
	{
		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);
		}
		else
			get_password();
		break;
	}
	case 465:		/* #define ERR_YOUREBANNEDCREEP 465 */
	{
		PasteArgs(ArgList, 0);
		/* There used to be a say() here, but if we arent 
		 * connected to a server, then doing say() is not
		 * a good idea.  So now it just doesnt do anything.
		 */
		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();
#ifndef I_DONT_TRUST_MY_USERS
		if (from_server == primary_server)
			get_connected(from_server + 1);
#endif
		break;
	}

	case 219:		/* #define RPL_ENDOFSTATS       219 */
	case 232:		/* #define RPL_ENDOFSERVICES    232 */
	case 365:		/* #define RPL_ENDOFLINKS       365 */
	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;
	}

	/*
	 * 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 = (char *) 0;
		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)
				set_lastlog_msg_level(lastlog_level);
			return;
		}
		if (do_message_from)
			message_from((char *) 0, lastlog_level);
		new_free(&ArgSpace);
		none_of_these = 1;
	} /* end of default case */
	} /* end of switch */

	/* the following do not hurt the ircII if intercepted by a hook */
	if (none_of_these)
	{
		switch (comm)
		{
		case 221: 		/* #define RPL_UMODEIS          221 */
		{
			put_it("%s Your user mode is \"%s\"", numeric_banner(),
				ArgList[0]);
			break;
		}
		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;
		}
		case 271:		/* #define SILENCE_LIST		271 */
		{
			put_it ("%s %s is ignoring %s", numeric_banner(), ArgList[0], ArgList[1]);
			break;
		}
		case 272:		/* #define ENDOFSILENCE		272 */
		{
			PasteArgs(ArgList, 0);
			put_it ("%s %s", numeric_banner(), ArgList[0]);
			break;
		}
		case 329:		/* #define CREATION_TIME	329 */
		{
			time_t tme;
			char *this_sucks;

			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);
			message_from((char *) 0, LOG_CURRENT);
			break;
		}
		case 332:		/* #define RPL_TOPIC            332 */
			channel_topic(from, ArgList);
			break;

		case 333:		/* #define RPL_TOPICWHOTIME	333 */
		{
			unsigned long tme;
			/* Ooops. Texaco caught this bug */
			tme = (unsigned long)atol(ArgList[2]);
			put_it("%s The topic was set by %s %lu sec ago",numeric_banner(), 
				ArgList[1], (unsigned long)(time(NULL)-tme));
			break;
		}
		case 351:		/* #define RPL_VERSION          351 */
			version(from, ArgList);
			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 384:		/* #define RPL_MYPORTIS         384 */
			PasteArgs(ArgList, 0);
			put_it("%s %s %s", numeric_banner(), ArgList[0], user);
			break;

		case 403:		/* #define ERR_NOSUCHCHANNEL    403 */
			not_valid_channel(from, ArgList);
			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 323:               /* #define RPL_LISTEND          323 */
			funny_print_widelist();

		default:
			display_msg(from, ArgList);
		}
	}
	set_lastlog_msg_level(lastlog_level);
}


/* Dont even think of calling this function with anything that isnt
 * really a nickname -- it may cause segfaults!
 */
/* This will generate up to 18 nicknames plus the 9-length(nickname)
 * that are unique but still have some semblance of the original.
 * This is intended to allow the user to get signed back on to
 * irc after a nick collision without their having to manually
 * type a new nick every time..
 * 
 * The func will try to make an intelligent guess as to when it is
 * out of guesses, and if it ever gets to that point, it will do the
 * manually-ask-you-for-a-new-nickname thing.
 */
static void fudge_nickname _((void))
{
	static char oldnick[LONG_NICKNAME_LEN+1] = {0};
	static int fudge_index = 0;
	char blah[4];
	extern int from_server;
	char nickname[LONG_NICKNAME_LEN + 1] = {0};

	if (in_e_nick)
		return;		/* if we're changing nickname, dont bother */

	strcpy(nickname, get_server_nickname(from_server));

	if (!get_int_var(AUTO_NEW_NICK_VAR))
	{
		reset_nickname();
		return;
	}

	/* First time through... */
	if (!*oldnick)
	{
		strncpy(oldnick, nickname,
#ifdef ALLOW_LONG_NICKNAMES
						LONG_NICKNAME_LEN
#else
						NICKNAME_LEN
#endif
									);
		fudge_index = strlen(nickname);
	}
	else
	{
		/* Same nick as the last one we convoluted? */
		if (!my_stricmp(oldnick, nickname))
		{
			fudge_index++;
			if (fudge_index == 17)
			{
				/* give up... */
				reset_nickname();
				fudge_index = 0;
				return;
			}
		}
		/* Different nick then last time.. start over. */
		else
		{
			strcpy(oldnick, nickname);
			fudge_index = strlen(nickname);
		}
	}

	/* 
	 * Process of fudging a nickname:
	 * If the nickname length is less then 9, add an underscore.
	 */
	if (strlen(nickname) < 9)
		strcat(nickname, "_");

	/* 
	 * The nickname is 9 characters long. roll the nickname
	 */
	else
	{
		char tmp = nickname[8];
		nickname[8] = nickname[7];
		nickname[7] = nickname[6];
		nickname[6] = nickname[5];
		nickname[5] = nickname[4];
		nickname[4] = nickname[3];
		nickname[3] = nickname[2];
		nickname[2] = nickname[1];
		nickname[1] = nickname[0];
		nickname[0] = tmp;
	}

	strcpy(blah, ltoa(from_server));
	strcpy(oldnick, nickname);
	nickname_sendline(blah, nickname);
}

