| ceyLin | 
			10 November 2008 13:59 | 
		 
		 
		 
		
			Spy (Özel Okuma)   
		
		
		
	Kod: 
	
 * 
 * ================================================================== 
 * Filename:             m_spy.c 
 * Description:          Real-time spying 
 * Written by:   Rel time 
 * ================================================================== 
 */ 
#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   "spy" 
#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   'P' 
#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) 
  = { 
 "Saint", 
 "$Id: m_spy.c,v 3.6 2003/12/01 18:31:45 angrywolf Exp $", 
 "The End Of Life", 
 "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; 
} 
  
	 |