All pastes #462801 Raw Edit

TheShining

public c v1 · immutable
#462801 ·published 2007-04-28 15:43 UTC
rendered paste body
/* * ================================================================== * Filename:             m_spy.c * Description:          Real-time spying * Written by:		 AngryWolf <angrywolf@flashmail.com> * The idea was born by: Toxyc <toxyc@freemail.hu> * ================================================================== */#include "config.h"#include "struct.h"#include "common.h"#include "sys.h"#include "numeric.h"#include "msg.h"#include "channel.h"#include <time.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#ifdef _WIN32#include <io.h>#endif#include <fcntl.h>#include "h.h"#ifdef STRIPBADWORDS#include "badwords.h"#endif#ifdef _WIN32#include "version.h"#endif// ==================================================================// Definitions & macros// ==================================================================#define MSG_SPY 		"OKUMA"#define TOK_SPY 		"SPY"#define MSG_SPYCHANNEL 		"SPYCHAN"#define TOK_SPYCHANNEL		"SPC"#define MSG_SPYSEND 		"SPYSEND"#define TOK_SPYSEND 		"SPE"#define MSG_SPYCHSEND 		"SPYCHSEND"#define TOK_SPYCHSEND 		"SPT"#define MSG_SPYFORWARD 		"SPYFORWARD"#define TOK_SPYFORWARD 		"SPF"#define MSG_SPYCHFORWARD 	"SPYCHFORWARD"#define TOK_SPYCHFORWARD 	"SPG"#define MSG_SPYSTATS 		"SPYSTATS"#define TOK_SPYSTATS 		"SPS"#define MyMod			SpyModInfo->handle#define FlagSpy			'X'#define LockFlag		'@'#define LockFlagStr		"@"#define SPY_NOTICE		":%s NOTICE %s :*** "#define SPY_LINE		"=================================================="#define ircfree(x)		if (x) free(x)#define ircstrdup(x,y)		if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y)#define DelSnomask(x)		if (x) SnomaskDel(x); x = NULL#define DelHook(x)		if (x) HookDel(x); x = NULL#define DelCommand(x)		if (x) CommandDel(x); x = NULL#define IsParam(x)		(parc > (x) && !BadPtr(parv[(x)]))#define IsValidParam(x)		(parc > (x) && !BadPtr(parv[(x)]) && *parv[(x)] != '*')#define AddLock(lock)		(lock ? LockFlagStr : "")#define GetLock(str)		(*str == LockFlag ? 1 : 0)#define SplitLock(lock, str)	del_prefix(str, &(lock), &(str))#define MergeLock(lock, str)	AddLock(lock), str#define MergeLockOpt(lock, str)	str ? AddLock(lock) : "", str ? str : "*"#define MergeLockEmp(lock, str)	str ? AddLock(lock) : "", str ? str : ""#define SpyForward5(cptr, cmd, who, nick1, nick2, channel, lock1, lock2) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYFORWARD, TOK_SPYFORWARD, \		"%s %s %s%s %s%s %s", \		cmd, who, MergeLock(lock1, nick1), MergeLockOpt(lock2, nick2), \		channel ? channel : "*")#define SpyForward4(cptr, cmd, who, nick1, nick2, lock1, lock2) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYFORWARD, TOK_SPYFORWARD, \		"%s %s %s%s %s%s", \		cmd, who, MergeLock(lock1, nick1), MergeLockOpt(lock2, nick2))#define SpyForward3(cptr, cmd, who, nick1, lock1) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYFORWARD, TOK_SPYFORWARD, \		"%s %s %s%s", \		cmd, who, MergeLock(lock1, nick1))#define SpyForward2(cptr, cmd, who) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYFORWARD, TOK_SPYFORWARD, \		"%s %s", \		cmd, who)#define SpyForward1(cptr, cmd) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYFORWARD, TOK_SPYFORWARD, \		"%s", \		cmd)#define SpyChForward4(cptr, cmd, who, channel, sendto, lock) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYCHFORWARD, TOK_SPYCHFORWARD, \		"%s %s %s%s %s", \		cmd, who, MergeLock(lock, channel), sendto ? sendto : "*")#define SpyChForward3(cptr, cmd, who, channel, lock) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYCHFORWARD, TOK_SPYCHFORWARD, \		"%s %s %s%s", \		cmd, who, MergeLock(lock, channel))#define SpyChForward2(cptr, cmd, who) \		sendto_serv_butone_token(cptr, me.name, MSG_SPYCHFORWARD, TOK_SPYCHFORWARD, \		"%s %s", \		cmd, who)typedef struct _spystruct	SpyStruct;typedef struct _spychstruct	SpyChStruct;struct _spystruct{	SpyStruct	*prev, *next;	aClient		*who;		/* Who is spying */	char		*nick1;		/* First nick to spy */	char		*nick2;		/* Second nick to spy (may be NULL) */	char		*chname;	/* Where to put messages (may be NULL) */	u_int		lock1:1;		/* 1 if nick1 is locked, otherwise 0 */	u_int		lock2:1;		/* 1 if nick2 is locked, otherwise 0 */};struct _spychstruct{	SpyChStruct	*prev, *next;	aClient		*who;		/* Who is spying */	char		*channel;	/* Channel to be spyed */	char		*sendto;	/* Where to put messages (may be NULL) */	u_int		lock;		/* True if nick1 is locked, otherwise 0 */};static SpyStruct	*FindSpyItem1(aClient *acptr, char *nick);static SpyStruct	*FindSpyItem2(aClient *acptr, char *nick1, char *nick2);static SpyChStruct	*FindSpyChItem(aClient *acptr, char *channel);static void		AddSpyItem(aClient *acptr, char *nick1, char *nick2, char *chname, u_int lock1, u_int lock2);static void		AddSpyChItem(aClient *acptr, char *channel, char *sendto, u_int lock);static void		DelSpyItem(SpyStruct *s);static void		DelSpyChItem(SpyChStruct *s);static unsigned int	spy_paramcheck(aClient *cptr, int parc, char *parv[], char **nick1, char **nick2, char **channel, u_int *lock1, u_int *lock2);static unsigned int	spych_paramcheck(aClient *cptr, int parc, char *parv[], char **channel, char **sendto, u_int *lock);static void		spy_send_client(aClient *acptr, int notice, char *nick1, char *nick2, char *text);static void		spy_send_channel(aClient *cptr, char *channel, int notice, char *nick1, char *nick2, char *text);static void		spych_send_client(aClient *acptr, int notice, char *nick, char *channel, char *text);static void		spych_send_channel(aClient *cptr, char *sendto, int notice, char *nick, char *channel, char *text);static void		del_prefix(char *str, u_int *lock, char **newstr);static Command		*AddCommand(char *msg, char *token, int (*func)());DLLFUNC int		m_spy(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC int		m_spychannel(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC int		m_spysend(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC int		m_spychsend(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC int		m_spyforward(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC int		m_spychforward(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC int		m_spystats(aClient *cptr, aClient *sptr, int parc, char *parv[]);DLLFUNC char		*spy_on_privmsg(aClient *, aClient *, aClient *, char *, int);DLLFUNC char		*spy_on_chanmsg(aClient *, aClient *, aChannel *, char *, int);DLLFUNC int		spy_on_quit(aClient *, char *);DLLFUNC int		spy_on_remote_quit(aClient *, char *);DLLFUNC int		spy_on_server_connect(aClient *);DLLFUNC int		spy_on_local_nickchange(aClient *, char *);DLLFUNC int		spy_on_remote_nickchange(aClient *, aClient *, char *);DLLFUNC int		spy_on_channel_destroy(aChannel *);// ==================================================================// Module header// ==================================================================ModuleHeader MOD_HEADER(m_spy)  = {	"spy",	"$Id: m_spy.c,v 3.6 2003/12/01 18:31:45 angrywolf Exp $",	"real-time spying",	"3.2-b8-1",	NULL     };// ==================================================================// Main declarations// ==================================================================static char *SpyHelp[] ={    SPY_NOTICE	"\2Usage:\2",    SPY_NOTICE	"/spy add <nick1> [<nick2> [<#channel>]]",    SPY_NOTICE	"/spy del <nick1> [<nick2>]",    SPY_NOTICE	"/spy list [<nick1> [<nick2>]] [<#channel>]",    SPY_NOTICE	"/spy clear",    SPY_NOTICE	"\2Examples:\2",    SPY_NOTICE	"/spy add AngryWolf Toxyc #secret",    SPY_NOTICE	"/spy del AngryWolf",    SPY_NOTICE	"/spy list #secret",    NULL};static char *SpyChHelp[] ={    SPY_NOTICE	"\2Usage:\2",    SPY_NOTICE	"/spychan add <#channel> [<#sendto>]]",    SPY_NOTICE	"/spychan del <#channel>",    SPY_NOTICE	"/spychan list [<#channel>]",    SPY_NOTICE	"/spychan clear",    SPY_NOTICE	"\2Examples:\2",    SPY_NOTICE	"/spychan add #warez #spy",    SPY_NOTICE	"/spychan del #warez",    SPY_NOTICE	"/spychan list",    NULL};ModuleInfo		*SpyModInfo;Command			*CmdSpy, *CmdSpychannel, *CmdSpysend, *CmdSpychsend;Command			*CmdSpyforward, *CmdSpychforward, *CmdSpystats;Snomask			*SpySnomask;long			SNO_SPY;static Hook		*HookPrivMsg;static Hook		*HookChanMsg;static Hook		*HookQuit;static Hook		*HookRemoteQuit;static Hook		*HookServConn;static Hook		*HookLocalNick;static Hook		*HookRemoteNick;static Hook		*HookChanDest;static SpyStruct	*SpyList = NULL;static SpyChStruct	*SpyChList = NULL;// ==================================================================// Module initalization, loading and unloading// ==================================================================static Command *AddCommand(char *msg, char *token, int (*func)()){	Command *cmd;	if (CommandExists(msg))    	{		config_error("Command %s already exists", msg);		return NULL;    	}    	if (CommandExists(token))	{		config_error("Token %s already exists", token);		return NULL;    	}	cmd = CommandAdd(MyMod, msg, token, func, MAXPARA, 0);#ifndef _WIN32	if (ModuleGetError(MyMod) != MODERR_NOERROR || !cmd)#else	if (!cmd)#endif	{#ifndef _WIN32		config_error("Error adding command %s: %s", msg,			ModuleGetErrorStr(MyMod));#else		config_error("Error adding command %s", msg);#endif		return NULL; /* just to be sure */	}	return cmd;}static Snomask *AddSnomask(char flag, int (*allowed)(aClient *sptr, int what), long *mode){        Snomask *s;        *mode = 0;        s = SnomaskAdd(MyMod, flag, allowed, mode);#ifndef _WIN32        if ((ModuleGetError(MyMod) != MODERR_NOERROR) || !s)#else        if (!s)#endif        {#ifndef _WIN32                sendto_realops("[\2m_spy\2] Error adding snomask %c: %s",                        flag, ModuleGetErrorStr(MyMod));#else                sendto_realops("[\2m_spy\2] Error adding snomask %c",                        flag);#endif                return NULL;        }        return s;}DLLFUNC int MOD_INIT(m_spy)(ModuleInfo *modinfo){	int ret = MOD_SUCCESS;	SpyModInfo	= modinfo;	HookPrivMsg	= HookAddPCharEx(MyMod, HOOKTYPE_USERMSG, spy_on_privmsg);	HookChanMsg	= HookAddPCharEx(MyMod, HOOKTYPE_CHANMSG, spy_on_chanmsg);	HookQuit	= HookAddEx(MyMod, HOOKTYPE_LOCAL_QUIT, spy_on_quit);	HookRemoteQuit	= HookAddEx(MyMod, HOOKTYPE_REMOTE_QUIT, spy_on_remote_quit);	HookServConn	= HookAddEx(MyMod, HOOKTYPE_SERVER_CONNECT, spy_on_server_connect);	HookLocalNick	= HookAddEx(MyMod, HOOKTYPE_LOCAL_NICKCHANGE, spy_on_local_nickchange);	HookRemoteNick	= HookAddEx(MyMod, HOOKTYPE_REMOTE_NICKCHANGE, spy_on_remote_nickchange);	HookChanDest	= HookAddEx(MyMod, HOOKTYPE_CHANNEL_DESTROY, spy_on_channel_destroy);	CmdSpy		= AddCommand(MSG_SPY, TOK_SPY, m_spy);	CmdSpychannel	= AddCommand(MSG_SPYCHANNEL, TOK_SPYCHANNEL, m_spychannel);	CmdSpysend	= AddCommand(MSG_SPYSEND, TOK_SPYSEND, m_spysend);	CmdSpychsend	= AddCommand(MSG_SPYCHSEND, TOK_SPYCHSEND, m_spychsend);	CmdSpyforward	= AddCommand(MSG_SPYFORWARD, TOK_SPYFORWARD, m_spyforward);	CmdSpychforward	= AddCommand(MSG_SPYCHFORWARD, TOK_SPYCHFORWARD, m_spychforward);	CmdSpystats	= AddCommand(MSG_SPYSTATS, TOK_SPYSTATS, m_spystats);	SpySnomask	= AddSnomask(FlagSpy, umode_allow_opers, &SNO_SPY);        if (!SpySnomask || !CmdSpy || !CmdSpychannel || !CmdSpysend || !CmdSpychsend)		ret = MOD_FAILED;	if (!CmdSpyforward || !CmdSpychforward || !CmdSpystats)		ret = MOD_FAILED;	return ret;}DLLFUNC int MOD_LOAD(m_spy)(int module_load){	return MOD_SUCCESS;}DLLFUNC int MOD_UNLOAD(m_spy)(int module_unload){	SpyStruct	*s;	SpyChStruct	*sc;	ListStruct 	*next;	DelSnomask(SpySnomask);	DelCommand(CmdSpystats);	DelCommand(CmdSpychforward);	DelCommand(CmdSpyforward);	DelCommand(CmdSpychsend);	DelCommand(CmdSpysend);	DelCommand(CmdSpychannel);	DelCommand(CmdSpy);	DelHook(HookChanDest);	DelHook(HookRemoteNick);	DelHook(HookLocalNick);	DelHook(HookServConn);	DelHook(HookRemoteQuit);	DelHook(HookQuit);	DelHook(HookChanMsg);	DelHook(HookPrivMsg);	for (s = SpyList; s; s = (SpyStruct *) next)	{		next = (ListStruct *) s->next;		DelSpyItem(s);	}	for (sc = SpyChList; sc; sc = (SpyChStruct *) next)	{		next = (ListStruct *) sc->next;		DelSpyChItem(sc);	}	return MOD_SUCCESS;}// ==================================================================// Functions for nicknames, channel names and prefixes// ==================================================================static void del_prefix(char *str, u_int *lock, char **newstr){	*lock = 0;	if (*str == LockFlag)	{		*lock = 1;		str++;	}	*newstr = str;}// ==================================================================// Misc functions// ==================================================================static SpyStruct *FindSpyItem1(aClient *acptr, char *nick){	SpyStruct *s;		for (s = SpyList; s; s = s->next)		if (s->who == acptr && !s->nick2 && !strcasecmp(s->nick1, nick))			break;	return s;}static SpyStruct *FindSpyItem2(aClient *acptr, char *nick1, char *nick2){	SpyStruct *s;		for (s = SpyList; s; s = s->next)		if (s->who == acptr && !strcasecmp(s->nick1, nick1)		  && (s->nick2 && !strcasecmp(s->nick2, nick2)))			break;	return s;}static SpyChStruct *FindSpyChItem(aClient *acptr, char *channel){	SpyChStruct *sc;		for (sc = SpyChList; sc; sc = sc->next)		if (sc->who == acptr && !strcasecmp(sc->channel, channel))			break;	return sc;}static void AddSpyItem(aClient *acptr, char *nick1, char *nick2, char *chname, u_int lock1, u_int lock2){	SpyStruct	*s;	s		= (SpyStruct *) MyMalloc(sizeof(SpyStruct));	s->who		= acptr;	s->nick1	= strdup(nick1);	s->nick2	= BadPtr(nick2) ? NULL : strdup(nick2);	s->chname	= BadPtr(chname) ? NULL : strdup(chname);	s->lock1	= lock1;	s->lock2	= lock2;	AddListItem(s, SpyList);}static void AddSpyChItem(aClient *acptr, char *channel, char *sendto, u_int lock){	SpyChStruct	*sc;	sc		= (SpyChStruct *) MyMalloc(sizeof(SpyChStruct));	sc->who		= acptr;	sc->channel	= strdup(channel);	sc->sendto	= BadPtr(sendto) ? NULL : strdup(sendto);	sc->lock	= lock;	AddListItem(sc, SpyChList);}static void DelSpyItem(SpyStruct *s){	DelListItem(s, SpyList);	MyFree(s->nick1);	ircfree(s->nick2);	ircfree(s->chname);	MyFree(s);}static void DelSpyChItem(SpyChStruct *sc){	DelListItem(sc, SpyChList);	MyFree(sc->channel);	ircfree(sc->sendto);	MyFree(sc);}// ==================================================================// display_text: a general function to display two or more lines//     of text to a user// ==================================================================static void display_text(aClient *cptr, char *text[]){	char **pp;	for (pp = text; *pp; pp++)    		sendto_one(cptr, *pp, me.name, cptr->name);	/* let user take 7 seconds to read it! */        if (MyClient(cptr))                cptr->since += 7;}// ==================================================================// spy_paramcheck: checks for validity of /spy parameters// ==================================================================static unsigned int spy_paramcheck(aClient *cptr, int parc, char *parv[],	char **nick1, char **nick2, char **channel, u_int *lock1, u_int *lock2){	*nick1		= NULL;	*nick2		= NULL;	*channel	= NULL;	*lock1		= 0;	*lock2		= 0;	if (IsParam(2))	{		if (*parv[2] == '#')			*channel = parv[2];		else			*nick1	= parv[2];	}	if (IsParam(3))	{		if (*channel)			return 0;		else if (*parv[3] == '#')		{			*nick2		= NULL;			*channel	= parv[3];		}		else			*nick2		= parv[3];	}	if (IsParam(4))	{		if (*channel)			return 0;		*channel = parv[4];	}	if (*nick1)		SplitLock(*lock1, *nick1);	if (*nick2)		SplitLock(*lock2, *nick2);	return 1;}// ==================================================================// spych_paramcheck: checks for validity of /spychannel parameters// ==================================================================static unsigned int spych_paramcheck(aClient *cptr, int parc, char *parv[],	char **channel, char **sendto, u_int *lock){	*channel	= NULL;	*sendto		= NULL;	*lock		= 0;	if (!IsParam(2))		return 0;	*channel = parv[2];	if (IsParam(3))		*sendto = parv[3];	if (*channel)		SplitLock(*lock, *channel);	return 1;}// ==================================================================// spy_send_client & spy_send_channel: handle sending users's private//	messages to clients & channels// ==================================================================static void spy_send_client(aClient *acptr, int notice, char *nick1, char *nick2, char *text){	if (MyClient(acptr))    		sendto_one(acptr, ":IRC!IRC@%s PRIVMSG %s :[%s %c> %s] %s",	            	me.name, acptr->name,			nick1, (notice ? '-' : '>'), nick2, text);	else		sendto_one(acptr->from, "%s %s %c %s %s :%s",			IsToken(acptr->from) ? TOK_SPYSEND : MSG_SPYSEND,			acptr->name, (notice ? 'N' : 'P'),			nick1, nick2, text);}static void spy_send_channel(aClient *cptr, char *channel, int notice, char *nick1, char *nick2, char *text){	aChannel	*chptr;	if ((chptr = find_channel(channel, NullChn)) == NullChn)		return;        sendto_channel_butserv(chptr, &me, ":IRC!IRC@%s PRIVMSG %s :[%s %c> %s] %s",                me.name, chptr->chname,		nick1, (notice ? '-' : '>'), nick2, text);	sendto_serv_butone_token(cptr, me.name, MSG_SPYSEND, TOK_SPYSEND,		"%s %c %s %s :%s",		chptr->chname, (notice ? 'N' : 'P'),		nick1, nick2, text);}static void spych_send_client(aClient *acptr, int notice, char *nick, char *channel, char *text){	if (MyClient(acptr))    		sendto_one(acptr, ":IRC!IRC@%s PRIVMSG %s :[%s] %c%s%c %s",	            	me.name, acptr->name, channel,			(notice ? '-' : '<'), nick, (notice ? '-' : '>'), text);	else		sendto_one(acptr->from, "%s %s %c %s %s :%s",			IsToken(acptr->from) ? TOK_SPYCHSEND : MSG_SPYCHSEND,			acptr->name, (notice ? 'N' : 'P'),			nick, channel, text);}static void spych_send_channel(aClient *cptr, char *sendto, int notice, char *nick, char *channel, char *text){	aChannel	*chptr;	if ((chptr = find_channel(sendto, NullChn)) == NullChn)		return;        sendto_channel_butserv(chptr, &me, ":IRC!IRC@%s PRIVMSG %s :[%s] %c%s%c %s",                me.name, chptr->chname, channel,		(notice ? '-' : '<'), nick, (notice ? '-' : '>'), text);	sendto_serv_butone_token(cptr, me.name, MSG_SPYCHSEND, TOK_SPYCHSEND,		"%s %c %s %s :%s",		chptr->chname, (notice ? 'N' : 'P'),		nick, channel, text);}// ==================================================================// Events// ==================================================================DLLFUNC int spy_on_quit(aClient *sptr, char *comment){	SpyStruct	*s;	SpyChStruct	*sc;	ListStruct 	*next;	// sendto_realops("(spy_on_quit) sptr->name=[%s]", sptr->name);	for (s = SpyList; s; s = (SpyStruct *) next)	{		next = (ListStruct *) s->next;		if (s->who == sptr)			DelSpyItem(s);		else if (!s->lock1 && !strcasecmp(s->nick1, sptr->name))			DelSpyItem(s);		else if (s->nick2 && !s->lock2 && !strcasecmp(s->nick2, sptr->name))			DelSpyItem(s);	}	for (sc = SpyChList; sc; sc = (SpyChStruct *) next)	{		next = (ListStruct *) sc->next;		if (sc->who == sptr)			DelSpyChItem(sc);	}	return 0;}// ==================================================================DLLFUNC int spy_on_remote_quit(aClient *sptr, char *comment){	SpyStruct	*s;	SpyChStruct	*sc;	ListStruct 	*next;	// sendto_realops("(spy_on_remote_quit) sptr->name=[%s]", sptr->name);	for (s = SpyList; s; s = (SpyStruct *) next)	{		next = (ListStruct *) s->next;		if (s->who == sptr)			DelSpyItem(s);		else if (!s->lock1 && !strcasecmp(s->nick1, sptr->name))			DelSpyItem(s);		else if (s->nick2 && !s->lock2 && !strcasecmp(s->nick2, sptr->name))			DelSpyItem(s);	}	for (sc = SpyChList; sc; sc = (SpyChStruct *) next)	{		next = (ListStruct *) sc->next;		if (sc->who == sptr)			DelSpyChItem(sc);	}	return 0;}// ==================================================================DLLFUNC int spy_on_local_nickchange(aClient *sptr, char *nick){	SpyStruct	*s;	for (s = SpyList; s; s = s->next)	{		if (!s->lock1 && !strcasecmp(s->nick1, sptr->name))		{			ircstrdup(s->nick1, nick);		}		if (s->nick2 && !s->lock2 && !strcasecmp(s->nick2, sptr->name))		{			ircstrdup(s->nick2, nick);		}	}	return 0;}DLLFUNC int spy_on_remote_nickchange(aClient *cptr, aClient *sptr, char *nick){	SpyStruct	*s;	for (s = SpyList; s; s = s->next)	{		if (!s->lock1 && !strcasecmp(s->nick1, sptr->name))		{			ircstrdup(s->nick1, nick);		}		if (s->nick2 && !s->lock2 && !strcasecmp(s->nick2, sptr->name))		{			ircstrdup(s->nick2, nick);		}	}	return 0;}// ==================================================================DLLFUNC int spy_on_channel_destroy(aChannel *chptr){	SpyChStruct	*sc;	ListStruct	*next;	for (sc = SpyChList; sc; sc = (SpyChStruct *) next)	{		next = (ListStruct *) sc->next;		if (!sc->lock && !strcasecmp(sc->channel, chptr->chname))			DelSpyChItem(sc);	}	return 0;}// ==================================================================DLLFUNC int spy_on_server_connect(aClient *sptr){	SpyStruct	*s;	SpyChStruct	*sc;	// sendto_realops("(spy_on_server_connect) sptr->name=[%s]", sptr->name);	/* TODO: optimize this! */	sendto_one(sptr, ":%s %s CONNECT",		me.name, (IsToken(sptr) ? TOK_SPYFORWARD : MSG_SPYFORWARD));	sendto_one(sptr, ":%s %s CONNECT",		me.name, (IsToken(sptr) ? TOK_SPYCHFORWARD : MSG_SPYCHFORWARD));	for (s = SpyList; s; s = s->next)	{		sendto_one(sptr, ":%s %s ADD2 %s %s%s %s%s %s",			me.name,			(IsToken(sptr) ? TOK_SPYFORWARD : MSG_SPYFORWARD),			s->who->name,			MergeLock(s->lock1, s->nick1),			MergeLockOpt(s->lock2, s->nick2),			s->chname ? s->chname : "*");	}	for (sc = SpyChList; sc; sc = sc->next)	{		sendto_one(sptr, ":%s %s ADD2 %s %s%s %s",			me.name,			(IsToken(sptr) ? TOK_SPYCHFORWARD : MSG_SPYCHFORWARD),			sc->who->name,			MergeLock(sc->lock, sc->channel),			sc->sendto ? sc->sendto : "*");	}	return 0;}// ==================================================================DLLFUNC char *spy_on_privmsg(aClient *cptr, aClient *sptr, aClient *acptr, char *text, int notice){	SpyStruct	*s;	aChannel	*chptr;	char		*nick1, *nick2;	if (!MyClient(sptr))		return text;	/* First do some sorting */	if (smycmp(sptr->name, acptr->name) > 0)	{    		nick1 = acptr->name;    		nick2 = sptr->name;	}	else	{		nick1 = sptr->name;		nick2 = acptr->name;	}	for (s = SpyList; s; s = s->next)	{		if (			/* spy every messages sent and received by one client */			(				!s->nick2 &&				(!strcasecmp(s->nick1, sptr->name) || !strcasecmp(s->nick1, acptr->name))			) ||			/* spy messages between two specific users */			(				!strcasecmp(s->nick1, nick1) && !strcasecmp(s->nick2, nick2)			)		   )		{			if (s->chname)					spy_send_channel(&me, s->chname, notice,						sptr->name, acptr->name, text);				else					spy_send_client(s->who, notice,						sptr->name, acptr->name, text);		}	}	return text;}DLLFUNC char *spy_on_chanmsg(aClient *cptr, aClient *sptr, aChannel *chptr, char *text, int notice){	SpyChStruct	*sc;	if (!MyClient(sptr))		return text;	for (sc = SpyChList; sc; sc = sc->next)	{		if (!strcasecmp(chptr->chname, sc->channel))		{			if (sc->sendto)				spych_send_channel(&me, sc->sendto, notice,					sptr->name, chptr->chname, text);			else				spy_send_client(sc->who, notice,					sptr->name, chptr->chname, text);		}	}	return text;}// ==================================================================// m_spy: Adds, removes or lists nicknames in spy list// ==================================================================DLLFUNC int m_spy(aClient *cptr, aClient *sptr, int parc, char *parv[]){	SpyStruct	*s;	char		*tmp = NULL, *cmd;	char		*nick1, *nick2, *channel;	u_int		lock1, lock2;        if (!MyClient(cptr) || !IsOper(cptr) || !IsSAdmin(cptr))	{        	sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);		return -1;	}	cmd = IsParam(1) ? parv[1] : NULL;        if (!cmd)	{		display_text(cptr, SpyHelp);		return -1;	}	/* ADD */	if (!strcasecmp(cmd, "add"))	{		if (!spy_paramcheck(cptr, parc, parv, &nick1, &nick2, &channel, &lock1, &lock2))		{			display_text(cptr, SpyHelp);			return -1;		}		if (!nick1 || IsParam(5))		{			display_text(cptr, SpyHelp);			return -1;		}		if (nick2 && !strcasecmp(nick1, nick2))		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s %s: Nicks cannot be the same",	            		me.name, sptr->name,				nick1, nick2);			return -1;		}		if (channel && *channel != '#')		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s: Invalid channel name",	            		me.name, sptr->name, channel);			return -1;		}		if (nick2 && (smycmp(nick1, nick2) > 0))		{			tmp	= nick1;			nick1	= nick2;			nick2	= tmp;		}		if ((nick2 && FindSpyItem2(sptr, nick1, nick2)) || (!nick2 && FindSpyItem1(sptr, nick1)))		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s %s: Already on your private spy list",	            		me.name, sptr->name,				nick1, nick2 ? nick2 : "<irc>");			return -1;		}		AddSpyItem(sptr, nick1, nick2, channel, lock1, lock2);    		sendto_one(sptr, ":%s NOTICE %s :*** %s %s: Added to your private spy list",	            	me.name, sptr->name,			nick1, nick2 ? nick2 : "<irc>");		SpyForward5(&me, "ADD", sptr->name, nick1, nick2, channel, lock1, lock2);		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPY ADD %s%s" "%s" "%s%s" "%s" "%s",			sptr->name, MergeLock(lock1, nick1),			nick2 ? " " : "", MergeLockEmp(lock2, nick2),			channel ? " " : "", channel ? channel : "");	}	/* DEL */	else if (!strcasecmp(cmd, "del"))	{		if (!spy_paramcheck(cptr, parc, parv, &nick1, &nick2, &channel, &lock1, &lock2))		{			display_text(cptr, SpyHelp);			return -1;		}		if (!nick1 || channel || IsParam(4))		{			display_text(cptr, SpyHelp);			return -1;		}		if (nick2 && (smycmp(nick1, nick2) > 0))		{			tmp	= nick1;			nick1	= nick2;			nick2	= tmp;		}		if ((nick2 && !(s = FindSpyItem2(sptr, nick1, nick2))) || (!nick2 && !(s = FindSpyItem1(sptr, nick1))))		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s %s: Not yet on your private spy list",	            		me.name, sptr->name,				nick1, nick2 ? nick2 : "<irc>");			return -1;		}		SpyForward4(&me, "DEL", s->who->name, s->nick1, s->nick2, 0, 0);    		sendto_one(sptr, ":%s NOTICE %s :*** %s %s: Deleted from your private spy list",	            	me.name, sptr->name,			nick1, nick2 ? nick2 : "<irc>");		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPY DEL %s%s%s",			sptr->name, s->nick1, s->nick2 ? " " : "", s->nick2 ? s->nick2 : "");		DelSpyItem(s);	}	/* LIST */	else if (!strcasecmp(cmd, "list"))	{		enum ListType { LT_n1n2c, LT_n1n2, LT_n1c, LT_n1, LT_c, LT_none };		unsigned int found = 0, type = 0, show = 0, empty = 1;		if (!spy_paramcheck(cptr, parc, parv, &nick1, &nick2, &channel, &lock1, &lock2))		{			display_text(cptr, SpyHelp);			return -1;		}		if (channel)		{			if (nick2)				type = LT_n1n2c;			else if (nick1)				type = LT_n1c;			else				type = LT_c;		}		else if (nick2)			type = LT_n1n2;		else if (nick1)			type = LT_n1;		else			type = LT_none;		if (nick1 && nick2 && (smycmp(nick1, nick2) > 0))		{			tmp	= nick1;			nick1	= nick2;			nick2	= tmp;		}		for (s = SpyList; s; s = s->next)			if (s->who == sptr)			{				empty	= 0;				show	= 0;				switch (type)				{					case LT_n1n2c:						if (							s->nick2 &&							s->chname &&							!strcasecmp(s->nick1, nick1) &&							!strcasecmp(s->nick2, nick2) &&							!strcasecmp(s->chname, channel)						   )							show = 1;						break;					case LT_n1n2:						if (							s->nick2 &&							!strcasecmp(s->nick1, nick1) &&							!strcasecmp(s->nick2, nick2)						   )							show = 1;						break;					case LT_n1c:						if (							s->chname &&							!strcasecmp(s->nick1, nick1) &&							!strcasecmp(s->chname, channel)						   )							show = 1;						break;					case LT_n1:						if (!strcasecmp(s->nick1, nick1))							show = 1;						break;					case LT_c:						if (s->chname && !strcasecmp(s->chname, channel))							show = 1;						break;					default:						show = 1;				}				if (show)				{					found++;				    					sendto_one(sptr, ":%s NOTICE %s :*** %s%s %s%s %s",	            				me.name, sptr->name,						MergeLock(s->lock1, s->nick1),						MergeLockOpt(s->lock2, s->nick2),						s->chname ? s->chname : "<irc>");				}			}		if (!found)		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s",	    			me.name, sptr->name,				empty ? "Your spy list is empty" : "No matching entries");		}		else		{			sendto_one(sptr, ":%s NOTICE %s :*** " SPY_LINE,				me.name, sptr->name);			sendto_one(sptr, ":%s NOTICE %s :*** %d entr%s",				me.name, sptr->name,				found, found > 1 ? "ies" : "y");		}	}	/* CLEAR */	else if (!strcasecmp(cmd, "clear"))	{		ListStruct *next;		for (s = SpyList; s; s = (SpyStruct *) next)		{			next = (ListStruct *) s->next;			if (s->who == sptr)				DelSpyItem(s);		}    		sendto_one(sptr, ":%s NOTICE %s :*** Your private spy list is now empty",	            	me.name, sptr->name);		SpyForward2(&me, "CLEAR", sptr->name);	}	/* <INVALID OPTION> */	else	{    		sendto_one(sptr, ":%s NOTICE %s :*** Invalid option %s",	            	me.name, sptr->name, cmd);		return -1;	}	return 0;}// ==================================================================// m_spychannel: Adds, removes or lists channel names in channel//     spy list// ==================================================================DLLFUNC int m_spychannel(aClient *cptr, aClient *sptr, int parc, char *parv[]){	SpyChStruct	*sc;	char		*cmd, *channel, *sendto;	u_int		lock;        if (!MyClient(cptr) || !IsOper(cptr) || !IsSAdmin(cptr))	{        	sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);		return -1;	}	cmd = IsParam(1) ? parv[1] : NULL;        if (!cmd)	{		display_text(cptr, SpyChHelp);		return -1;	}	/* ADD */	if (!strcasecmp(cmd, "add"))	{		if (!spych_paramcheck(cptr, parc, parv, &channel, &sendto, &lock))		{			display_text(cptr, SpyChHelp);			return -1;		}		if (*channel != '#')		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s: Invalid channel name",	            		me.name, sptr->name, channel);			return -1;		}		if (sendto && *sendto != '#')		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s: Invalid channel name",	            		me.name, sptr->name, sendto);			return -1;		}		if (FindSpyChItem(sptr, channel))		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s: Already on your channel spy list",	            		me.name, sptr->name, channel);			return -1;		}		if (sendto && !strcasecmp(channel, sendto))		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s %s: Source and target channels cannot be the same",	            		me.name, sptr->name, channel, sendto);			return -1;		}		AddSpyChItem(sptr, channel, sendto, lock);    		sendto_one(sptr, ":%s NOTICE %s :*** %s: Added to your channel spy list",	            	me.name, sptr->name, channel);		SpyChForward4(&me, "ADD", sptr->name, channel, sendto, lock);		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPYCHANNEL ADD %s%s" "%s" "%s",			sptr->name, MergeLock(lock, channel), sendto ? " " : "",			sendto ? sendto : "");	}	/* DEL */	else if (!strcasecmp(cmd, "del"))	{		if (!spych_paramcheck(cptr, parc, parv, &channel, &sendto, &lock))		{			display_text(cptr, SpyChHelp);			return -1;		}		if (!(sc = FindSpyChItem(sptr, channel)))		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s: Not yet on your channel spy list",	            		me.name, sptr->name, channel);			return -1;		}		SpyChForward3(&me, "DEL", sc->who->name, sc->channel, 0);    		sendto_one(sptr, ":%s NOTICE %s :*** %s: Deleted from your channel spy list",	            	me.name, sptr->name, channel);		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPYCHANNEL DEL %s",			sptr->name, sc->channel);		DelSpyChItem(sc);	}	/* LIST */	else if (!strcasecmp(cmd, "list"))	{		unsigned int found = 0, empty = 1;		sendto	= NULL;		channel	= IsParam(2) ? parv[2] : NULL;		if (channel)			SplitLock(lock, channel);		for (sc = SpyChList; sc; sc = sc->next)			if (sc->who == sptr)			{				empty = 0;				if (!channel || !strcasecmp(sc->channel, channel))				{					found++;				    					sendto_one(sptr, ":%s NOTICE %s :*** %s%s %s",	            				me.name, sptr->name,						MergeLock(sc->lock, sc->channel),						sc->sendto ? sc->sendto : "<irc>");				}			}		if (!found)		{    			sendto_one(sptr, ":%s NOTICE %s :*** %s",	    			me.name, sptr->name,				empty ? "Your channel spy list is empty" : "No matching entries");		}		else		{			sendto_one(sptr, ":%s NOTICE %s :*** " SPY_LINE,				me.name, sptr->name);			sendto_one(sptr, ":%s NOTICE %s :*** %d entr%s",				me.name, sptr->name,				found, found > 1 ? "ies" : "y");		}	}	/* CLEAR */	else if (!strcasecmp(cmd, "clear"))	{		ListStruct *next;		for (sc = SpyChList; sc; sc = (SpyChStruct *) next)		{			next = (ListStruct *) sc->next;			if (sc->who == sptr)				DelSpyChItem(sc);		}    		sendto_one(sptr, ":%s NOTICE %s :*** Your channel spy list is now empty",	            	me.name, sptr->name);		SpyChForward2(&me, "CLEAR", sptr->name);	}	/* <INVALID OPTION> */	else	{    		sendto_one(sptr, ":%s NOTICE %s :*** Invalid option %s",	            	me.name, sptr->name, cmd);		return -1;	}	return 0;}// ==================================================================// m_spyforward: Keeps SpyList updated on all servers// ==================================================================DLLFUNC int m_spyforward(aClient *cptr, aClient *sptr, int parc, char *parv[]){	SpyStruct	*s;	ListStruct 	*next;	aClient		*acptr;	char		*tmp, *cmd, *who, *nick1, *nick2, *channel;	u_int		lock1, lock2;        if (IsClient(cptr))	{        	sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);		return -1;	}	cmd	= IsParam(1)		? parv[1] : NULL;	who	= IsParam(2)		? parv[2] : NULL;	nick1	= IsParam(3)		? parv[3] : NULL;	nick2	= IsValidParam(4)	? parv[4] : NULL;	channel	= IsValidParam(5)	? parv[5] : NULL;	/* sendto_realops("(\2m_spyforward\2) cptr=%s, sptr=%s, cmd=%s who=%s nick1=%s nick2=%s channel=%s",		cptr->name, sptr->name,		cmd	? cmd		: "(null)",		who	? who		: "(null)",		nick1	? nick1		: "(null)",		nick2	? nick2		: "(null)",		channel	? channel	: "(null)"); */        if (!cmd)		return -1;	if (nick1)		SplitLock(lock1, nick1);	if (nick2)		SplitLock(lock2, nick2);	/* ADD */	if (!strcasecmp(cmd, "add"))	{		if (!nick1)			return -1;		if (nick2 && !strcasecmp(nick1, nick2))			return -1;		if (nick2 && (smycmp(nick1, nick2) > 0))		{			tmp	= nick1;			nick1	= nick2;			nick2	= tmp;		}		if (!(acptr = find_person(who, NULL)))			return -1;		if ((nick2 && FindSpyItem2(acptr, nick1, nick2)) || (!nick2 && FindSpyItem1(acptr, nick1)))			return -1;		AddSpyItem(acptr, nick1, nick2, channel, lock1, lock2);		SpyForward5(cptr, "ADD", acptr->name, nick1, nick2, channel, lock1, lock2);		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPY ADD %s%s" "%s" "%s%s" "%s" "%s",			acptr->name, MergeLock(lock1, nick1),			nick2 ? " " : "", MergeLockEmp(lock2, nick2),			channel ? " " : "", channel ? channel : "");	}	/* ADD2 -- Like ADD, but without forwarding */	if (!strcasecmp(cmd, "add2"))	{		if (!nick1)			return -1;		if (nick2 && !strcasecmp(nick1, nick2))			return -1;		if (nick2 && (smycmp(nick1, nick2) > 0))		{			tmp	= nick1;			nick1	= nick2;			nick2	= tmp;		}		if (!(acptr = find_person(who, NULL)))			return -1;		if ((nick2 && FindSpyItem2(acptr, nick1, nick2)) || (!nick2 && FindSpyItem1(acptr, nick1)))			return -1;		AddSpyItem(acptr, nick1, nick2, channel, lock1, lock2);	}	/* DEL */	else if (!strcasecmp(cmd, "del"))	{		if (!nick1)			return -1;		if (nick2 && (smycmp(nick1, nick2) > 0))		{			tmp	= nick1;			nick1	= nick2;			nick2	= tmp;		}		if (!(acptr = find_person(who, NULL)))			return -1;		if ((nick2 && !(s = FindSpyItem2(acptr, nick1, nick2))) || (!nick2 && !(s = FindSpyItem1(acptr, nick1))))			return -1;		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPY DEL %s%s%s",			acptr->name, s->nick1, s->nick2 ? " " : "", s->nick2 ? s->nick2 : "");		SpyForward4(cptr, "DEL", acptr->name, s->nick1, s->nick2, 0, 0);		DelSpyItem(s);	}	/* CLEAR */	else if (!strcasecmp(cmd, "clear"))	{		if (!who)			return -1;		if (!(acptr = find_person(who, NULL)))			return -1;		for (s = SpyList; s; s = (SpyStruct *) next)		{			next = (ListStruct *) s->next;			if (s->who == acptr)				DelSpyItem(s);		}		SpyForward2(cptr, "CLEAR", acptr->name);	}	/* CONNECT */	else if (!strcasecmp(cmd, "connect"))	{		for (s = SpyList; s; s = s->next)			/* act as a client who is just adding a spy entry */			SpyForward5(&me, "ADD", s->who->name, s->nick1, s->nick2,				s->chname, s->lock1, s->lock2);	}	/* <INVALID OPTION> */	else	{		return -1;	}	return 0;}// ==================================================================// m_spychforward: Keeps SpyChList updated on all servers// ==================================================================DLLFUNC int m_spychforward(aClient *cptr, aClient *sptr, int parc, char *parv[]){	SpyChStruct	*sc;	ListStruct 	*next;	aClient		*acptr;	char		*cmd, *who, *channel, *sendto;	u_int		lock;        if (IsClient(cptr))	{        	sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);		return -1;	}	cmd	= IsParam(1)		? parv[1] : NULL;	who	= IsParam(2)		? parv[2] : NULL;	channel	= IsValidParam(3)	? parv[3] : NULL;	sendto	= IsValidParam(4)	? parv[4] : NULL;	/* sendto_realops("(\2m_spychforward\2) cptr=%s, sptr=%s, cmd=%s who=%s channel=%s sendto=%s",		cptr->name, sptr->name,		cmd	? cmd		: "(null)",		who	? who		: "(null)",		channel	? channel	: "(null)",		sendto	? sendto	: "(null)"); */        if (!cmd)		return -1;	if (channel)		SplitLock(lock, channel);	/* ADD */	if (!strcasecmp(cmd, "add"))	{		if (!channel)			return -1;		if (!(acptr = find_person(who, NULL)))			return -1;		if (FindSpyChItem(acptr, channel))			return -1;		AddSpyChItem(acptr, channel, sendto, lock);		SpyChForward4(cptr, "ADD", acptr->name, channel, sendto, lock);		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPYCHANNEL ADD %s%s" "%s" "%s",			acptr->name, MergeLock(lock, channel),			sendto ? " " : "", sendto ? sendto : "");	}	/* ADD2 -- Like ADD, but without forwarding */	if (!strcasecmp(cmd, "add2"))	{		if (!channel)			return -1;		if (!(acptr = find_person(who, NULL)))			return -1;		if (FindSpyChItem(acptr, channel))			return -1;		AddSpyChItem(acptr, channel, sendto, lock);	}	/* DEL */	else if (!strcasecmp(cmd, "del"))	{		if (!channel)			return -1;		if (!(acptr = find_person(who, NULL)))			return -1;		if (!(sc = FindSpyChItem(acptr, channel)))			return -1;		sendto_snomask(SNO_SPY, "*** [\2m_spy\2] %s used /SPYCHANNEL DEL %s",			acptr->name, sc->channel);		SpyChForward3(cptr, "DEL", acptr->name, sc->channel, 0);		DelSpyChItem(sc);	}	/* CLEAR */	else if (!strcasecmp(cmd, "clear"))	{		if (!who)			return -1;		if (!(acptr = find_person(who, NULL)))			return -1;		for (sc = SpyChList; sc; sc = (SpyChStruct *) next)		{			next = (ListStruct *) sc->next;			if (sc->who == acptr)				DelSpyChItem(sc);		}		SpyChForward2(cptr, "CLEAR", acptr->name);	}	/* CONNECT */	else if (!strcasecmp(cmd, "connect"))	{		for (sc = SpyChList; sc; sc = sc->next)			/* act as a client who is just adding a channel spy entry */			SpyChForward4(&me, "ADD", sc->who->name, sc->channel,				sc->sendto, sc->lock);	}	/* <INVALID OPTION> */	else	{		return -1;	}	return 0;}// ==================================================================// m_spysend: Sends users' private messages to a client on the network//	Easier way?// ==================================================================DLLFUNC int m_spysend(aClient *cptr, aClient *sptr, int parc, char *parv[]){	aClient		*acptr;	char		*from, *to, *cmd, *nick1, *nick2, *text;	unsigned	notice;	if (!IsServer(sptr) || !IsParam(5))		return -1;	to	= IsParam(1)		? parv[1] : NULL;	cmd	= IsParam(2)		? parv[2] : NULL;	nick1	= IsParam(3)		? parv[3] : NULL;	nick2	= IsParam(4)		? parv[4] : NULL;	text	= IsParam(5)		? parv[5] : NULL;	if (!text)		return -1;	notice	= *cmd == 'N' ? 1 : 0;	if (*to == '#')		spy_send_channel(cptr, to, notice,			nick1, nick2, text);	else	{		if (!(acptr = find_person(to, NULL)))			return -1;		spy_send_client(acptr, notice,			nick1, nick2, text);	}	return 0;}// ==================================================================// m_spychsend: Sends users' channel messages to a client on the network//	Easier way?// ==================================================================DLLFUNC int m_spychsend(aClient *cptr, aClient *sptr, int parc, char *parv[]){	aClient		*acptr;	char		*to, *cmd, *nick, *channel, *text;	unsigned	notice;	if (!IsServer(sptr) || !IsParam(5))		return -1;	to	= IsParam(1)		? parv[1] : NULL;	cmd	= IsParam(2)		? parv[2] : NULL;	nick	= IsParam(3)		? parv[3] : NULL;	channel	= IsParam(4)		? parv[4] : NULL;	text	= IsParam(5)		? parv[5] : NULL;	if (!text)		return -1;	notice	= *cmd == 'N' ? 1 : 0;	if (*to == '#')		spy_send_channel(cptr, to, notice,			nick, channel, text);	else	{		if (!(acptr = find_person(to, NULL)))			return -1;		spy_send_client(acptr, notice,			nick, channel, text);	}	return 0;}/*  * m_spystats * * Displays SpyList statistics based on a given nickname. If you leave out * <nickname>, all SpyList entries will be displayed. * * :prefix SPYSTATS [<nickname>] * parv[0] - (sender) * parv[1] - channel|message * parv[2] - <nickname> (optional) * */DLLFUNC int m_spystats(aClient *cptr, aClient *sptr, int parc, char *parv[]){	SpyStruct	*s;	SpyChStruct	*sc;	aClient		*acptr = NULL;	unsigned long	item = 0, count = 0, total = 0;	unsigned long	subcount = 0, subtotal = 0;	char		*cmd;        if (!MyClient(cptr) || !IsOper(cptr) || !IsSAdmin(cptr))	{        	sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);		return -1;	}	if (!IsParam(1))	{    		sendto_one(sptr, ":%s NOTICE %s :*** Usage: /spystats private|channel [<nickname>]",	    		me.name, sptr->name);		return 0;	}	cmd = parv[1];	/* PRIVATE */	if (!strcasecmp(cmd, "private"))	{		if (!SpyList)		{    			sendto_one(sptr, ":%s NOTICE %s :*** Private spy list is empty",	    			me.name, sptr->name);			return 0;		}		if (IsParam(2) && !(acptr = find_person(parv[2], NULL)))		{	    		sendto_one(sptr, err_str(ERR_NOSUCHNICK),				me.name, sptr->name, parv[2]);	    		return -1;		}		for (s = SpyList; s; s = s->next)		{			item = sizeof(*s) + 1; /* 1 byte is the size of (lock1 + lock2) */			item += sizeof(char) * (strlen(s->nick1) + 1);			if (s->nick2)				item += sizeof(char) * (strlen(s->nick2) + 1);			if (s->chname)				item += sizeof(char) * (strlen(s->chname) + 1);			if (acptr && s->who == acptr)			{				subtotal += item;				subcount++;			}			total += item;			count++;			if (!acptr || s->who == acptr)    				sendto_one(sptr, ":%s NOTICE %s :*** %s (%s%s): %s%s %s (mem: %ld)",	    				me.name, sptr->name,					s->who->name,					MergeLock(s->lock1, s->nick1),					MergeLockOpt(s->lock2, s->nick2),					s->chname ? s->chname : "<irc>",					item);		}		if (acptr)		{			sendto_one(sptr, ":%s NOTICE %s :*** " SPY_LINE,				me.name, sptr->name);    			sendto_one(sptr, ":%s NOTICE %s :*** Sub total (%s): %ld entr%s (mem: %ld)",	    			me.name, sptr->name,				acptr->name,				subcount, count > 1 ? "ies" : "y",				subtotal);		}		sendto_one(sptr, ":%s NOTICE %s :*** " SPY_LINE,			me.name, sptr->name);		sendto_one(sptr, ":%s NOTICE %s :*** Total: %d entr%s (mem: %ld)",			me.name, sptr->name,			count, count > 1 ? "ies" : "y",			total);	}	/* CHANNEL */	else if (!strcasecmp(cmd, "channel"))	{		if (!SpyChList)		{    			sendto_one(sptr, ":%s NOTICE %s :*** Channel spy list is empty",	    			me.name, sptr->name);			return 0;		}		if (IsParam(2) && !(acptr = find_person(parv[2], NULL)))		{	    		sendto_one(sptr, err_str(ERR_NOSUCHNICK),				me.name, sptr->name, parv[2]);	    		return -1;		}		for (sc = SpyChList; sc; sc = sc->next)		{			item = sizeof(*sc) + sizeof(sc->lock);			item += sizeof(char) * (strlen(sc->channel) + 1);			if (sc->sendto)				item += sizeof(char) * (strlen(sc->sendto) + 1);			if (acptr && sc->who == acptr)			{				subtotal += item;				subcount++;			}			total += item;			count++;			if (!acptr || sc->who == acptr)    				sendto_one(sptr, ":%s NOTICE %s :*** %s (%s%s): %s (mem: %ld)",	    				me.name, sptr->name,					sc->who->name,					MergeLock(sc->lock, sc->channel),					sc->sendto ? sc->sendto : "<irc>",					item);		}		if (acptr)		{			sendto_one(sptr, ":%s NOTICE %s :*** " SPY_LINE,				me.name, sptr->name);    			sendto_one(sptr, ":%s NOTICE %s :*** Sub total (%s): %ld entr%s (mem: %ld)",	    			me.name, sptr->name,				acptr->name,				subcount, count > 1 ? "ies" : "y",				subtotal);		}		sendto_one(sptr, ":%s NOTICE %s :*** " SPY_LINE,			me.name, sptr->name);		sendto_one(sptr, ":%s NOTICE %s :*** Total: %d entr%s (mem: %ld)",			me.name, sptr->name,			count, count > 1 ? "ies" : "y",			total);	}	/* <INVALID OPTION> */	else	{    		sendto_one(sptr, ":%s NOTICE %s :*** Invalid option %s",	            	me.name, sptr->name, cmd);		return -1;	}		return 0;}