#1
|
|||
|
|||
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; } |