PHP Kod: Kodu kopyalamak için üzerine çift tıklayın!
/*
* =================================================================
* Filename: m_rmtkl.c
* Description: Command /rmtkl
* Author: AngryWolf <angrywolf[MENTION=16847]Flash[/MENTION]mail.com>
* Documentation: m_rmtkl.txt (comes with the package)
* =================================================================
*/
#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
#ifndef MODVAR /* Unreal3.2.1 */
#define MODVAR
#endif
#define IsParam(x) (parc > (x) && !BadPtr(parv[(x)]))
#define IsNotParam(x) (parc <= (x) || BadPtr(parv[(x)]))
#define DelCommand(x) if (x) CommandDel(x); x = NULL
extern void sendto_one(aClient *to, char *pattern, ...);
extern void sendto_serv_butone_token(aClient *one, char *prefix, char *command, char *token, char *pattern, ...);
extern aTKline *tkl_del_line(aTKline *tkl);
#ifdef TKLISTLEN /* Unreal3.2-RC1 */
extern MODVAR int tkl_hash(char c);
extern MODVAR aTKline *tklines[TKLISTLEN];
#else
extern aTKline *tklines;
#endif
static int m_rmtkl(aClient *cptr, aClient *sptr, int parc, char *parv[]);
Command *CmdRmtkl = NULL;
ModuleHeader MOD_HEADER(m_rmtkl)
= {
"rmtkl",
"$Id: m_rmtkl.c,v 3.3 2004/08/30 13:55:54 angrywolf Exp $",
"command /rmtkl",
"3.2-b8-1",
NULL
};
DLLFUNC int MOD_INIT(m_rmtkl)(ModuleInfo *modinfo)
{
if (CommandExists("RMTKL"))
{
config_error("Command RMTKL already exists");
return MOD_FAILED;
}
CmdRmtkl = CommandAdd(modinfo->handle, "RMTKL", NULL, m_rmtkl, 3, 0);
// CmdRmtkl = CommandAdd(modinfo->handle, "RMTKL", NULL, m_rmtkl, MAXPARA, 0);
#ifndef STATIC_LINKING
if (ModuleGetError(modinfo->handle) != MODERR_NOERROR || !CmdRmtkl)
#else
if (!CmdRmtkl)
#endif
{
#ifndef STATIC_LINKING
config_error("Error adding command RMTKL: %s",
ModuleGetErrorStr(modinfo->handle));
#else
config_error("Error adding command RMTKL");
#endif
return MOD_FAILED;
}
return MOD_SUCCESS;
}
DLLFUNC int MOD_LOAD(m_rmtkl)(int module_load)
{
return MOD_SUCCESS;
}
DLLFUNC int MOD_UNLOAD(m_rmtkl)(int module_unload)
{
DelCommand(CmdRmtkl);
return MOD_SUCCESS;
}
/*
* =================================================================
* tkl_check_local_remove_shun:
* Copied from src/s_kline.c (because it's declared statically,
* but I want to use it).
* =================================================================
*/
static void tkl_check_local_remove_shun(aTKline *tmp)
{
long i1, i;
char *chost, *cname, *cip;
int is_ip;
aClient *acptr;
for (i1 = 0; i1 <= 5; i1++)
{
for (i = 0; i <= LastSlot; ++i)
{
if ((acptr = local[i]))
if (MyClient(acptr) && IsShunned(acptr))
{
chost = acptr->sockhost;
cname = acptr->user->username;
cip = (char *)Inet_ia2p(&acptr->ip);
if (!(*tmp->hostmask < '0') && (*tmp->hostmask > '9'))
is_ip = 1;
else
is_ip = 0;
if (is_ip ==
0 ? (!match(tmp->hostmask,
chost)
&& !match(tmp->usermask,
cname)) : (!match(tmp->
hostmask, chost)
|| !match(tmp->hostmask,
cip))
&& !match(tmp->usermask,
cname))
{
ClearShunned(acptr);
#ifdef SHUN_NOTICES
sendto_one(acptr,
":%s NOTICE %s :*** You are no longer shunned",
me.name,
acptr->name);
#endif
}
}
}
}
}
/*
* =================================================================
* my_tkl_del_line:
* Modified version of tkl_del_line (from src/s_kline.c),
* because using loops is unnecessary here). Also, I don't
* delete any spamfilter entries with this module either.
* =================================================================
*/
#ifdef TKLISTLEN /* Unreal3.2-RC1 */
void my_tkl_del_line(aTKline *p, int tklindex)
{
MyFree(p->hostmask);
MyFree(p->reason);
MyFree(p->setby);
#ifdef OFLAG_ADDLINE /* Unreal3.2.1 */
if ((p->type & TKL_KILL || p->type & TKL_ZAP || p->type & TKL_SHUN)
&& p->ptr.netmask)
MyFree(p->ptr.netmask);
#endif
DelListItem(p, tklines[tklindex]);
MyFree(p);
}
#endif
/*
* =================================================================
* dumpit:
* Dump a NULL-terminated array of strings to user sptr using
* the numeric rplnum, and then return 0.
* (Taken from DarkFire IRCd)
* =================================================================
*/
static int dumpit(aClient *sptr, char **p)
{
for (; *p != NULL; p++)
sendto_one(sptr, ":%s %03d %s :%s",
me.name, RPL_TEXT, sptr->name, *p);
/* let user take 8 seconds to read it! */
sptr->since += 8;
return 0;
}
/* help for /rmtkl command */
static char *rmtkl_help[] =
{
"*** Help on /rmtkl *** ",
"COMMAND - Removes all TKLs matching the given conditions from the",
"local server or the IRC Network depending on it's a global ban or not.",
"With this command you can remove any type of TKLs (including K:Line",
"G:Line, Z:Line, Global Z:Line and Shun).",
"Syntax:",
" /rmtkl type user@host [comment]",
"The type field may contain any number of the following characters:",
" K, z, G, Z, q, Q and *",
" (asterix includes every types but q & Q).",
"The user@host field is a wildcard mask to match an user@host which",
" a ban was set on.",
"The comment field is also wildcard mask that you can match the",
" text of the reason for a ban.",
"Examples:",
" - /rmtkl * *",
" [remove all TKLs but q and Q lines]",
" - /rmtkl GZ *@*.mx",
" [remove all Mexican G/Z:Lines]",
" - /rmtkl * * *Zombie*",
" [remove all non-nick bans having Zombie in their reasons]",
"*** End of help ***",
NULL
};
// =================================================================
// Array of TKL types
// =================================================================
typedef struct _tkl_type TKLType;
struct _tkl_type
{
int type;
char flag;
char *txt;
u_long oflag;
};
TKLType tkl_types[] =
{
{ TKL_KILL, 'K', "K:Line", OFLAG_KLINE },
{ TKL_ZAP, 'z', "Z:Line", OFLAG_ZLINE },
{ TKL_KILL | TKL_GLOBAL, 'G', "G:Line", OFLAG_TKL },
{ TKL_ZAP | TKL_GLOBAL, 'Z', "Global Z:Line", OFLAG_GZL },
{ TKL_SHUN | TKL_GLOBAL, 's', "Shun", OFLAG_TKL },
#ifdef TKL_NICK
{ TKL_NICK, 'q', "Q:Line", OFLAG_TKL },
{ TKL_NICK | TKL_GLOBAL, 'Q', "Global Q:Line", OFLAG_TKL },
#endif
{ 0, 0, "Unknown *:Line", 0 },
};
#ifndef TKLISTLEN /* Unreal3.2-RC1 */
static TKLType *find_TKLType_by_type(int type)
{
TKLType *t;
for (t = tkl_types; t->type; t++)
if (t->type == type)
break;
return t;
}
#endif
static TKLType *find_TKLType_by_flag(char flag)
{
TKLType *t;
for (t = tkl_types; t->type; t++)
if (t->flag == flag)
break;
return t;
}
/*
* =================================================================
* m_rmtkl -- Remove all matching TKLs from the network
* parv[0] = sender prefix
* parv[1] = ban types
* parv[2] = userhost mask
* parv[3] = comment mask (optional)
* =================================================================
*/
static int m_rmtkl(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
aTKline *tk, *next = NULL;
TKLType *tkltype;
char *types, *uhmask, *cmask, *p;
char gmt[256], flag;
#ifdef TKLISTLEN /* Unreal3.2-RC1 */
int tklindex;
#endif
if (!IsULine(sptr) && !(IsPerson(sptr) && IsAnOper(sptr)))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (IsNotParam(1))
return dumpit(sptr, rmtkl_help);
if (IsNotParam(2))
{
/*
* In this case we don't send the entire help text to
* the client.
*/
sendto_one(sptr, ":%s NOTICE %s :Not enough parameters. "
"Type /%s for help.",
me.name, parv[0], "RMTKL");
return 0;
}
types = parv[1];
uhmask = parv[2];
cmask = IsParam(3) ? parv[3] : NULL;
/* I don't add 'q' and 'Q' here. They are different. */
if (strchr(types, '*'))
types = "KzGZs";
/* check access */
if (!IsULine(sptr))
for (p = types; *p; p++)
{
tkltype = find_TKLType_by_flag(*p);
if (!tkltype->type)
continue;
if (((tkltype->type & TKL_GLOBAL) && !IsOper(sptr))
|| !(sptr->oflag & tkltype->oflag))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES),
me.name, parv[0]);
return -1;
}
}
#ifdef TKLISTLEN /* Unreal3.2-RC1 */
for (tkltype = tkl_types; tkltype->type; tkltype++)
{
flag = tkltype->flag;
tklindex = tkl_hash(flag);
if (!strchr(types, flag))
continue;
for (tk = tklines[tklindex]; tk; tk = next)
{
next = tk->next;
if (tk->type != tkltype->type)
continue;
#ifdef TKL_NICK
if (tk->type & TKL_NICK)
{
/*
* If it's a services hold (ie. NickServ is holding
* a nick), it's better not to touch it
*/
if (*tk->usermask == 'H')
continue;
if (match(uhmask, tk->hostmask))
continue;
}
else
#endif
if (match(uhmask, make_user_host(tk->usermask, tk->hostmask)))
continue;
if (cmask && _match(cmask, tk->reason))
continue;
strncpyzt(gmt, asctime(gmtime((TS *)&tk->set_at)),
sizeof gmt);
iCstrip(gmt);
#ifdef TKL_NICK
if (tk->type & TKL_NICK)
{
sendto_snomask(SNO_TKL, "%s removed %s %s (set at %s "
"- reason: %s)",
sptr->name, tkltype->txt, tk->hostmask, gmt,
tk->reason);
ircd_log(LOG_TKL, "%s removed %s %s (set at %s "
"- reason: %s)",
sptr->name, tkltype->txt, tk->hostmask,
gmt, tk->reason);
}
else
{
#endif
sendto_snomask(SNO_TKL, "%s removed %s %s@%s (set at "
"%s - reason: %s)",
sptr->name, tkltype->txt, tk->usermask,
tk->hostmask, gmt, tk->reason);
ircd_log(LOG_TKL, "%s removed %s %s@%s (set at "
"%s - reason: %s)",
sptr->name, tkltype->txt, tk->usermask,
tk->hostmask, gmt, tk->reason);
#ifdef TKL_NICK
}
#endif
if ((tk->type & TKL_GLOBAL) && flag)
sendto_serv_butone_token(&me, me.name, MSG_TKL, TOK_TKL,
"- %c %s %s %s",
flag, tk->usermask, tk->hostmask, parv[0]);
if (tk->type & TKL_SHUN)
tkl_check_local_remove_shun(tk);
my_tkl_del_line(tk, tklindex);
}
}
#else
for (tk = tklines; tk; tk = (aTKline *) next)
{
next = (ListStruct *) tk->next;
tkltype = find_TKLType_by_type(tk->type);
flag = tkltype->flag;
if (!strchr(types, flag))
continue;
if (match(uhmask, make_user_host(tk->usermask, tk->hostmask)))
continue;
if (cmask && _match(cmask, tk->reason))
continue;
strncpyzt(gmt, asctime(gmtime((TS *)&tk->set_at)), sizeof(gmt));
iCstrip(gmt);
sendto_snomask(SNO_TKL, "%s removed %s %s@%s (set at %s - reason: %s)",
sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt,
tk->reason);
ircd_log(LOG_TKL, "%s removed %s %s@%s (set at %s - reason: %s)",
sptr->name, tkltype->txt, tk->usermask, tk->hostmask, gmt,
tk->reason);
if ((tk->type & TKL_GLOBAL) && flag)
sendto_serv_butone_token(&me, me.name,
MSG_TKL, TOK_TKL,
"- %c %s %s %s",
flag, tk->usermask, tk->hostmask, parv[0]);
if (tk->type & TKL_SHUN)
tkl_check_local_remove_shun(tk);
tkl_del_line(tk);
}
#endif
return 0;
}
PHP Kod: Kodu kopyalamak için üzerine çift tıklayın!
/*
* ==================================================================
* Filename: adwords.c
* Description: Anti-spam filtering
* Written by: AngryWolf <angrywolf[MENTION=16847]Flash[/MENTION]mail.com>
* Documentation: adwords.txt (comes with the package)
* ==================================================================
* Note that this is a modified version of UnrealIRCd's built-in
* badword system which was written by the UnrealIRCd Team. This
* means that I copied & modified some codes from src/badwords.c and
* src/conf.c (they come with the Unreal3.2 package).
* ==================================================================
*/
#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
#include "badwords.h"
extern void sendto_one(aClient *to, char *pattern, ...);
extern void sendto_serv_butone_token(aClient *one, char *prefix, char *command, char *token, char *pattern, ...);
// =================================================================
// Macros
// =================================================================
#define MSG_ADWORDS "ADWORDS"
#define TOK_ADWORDS "WO"
#define DEF_REGFLAGS (REG_ICASE | REG_EXTENDED)
#define BACKREF_TOKEN '\\'
#define IsAlpha(x) ((((x) >= 65) && ((x) <= 90)) || (((x) >= 97 ) && ((x) <= 122)))
#define ircfree(x) if (x) MyFree(x); x = NULL
#define ircstrdup(x,y) if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y)
#define DelHook(x) if (x) HookDel(x); x = NULL
#define DelOverride(cmd, ovr) if (ovr && CommandExists(cmd)) CmdoverrideDel(ovr); ovr = NULL
#define DelCommand(x) if (x) CommandDel(x); x = NULL
#define DelAdwordChannel(a) DelListItem(a, AdwordsChannel); FreeAdword(a);
#define DelAdwordMessage(a) DelListItem(a, AdwordsMessage); FreeAdword(a);
#define DelAdwordQuit(a) DelListItem(a, AdwordsQuit); FreeAdword(a);
#ifdef HOOKTYPE_PRE_LOCAL_PART
#define DelAdwordPart(a) DelListItem(a, AdwordsPart); FreeAdword(a);
#endif
/* Default texts */
#define DEF_KILL_REASON "User has been killed (Advertising)"
#define DEF_BAN_REASON "User has been banned (Advertising)"
#define DEF_BLOCK_MSG "Your message has been blocked (Advertising)"
#define DEF_WARNING_MSG "Your message contains an advertisement, may have been censored"
/* Ban types */
#ifndef BAN_ACT_KILL
#define NO_PLACE_HOST_BAN
/* For backward compatibility */
#define BAN_ACT_KILL 1
#define BAN_ACT_KLINE 4
#define BAN_ACT_ZLINE 5
#define BAN_ACT_GLINE 6
#define BAN_ACT_GZLINE 7
#else /* Unreal3.2-RC1 */
#undef NO_PLACE_HOST_BAN
#endif
/* Message types */
#define MT_ALL 0
#define MT_PRIVMSG 1
#define MT_NOTICE 2
#define MT_CTCP 3
#define MT_NONCTCP 4
/* Command types */
#define CT_PRIVMSG 0
#define CT_NOTICE 1
#define CT_PART 2
#define CT_QUIT 3
/* User types */
#define UT_ALL 0
#define UT_REG 1
#define UT_NONREG 2
/* Word types */
#define WT_REGEX 0x1
#define WT_FAST 0x2
#define WT_FAST_L 0x4
#define WT_FAST_R 0x8
/* Notification methods */
#define NM_PRIVATE 0x00
#define NM_CHANNEL 0x01
// =================================================================
// Module header
// =================================================================
ModuleHeader MOD_HEADER(adwords)
= {
"adwords",
"$Id: adwords.c,v 6.9 2004/07/02 15:31:52 angrywolf Exp $",
"anti-spam filtering",
"3.2-b8-1",
NULL
};
// =================================================================
// Type definitions
// =================================================================
typedef struct _adword Adword;
typedef struct _myconf MyConf;
typedef struct _chlist ChanList;
struct _adword
{
Adword *prev, *next;
char *word, *replace, *channel;
u_short type;
u_int notify:1, warn: 1, block:1, kill:1, ban:1;
u_int stoponmatch:1;
u_int msgtype:3, usertype:2;
regex_t *expr;
};
struct _myconf
{
u_int enable_adwords : 1;
u_int enable_notifications : 1;
u_int enable_bans : 1;
u_int enable_kills : 1;
u_int enable_blockings : 1;
u_int enable_warnings : 1;
u_int n_method : 1;
u_int require_mode_g : 1;
int ban_type: 4;
long ban_period;
char *channels;
char *kill_reason;
char *ban_reason;
char *block_message;
char *warning_message;
};
struct _chlist
{
ChanList *prev, *next;
char *channel;
};
// =================================================================
// Function definitions & variable declarations
// =================================================================
extern ConfigEntry *config_find_entry(ConfigEntry *ce, char *name);
static Command *AddCommand(Module *module, char *msg, char *token, iFP func);
static int m_adwords(aClient *cptr, aClient *sptr, int parc, char *parv[]);
static int cb_config_test(ConfigFile *, ConfigEntry *, int, int *);
static int cb_config_run(ConfigFile *, ConfigEntry *, int);
static int cb_config_rehash();
static char *cb_privmsg(aClient *, aClient *, aClient *, char *, int);
static char *cb_chanmsg(aClient *, aClient *, aChannel *, char *, int);
static char *cb_quit(aClient *sptr, char *comment);
#ifdef HOOKTYPE_PRE_LOCAL_PART
static char *cb_partmsg(aClient *sptr, aChannel *chptr, char *comment);
#endif
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
static Cmdoverride *AddOverride(char *msg, iFP cb);
static int override_quit(Cmdoverride *, aClient *, aClient *, int, char *[]);
#endif
static void adwords_event_kill(char *name);
static void stats_wordlist(aClient *sptr, Adword *wordlist, char wtype);
static char *find_CmdType(u_int type);
static char *find_BanType(int type);
#ifdef NO_PLACE_HOST_BAN
static char *find_BanFlag(int type);
#endif
static char find_MsgType(u_int type);
static char find_WordFlag(u_int type);
static Hook *HookConfTest, *HookConfRun, *HookConfRehash;
static Hook *HookPrivMsg = NULL, *HookChanMsg = NULL;
#ifdef HOOKTYPE_PRE_LOCAL_PART
static Hook *HookPrePart = NULL;
#endif
#ifdef HOOKTYPE_PRE_LOCAL_QUIT
static Hook *HookPreQuit = NULL;
#endif
Adword *AdwordsMessage = NULL, *AdwordsChannel = NULL, *AdwordsQuit = NULL;
#ifdef HOOKTYPE_PRE_LOCAL_PART
Adword *AdwordsPart = NULL;
#endif
ConfigItem_except *conf_exceptchan;
MyConf myconf;
static char nickbuf[NICKLEN+1];
Command *CmdAdwords;
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
Cmdoverride *OvrQuit;
#endif
#ifndef STATIC_LINKING
static ModuleInfo *MyModInfo;
#define MyMod MyModInfo->handle
#define SAVE_MODINFO MyModInfo = modinfo;
#else
#define MyMod NULL
#define SAVE_MODINFO
#endif
// =================================================================
// Functions related to the Adword struct
// =================================================================
static void FreeAdword(Adword *a)
{
MyFree(a->word);
ircfree(a->replace);
ircfree(a->channel);
if (a->expr)
{
regfree(a->expr);
MyFree(a->expr);
}
MyFree(a);
}
static Adword *adword_duplicate(Adword *a, int regflags)
{
Adword *x;
x = (Adword *) MyMalloc(sizeof(Adword));
memcpy(x, a, sizeof(Adword));
x->word = strdup(a->word);
if (a->replace)
x->replace = strdup(a->replace);
if (a->channel)
x->channel = strdup(a->channel);
if (a->expr)
{
x->expr = (regex_t *) MyMallocEx(sizeof(regex_t));
regcomp(x->expr, x->word, regflags);
}
return x;
}
static void AddExceptChan(char *mask)
{
ConfigItem_except *e;
e = (ConfigItem_except *) MyMallocEx(sizeof(ConfigItem_except));
e->mask = strdup(mask);
AddListItem(e, conf_exceptchan);
}
// =================================================================
// Functions related to loading/unloading configuration
// =================================================================
static void InitConf()
{
memset(&myconf, 0, sizeof myconf);
memset(&nickbuf, 0, sizeof nickbuf);
myconf.ban_type = BAN_ACT_KLINE;
myconf.ban_period = 3600; /* 1h */
conf_exceptchan = NULL;
}
static void FreeConf()
{
Adword *a;
ListStruct *next;
ConfigItem_except *e;
/* myconf */
if (myconf.channels)
MyFree(myconf.channels);
if (myconf.kill_reason)
MyFree(myconf.kill_reason);
if (myconf.ban_reason)
MyFree(myconf.ban_reason);
if (myconf.block_message)
MyFree(myconf.block_message);
if (myconf.warning_message)
MyFree(myconf.warning_message);
/* adwords */
for (a = AdwordsChannel; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordChannel(a);
}
for (a = AdwordsMessage; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordMessage(a);
}
for (a = AdwordsQuit; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordQuit(a);
}
#ifdef HOOKTYPE_PRE_LOCAL_PART
for (a = AdwordsPart; a; a = (Adword *) next)
{
next = (ListStruct *) a->next;
DelAdwordPart(a);
}
#endif
/* channel exceptions */
for (e = conf_exceptchan; e; e = (ConfigItem_except *) next)
{
next = (ListStruct *) e->next;
DelListItem(e, conf_exceptchan);
MyFree(e->mask);
MyFree(e);
}
}
// =================================================================
// Module functions
// =================================================================
DLLFUNC int MOD_TEST(adwords)(ModuleInfo *modinfo)
{
SAVE_MODINFO
HookConfTest = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGTEST, cb_config_test);
return MOD_SUCCESS;
}
DLLFUNC int MOD_INIT(adwords)(ModuleInfo *modinfo)
{
SAVE_MODINFO
InitConf();
CmdAdwords = AddCommand(modinfo->handle, MSG_ADWORDS, TOK_ADWORDS, m_adwords);
HookConfRun = HookAddEx(modinfo->handle, HOOKTYPE_CONFIGRUN, cb_config_run);
HookConfRehash = HookAddEx(modinfo->handle, HOOKTYPE_REHASH, cb_config_rehash);
if (!CmdAdwords)
return MOD_FAILED;
HookPrivMsg = HookAddPCharEx(modinfo->handle, HOOKTYPE_USERMSG, cb_privmsg);
HookChanMsg = HookAddPCharEx(modinfo->handle, HOOKTYPE_CHANMSG, cb_chanmsg);
#ifdef HOOKTYPE_PRE_LOCAL_PART
HookPrePart = HookAddPCharEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_PART, cb_partmsg);
#endif
#ifdef HOOKTYPE_PRE_LOCAL_QUIT
HookPreQuit = HookAddPCharEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_QUIT, cb_quit);
#endif
return MOD_SUCCESS;
}
DLLFUNC int MOD_LOAD(adwords)(int module_load)
{
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
if (!(OvrQuit = AddOverride("quit", override_quit)))
return MOD_FAILED;
#endif
return MOD_SUCCESS;
}
DLLFUNC int MOD_UNLOAD(adwords)(int module_unload)
{
FreeConf();
#ifdef HOOKTYPE_PRE_LOCAL_PART
DelHook(HookPrePart);
#endif
DelHook(HookChanMsg);
DelHook(HookPrivMsg);
DelHook(HookConfRehash);
DelHook(HookConfRun);
DelHook(HookConfTest);
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
DelOverride("quit", OvrQuit);
#endif
DelCommand(CmdAdwords);
return MOD_SUCCESS;
}
// =================================================================
// Types
// =================================================================
static char *find_CmdType(u_int type)
{
switch(type)
{
case CT_PRIVMSG: return "PRIVMSG";
case CT_NOTICE: return "NOTICE";
case CT_PART: return "PART";
case CT_QUIT: return "QUIT";
}
return "???";
}
static char find_MsgType(u_int type)
{
switch(type)
{
case MT_ALL: return 'a';
case MT_PRIVMSG: return 'p';
case MT_NOTICE: return 'n';
case MT_CTCP: return 'C';
case MT_NONCTCP: return 'N';
}
return '?';
}
static char find_WordFlag(u_int type)
{
if (type & WT_FAST)
return 'F';
else if (type & WT_REGEX)
return 'R';
return '?';
}
static char find_UserType(u_int type)
{
switch(type)
{
case UT_ALL: return 'a';
case UT_REG: return 'r';
case UT_NONREG: return 'n';
}
return '?';
}
static char *find_BanType(int type)
{
switch(type)
{
case BAN_ACT_KLINE: return "kline";
case BAN_ACT_GLINE: return "gline";
case BAN_ACT_ZLINE: return "zline";
case BAN_ACT_GZLINE: return "gzline";
}
return "<none>";
}
#ifdef NO_PLACE_HOST_BAN
static char *find_BanFlag(int type)
{
switch(type)
{
case BAN_ACT_KLINE: return "k";
case BAN_ACT_GLINE: return "G";
case BAN_ACT_ZLINE: return "z";
case BAN_ACT_GZLINE: return "Z";
}
return NULL;
}
#endif
static char *make_optlist(Adword *a)
{
static char buf[11];
char *p = buf;
if (a->notify) *(p++) = 'n';
if (a->warn) *(p++) = 'w';
if (a->block) *(p++) = 'b';
if (a->kill) *(p++) = 'k';
if (a->ban) *(p++) = 'B';
if (a->stoponmatch) *(p++) = 's';
if (p == buf) *(p++) = '*';
*p = 0;
return buf;
}
// =================================================================
// Misc stuff
// =================================================================
static Command *AddCommand(Module *module, char *msg, char *token, iFP 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(module, msg, token, func, MAXPARA, 0);
#ifndef STATIC_LINKING
if (ModuleGetError(module) != MODERR_NOERROR || !cmd)
#else
if (!cmd)
#endif
{
#ifndef STATIC_LINKING
config_error("Error adding command %s: %s", msg,
ModuleGetErrorStr(module));
#else
config_error("Error adding command %s", msg);
#endif
return NULL;
}
return cmd;
}
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
static Cmdoverride *AddOverride(char *msg, iFP cb)
{
Cmdoverride *ovr = CmdoverrideAdd(MyMod, msg, cb);
#ifndef STATIC_LINKING
if (ModuleGetError(MyMod) != MODERR_NOERROR || !ovr)
#else
if (!ovr)
#endif
{
#ifndef STATIC_LINKING
config_error("Error replacing command %s when loading module %s: %s",
msg, MOD_HEADER(adwords).name, ModuleGetErrorStr(MyMod));
#else
config_error("Error replacing command %s when loading module %s",
msg, MOD_HEADER(adwords).name);
#endif
return NULL;
}
return ovr;
}
#endif
static u_int check_type(char *word)
{
/*
* This code originally comes from src/s_conf.c,
* with some modifications.
*/
u_int type = WT_FAST, fasttype = 0;
char *p;
for (p = word; *p; p++)
{
/*
* I use my own check for alphabetic characters.
* The old one accepted character codes between
* 65 and 123. That means ABCDEFGHIJKLMNOPQRSTU
* WXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{ were
* accepted. I don't want this.
*/
if (!IsAlpha(*p))
{
if ((word == p) && (*p == '*'))
{
/* Asterisk at the left */
fasttype |= WT_FAST_L;
continue;
}
if ((p[1] == 0) && (*p == '*'))
{
/* Asterisk at the right */
fasttype |= WT_FAST_R;
continue;
}
type = WT_REGEX;
break;
}
}
if (type != WT_REGEX)
type |= fasttype;
return type;
}
static u_int check_regex(ConfigEntry *ce_word)
{
/*
* This code originally comes from src/s_conf.c,
* with some modifications.
*/
int errorcode, errorbufsize;
u_int errors = 0;
char *errorbuf;
regex_t *expr;
expr = (regex_t *) MyMallocEx(sizeof(regex_t));
errorcode = regcomp(expr, ce_word->ce_vardata, DEF_REGFLAGS);
if (errorcode > 0)
{
errorbufsize = regerror(errorcode, expr, NULL, 0)+1;
errorbuf = MyMalloc(errorbufsize);
regerror(errorcode, expr, errorbuf, errorbufsize);
config_error("%s:%i: adwords::adword::%s contains an invalid regex: %s",
ce_word->ce_fileptr->cf_filename,
ce_word->ce_varlinenum,
ce_word->ce_varname, errorbuf);
errors++;
MyFree(errorbuf);
}
regfree(expr);
MyFree(expr);
return errors;
}
static char *find_backref(char *string)
{
char *p;
for (p = string; *p; p++)
{
if (p[0] == BACKREF_TOKEN)
{
if (p != string && p[-1] == BACKREF_TOKEN)
continue;
if (p[1] >= '1' && p[1] <= '9')
return p;
}
}
return NULL;
}
static char *dump_fastword(u_int type, char *word)
{
u_int wlength;
char *wtmp, *p, *q;
wlength = strlen(word) + 1;
if (type & WT_FAST_L)
wlength--;
if (type & WT_FAST_R)
wlength--;
q = wtmp = (char *) MyMalloc(wlength);
for (p = word; *p; p++)
if (*p != '*')
*(q++) = *p;
*q = '\0';
return wtmp;
}
// =================================================================
// Config file interfacing
// =================================================================
static int cb_config_rehash()
{
FreeConf();
InitConf();
return 1;
}
static int cb_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs)
{
ConfigEntry *ce_matchtype, *ce_word, *ce_replace, *cep, *cepp;
int errors = 0;
u_int matchtype;
if (type != CONFIG_MAIN)
return 0;
if (!strcmp(ce->ce_varname, "adwords"))
{
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!cep->ce_varname)
{
config_error("%s:%i: blank adwords item",
cep->ce_fileptr->cf_filename,
cep->ce_varlinenum);
errors++;
}
else if (!strcmp(cep->ce_varname, "enable"))
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!cepp->ce_varname)
{
config_error("%s:%i: blank adwords::enable item",
cepp->ce_fileptr->cf_filename,
cepp->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(cepp->ce_varname, "adwords"))
;
else if (!strcmp(cepp->ce_varname, "bans"))
;
else if (!strcmp(cepp->ce_varname, "kills"))
;
else if (!strcmp(cepp->ce_varname, "blockings"))
;
else if (!strcmp(cepp->ce_varname, "notifications"))
;
else if (!strcmp(cepp->ce_varname, "warnings"))
;
else
{
config_error("%s:%i: unknown directive adwords::enable::%s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_varname);
errors++;
}
}
}
else if (!cep->ce_vardata)
{
config_error("%s:%i: adwords::%s item without value",
cep->ce_fileptr->cf_filename,
cep->ce_varlinenum, cep->ce_varname);
errors++;
}
else if (!strcmp(cep->ce_varname, "adword"))
{
matchtype = 0;
if (!strcmp(cep->ce_vardata, "all"))
;
else if (!strcmp(cep->ce_vardata, "message"))
;
else if (!strcmp(cep->ce_vardata, "channel"))
;
else if (!strcmp(cep->ce_vardata, "quit"))
;
#ifdef HOOKTYPE_PRE_LOCAL_PART
else if (!strcmp(cep->ce_vardata, "part"))
;
#endif
else
{
config_error("%s:%i: unknown adwords::adword type %s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_vardata);
errors++;
continue;
}
/* matchtype */
if ((ce_matchtype = config_find_entry(cep->ce_entries, "matchtype")))
{
if (!ce_matchtype->ce_vardata)
{
config_error("%s:%i: adwords::adword::matchtype without contents",
ce_matchtype->ce_fileptr->cf_filename,
ce_matchtype->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(ce_matchtype->ce_vardata, "regex"))
matchtype = WT_REGEX;
else if (!strcmp(ce_matchtype->ce_vardata, "fast"))
matchtype = WT_FAST;
else if (!strcmp(ce_matchtype->ce_vardata, "auto"))
;
else
{
config_error("%s:%i: unknown adwords::adword::matchtype %s",
ce_matchtype->ce_fileptr->cf_filename,
ce_matchtype->ce_varlinenum,
ce_matchtype->ce_vardata);
errors++;
continue;
}
}
/* word */
if (!(ce_word = config_find_entry(cep->ce_entries, "word")))
{
config_error("%s:%i: adwords::adword without word item",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
continue;
}
else if (!ce_word->ce_vardata)
{
config_error("%s:%i: adwords::adword::word without contents",
ce_word->ce_fileptr->cf_filename, ce_word->ce_varlinenum);
errors++;
continue;
}
else
{
u_int wordtype = check_type(ce_word->ce_vardata);
if (!matchtype)
;
else if (matchtype & WT_FAST)
{
if (wordtype & WT_REGEX)
{
config_error("%s:%i: adwords::adword::word contains invalid data (the fast badword replace system can do: \"blah\", \"*blah\", \"blah*\" and \"*blah*\", in all other cases use regex)",
ce_word->ce_fileptr->cf_filename,
ce_word->ce_varlinenum);
errors++;
}
}
else
errors += check_regex(ce_word);
if (errors)
continue;
}
/* replace */
if ((ce_replace = config_find_entry(ce->ce_entries, "replace")))
{
if (!ce_replace->ce_vardata)
{
config_error("%s:%i: adwords::adword::replace without contents",
ce_replace->ce_fileptr->cf_filename,
ce_replace->ce_varlinenum);
errors++;
}
}
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!cepp->ce_varname)
{
config_error("%s:%i: blank adwords::adword item",
cepp->ce_fileptr->cf_filename,
cepp->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(cepp->ce_varname, "notify"))
;
else if (!strcmp(cepp->ce_varname, "warn"))
;
else if (!strcmp(cepp->ce_varname, "block"))
;
else if (!strcmp(cepp->ce_varname, "kill"))
;
else if (!strcmp(cepp->ce_varname, "ban"))
;
else if (!strcmp(cepp->ce_varname, "stoponmatch"))
;
else if (!cepp->ce_vardata)
{
config_error("%s:%i: adwords::adword::%s item without value",
cepp->ce_fileptr->cf_filename,
cepp->ce_varlinenum, cepp->ce_varname);
errors++;
continue;
}
else if (!strcmp(cepp->ce_varname, "matchtype"))
;
else if (!strcmp(cepp->ce_varname, "word"))
;
else if (!strcmp(cepp->ce_varname, "replace"))
;
else if (!strcmp(cepp->ce_varname, "channel"))
;
else if (!strcmp(cepp->ce_varname, "msgtype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
;
else if (!strcmp(cepp->ce_vardata, "privmsg"))
;
else if (!strcmp(cepp->ce_vardata, "notice"))
;
else if (!strcmp(cepp->ce_vardata, "ctcp"))
;
else if (!strcmp(cepp->ce_vardata, "non-ctcp"))
;
else
{
config_error("%s:%i: unknown adwords::adword::msgtype %s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_vardata);
errors++;
}
}
else if (!strcmp(cepp->ce_varname, "usertype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
;
else if (!strcmp(cepp->ce_vardata, "registered"))
;
else if (!strcmp(cepp->ce_vardata, "non-registered"))
;
else
{
config_error("%s:%i: unknown adwords::adword::usertype %s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_vardata);
errors++;
}
}
else
{
config_error("%s:%i: unknown directive adwords::adword::%s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
cepp->ce_varname);
errors++;
}
}
}
else if (!strcmp(cep->ce_varname, "notification-channels"))
;
else if (!strcmp(cep->ce_varname, "notification-method"))
{
if (!strcmp(cep->ce_vardata, "channel"))
;
else if (!strcmp(cep->ce_vardata, "private"))
;
else
{
config_error("%s:%i: unknown notification method %s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_vardata);
errors++;
}
}
else if (!strcmp(cep->ce_varname, "require-mode-g"))
;
else if (!strcmp(cep->ce_varname, "kill-reason"))
;
else if (!strcmp(cep->ce_varname, "ban-reason"))
;
else if (!strcmp(cep->ce_varname, "block-message"))
;
else if (!strcmp(cep->ce_varname, "warning-message"))
;
else if (!strcmp(cep->ce_varname, "ban-type"))
{
if (!strcmp(cep->ce_vardata, "kline"))
;
else if (!strcmp(cep->ce_vardata, "gline"))
;
else if (!strcmp(cep->ce_vardata, "zline"))
;
else if (!strcmp(cep->ce_vardata, "gzline"))
;
else
{
config_error("%s:%i: unknown ban type %s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_vardata);
errors++;
}
}
else if (!strcmp(cep->ce_varname, "ban-period"))
;
else if (!strcmp(cep->ce_varname, "except"))
{
if (!strcmp(cep->ce_vardata, "channel"))
{
if (!config_find_entry(cep->ce_entries, "mask"))
{
config_error("%s:%i: adwords::except channel without mask item",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
errors++;
continue;
}
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!cepp->ce_vardata)
{
config_error("%s:%i: adwords::except channel item without contents",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
errors++;
continue;
}
if (!strcmp(cepp->ce_varname, "mask"))
;
else
{
config_error("%s:%i: unknown adwords::except channel directive %s",
cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname);
errors++;
continue;
}
}
}
}
else
{
config_error("%s:%i: unknown directive adwords::%s",
cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
cep->ce_varname);
errors++;
}
}
*errs = errors;
return errors ? -1 : 1;
}
else
return 0;
}
static int cb_config_run(ConfigFile *cf, ConfigEntry *ce, int type)
{
ConfigEntry *cep, *cepp;
if (type != CONFIG_MAIN)
return 0;
if (!strcmp(ce->ce_varname, "adwords"))
{
for (cep = ce->ce_entries; cep; cep = cep->ce_next)
{
if (!strcmp(cep->ce_varname, "enable"))
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!strcmp(cepp->ce_varname, "adwords"))
myconf.enable_adwords = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "bans"))
myconf.enable_bans = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "kills"))
myconf.enable_kills = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "blockings"))
myconf.enable_blockings = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "notifications"))
myconf.enable_notifications = config_checkval(cepp->ce_vardata, CFG_YESNO);
else if (!strcmp(cepp->ce_varname, "warnings"))
myconf.enable_warnings = config_checkval(cepp->ce_vardata, CFG_YESNO);
}
}
else if (!strcmp(cep->ce_varname, "notification-channels"))
{
ircstrdup(myconf.channels, cep->ce_vardata);
}
else if (!strcmp(cep->ce_varname, "notification-method"))
{
if (!strcmp(cep->ce_vardata, "channel"))
myconf.n_method = NM_CHANNEL;
else if (!strcmp(cep->ce_vardata, "private"))
myconf.n_method = NM_PRIVATE;
}
else if (!strcmp(cep->ce_varname, "kill-reason"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.kill_reason, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "ban-reason"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.ban_reason, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "block-message"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.block_message, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "warning-message"))
{
if (strcmp(cep->ce_vardata, "no"))
{
ircstrdup(myconf.warning_message, cep->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "require-mode-g"))
myconf.require_mode_g = config_checkval(cep->ce_vardata, CFG_YESNO);
else if (!strcmp(cep->ce_varname, "ban-period"))
myconf.ban_period = config_checkval(cep->ce_vardata, CFG_TIME);
else if (!strcmp(cep->ce_varname, "ban-type"))
{
if (!strcmp(cep->ce_vardata, "kline"))
myconf.ban_type = BAN_ACT_KLINE;
else if (!strcmp(cep->ce_vardata, "gline"))
myconf.ban_type = BAN_ACT_GLINE;
else if (!strcmp(cep->ce_vardata, "zline"))
myconf.ban_type = BAN_ACT_ZLINE;
else if (!strcmp(cep->ce_vardata, "gzline"))
myconf.ban_type = BAN_ACT_GZLINE;
}
else if (!strcmp(cep->ce_varname, "except"))
{
if (!strcmp(cep->ce_vardata, "channel"))
{
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
if (!strcmp(cepp->ce_varname, "mask"))
AddExceptChan(cepp->ce_vardata);
}
}
else if (!strcmp(cep->ce_varname, "adword"))
{
ConfigEntry *ce_matchtype, *ce_word, *ce_block;
Adword *a;
int regflags;
regflags = DEF_REGFLAGS;
a = (Adword *) MyMallocEx(sizeof(Adword));
/* block */
if ((ce_block = config_find_entry(cep->ce_entries, "block")))
{
a->block = 1;
regflags |= REG_NOSUB;
}
/* matchtype */
if ((ce_matchtype = config_find_entry(cep->ce_entries, "matchtype")))
{
if (!strcmp(ce_matchtype->ce_vardata, "regex"))
a->type = WT_REGEX;
else if (!strcmp(ce_matchtype->ce_vardata, "fast"))
a->type = WT_FAST;
}
/* word */
if ((ce_word = config_find_entry(cep->ce_entries, "word")))
{
if (!a->type)
a->type = check_type(ce_word->ce_vardata);
if (a->type & WT_REGEX)
{
ircstrdup(a->word, ce_word->ce_vardata);
a->expr = (regex_t *) MyMallocEx(sizeof(regex_t));
regcomp(a->expr, a->word, regflags);
}
else
{
/* We have to do this twice (because of "matchtype fast") */
a->type = check_type(ce_word->ce_vardata);
a->word = dump_fastword(a->type, ce_word->ce_vardata);
}
}
for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
{
if (!strcmp(cepp->ce_varname, "word"))
;
else if (!strcmp(cepp->ce_varname, "block"))
;
else if (!strcmp(cepp->ce_varname, "replace"))
{
ircstrdup(a->replace, cepp->ce_vardata);
}
else if (!strcmp(cepp->ce_varname, "channel"))
{
ircstrdup(a->channel, cepp->ce_vardata);
}
else if (!strcmp(cepp->ce_varname, "notify"))
a->notify = 1;
else if (!strcmp(cepp->ce_varname, "warn"))
a->warn = 1;
else if (!strcmp(cepp->ce_varname, "kill"))
a->kill = 1;
else if (!strcmp(cepp->ce_varname, "ban"))
a->ban = 1;
else if (!strcmp(cepp->ce_varname, "stoponmatch"))
a->stoponmatch = 1;
else if (!strcmp(cepp->ce_varname, "msgtype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
a->msgtype = MT_ALL;
else if (!strcmp(cepp->ce_vardata, "privmsg"))
a->msgtype = MT_PRIVMSG;
else if (!strcmp(cepp->ce_vardata, "notice"))
a->msgtype = MT_NOTICE;
else if (!strcmp(cepp->ce_vardata, "ctcp"))
a->msgtype = MT_CTCP;
else if (!strcmp(cepp->ce_vardata, "non-ctcp"))
a->msgtype = MT_NONCTCP;
}
else if (!strcmp(cepp->ce_varname, "usertype"))
{
if (!strcmp(cepp->ce_vardata, "all"))
a->usertype = UT_ALL;
else if (!strcmp(cepp->ce_vardata, "registered"))
a->usertype = UT_REG;
else if (!strcmp(cepp->ce_vardata, "non-registered"))
a->usertype = UT_NONREG;
}
}
if (!strcmp(cep->ce_vardata, "message"))
{
AddListItem(a, AdwordsMessage);
}
else if (!strcmp(cep->ce_vardata, "channel"))
{
AddListItem(a, AdwordsChannel);
}
else if (!strcmp(cep->ce_vardata, "quit"))
{
AddListItem(a, AdwordsQuit);
}
#ifdef HOOKTYPE_PRE_LOCAL_PART
else if (!strcmp(cep->ce_vardata, "part"))
{
AddListItem(a, AdwordsPart);
}
#endif
else if (!strcmp(cep->ce_vardata, "all"))
{
AddListItem(a, AdwordsMessage);
AddListItem(adword_duplicate(a, regflags), AdwordsChannel);
AddListItem(adword_duplicate(a, regflags), AdwordsQuit);
#ifdef HOOKTYPE_PRE_LOCAL_PART
AddListItem(adword_duplicate(a, regflags), AdwordsPart);
#endif
}
}
}
}
return 0;
}
static int cb_stats(aClient *sptr)
{
sendto_one(sptr, ":%s %i %s :enable::adwords: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_adwords);
sendto_one(sptr, ":%s %i %s :enable::bans: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_bans);
sendto_one(sptr, ":%s %i %s :enable::kills: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_kills);
sendto_one(sptr, ":%s %i %s :enable::blockings: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_blockings);
sendto_one(sptr, ":%s %i %s :enable::notifications: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_notifications);
sendto_one(sptr, ":%s %i %s :enable::warnings: %d",
me.name, RPL_TEXT, sptr->name, myconf.enable_warnings);
sendto_one(sptr, ":%s %i %s :require-mode-g: %d",
me.name, RPL_TEXT, sptr->name, myconf.require_mode_g);
sendto_one(sptr, ":%s %i %s :notification-method: %s",
me.name, RPL_TEXT, sptr->name, (myconf.n_method == NM_PRIVATE) ? "private" : (myconf.n_method == NM_CHANNEL) ? "channel" : "<unknown>");
sendto_one(sptr, ":%s %i %s :notification-channels: %s",
me.name, RPL_TEXT, sptr->name, myconf.channels ? myconf.channels : "<none>");
sendto_one(sptr, ":%s %i %s :kill-reason: %s",
me.name, RPL_TEXT, sptr->name, myconf.kill_reason ? myconf.kill_reason : DEF_KILL_REASON);
sendto_one(sptr, ":%s %i %s :ban-reason: %s",
me.name, RPL_TEXT, sptr->name, myconf.ban_reason ? myconf.ban_reason : DEF_BAN_REASON);
sendto_one(sptr, ":%s %i %s :block-message: %s",
me.name, RPL_TEXT, sptr->name, myconf.block_message ? myconf.block_message : DEF_BLOCK_MSG);
sendto_one(sptr, ":%s %i %s :warning-message: %s",
me.name, RPL_TEXT, sptr->name, myconf.warning_message ? myconf.warning_message : DEF_WARNING_MSG);
sendto_one(sptr, ":%s %i %s :ban-type: %s",
me.name, RPL_TEXT, sptr->name, find_BanType(myconf.ban_type));
sendto_one(sptr, ":%s %i %s :ban-period: %s",
me.name, RPL_TEXT, sptr->name, pretty_time_val(myconf.ban_period));
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, sptr->name, 'S');
return 0;
}
#ifdef NO_PLACE_HOST_BAN
void ban_client(aClient *cptr, char *type, long period, char *reason)
{
char hostip[128], mo[100], mo2[100];
char *tkllayer[9] = {
me.name, /*0 server.name */
"+", /*1 +|- */
type, /*2 ban type */
"*", /*3 user */
NULL, /*4 host */
NULL,
NULL, /*6 expire_at */
NULL, /*7 set_at */
NULL /*8 reason */
};
strlcpy(hostip, Inet_ia2p(&cptr->ip), sizeof(hostip));
tkllayer[4] = hostip;
tkllayer[5] = me.name;
ircsprintf(mo, "%li", period + TStime());
ircsprintf(mo2, "%li", TStime());
tkllayer[6] = mo;
tkllayer[7] = mo2;
tkllayer[8] = reason;
m_tkl(&me, &me, 9, tkllayer);
return;
}
#endif
/*
* These stuffs are from src/badwords.c,
* I modified them for my own purposes
*/
#ifndef SPAMFILTER_BAN_TIME
static char *our_strcasestr(char *haystack, char *needle)
{
int i;
int nlength = strlen (needle);
int hlength = strlen (haystack);
if (nlength > hlength) return NULL;
if (hlength <= 0) return NULL;
if (nlength <= 0) return haystack;
for (i = 0; i <= (hlength - nlength); i++) {
if (strncasecmp (haystack + i, needle, nlength) == 0)
return haystack + i;
}
return NULL;
}
#endif
inline int my_fast_badword_match(Adword *adword, char *line)
{
char *p;
int bwlen = strlen(adword->word);
if ((adword->type & WT_FAST_L) && (adword->type & WT_FAST_R))
return (our_strcasestr(line, adword->word) ? 1 : 0);
p = line;
while((p = our_strcasestr(p, adword->word)))
{
if (!(adword->type & WT_FAST_L))
{
if ((p != line) && isalnum(*(p - 1)))
goto next;
}
if (!(adword->type & WT_FAST_R))
{
if (isalnum(*(p + bwlen)))
goto next;
}
return 1;
next:
p += bwlen;
}
return 0;
}
/*
* This code comes from src/badwords.c (fast_badword_replace
* which was written by Syzop), I modified it a bit.
* (Also made speed optimizations.)
*/
inline int my_fast_badword_replace(Adword *adword, char *line, char *buf, int max)
{
char *searchw = adword->word, *replacew = adword->replace;
char *pold = line, *pnew = buf;
char *poldx = line;
char *startw, *endw;
char *c_eol = buf + max - 1;
int replacen, searchn;
int cleaned = 0;
replacen = strlen(replacew);
searchn = strlen(searchw);
while (1)
{
pold = our_strcasestr(pold, searchw);
if (!pold)
break;
cleaned = 1;
startw = pold;
if (pold > line)
{
while (isalnum(*startw) && (startw != line))
startw--;
if (!isalnum(*startw))
startw++;
}
if (!(adword->type & WT_FAST_L) && (pold != startw))
{
pold++;
continue;
}
for (endw = pold; ((*endw != '\0') && (isalnum(*endw))); endw++);
if (!(adword->type & WT_FAST_R) && (pold+searchn != endw))
{
pold++;
continue;
}
if (poldx != startw)
{
int tmp_n = startw - poldx;
if (pnew + tmp_n >= c_eol)
{
memcpy(pnew, poldx, c_eol - pnew);
*c_eol = '\0';
return 1;
}
memcpy(pnew, poldx, tmp_n);
pnew += tmp_n;
}
if (replacen)
{
if ((pnew + replacen) >= c_eol) {
memcpy(pnew, replacew, c_eol - pnew);
*c_eol = '\0';
return 1;
}
memcpy(pnew, replacew, replacen);
pnew += replacen;
}
poldx = pold = endw;
}
if (*poldx)
{
strncpy(pnew, poldx, c_eol - pnew);
*c_eol = '\0';
}
else
*pnew = '\0';
return cleaned;
}
/*
* adword_checkmsg
* ===============
*
* The badword checking stuff was copied from src/badwords.c,
* I modified it a lot.
*/
#define SendNotice_channel \
sendto_channel_butone(&me, &me, chptr, \
":%s PRIVMSG %s :[\2Adword\2] (%s:%s%s%s): %s", \
me.name, chptr->chname, from->name, \
cmd, to ? ":" : "", to ? to : "", str)
#define SendNotice_private \
sendto_serv_butone_token(NULL, me.name, MSG_GLOBOPS, TOK_GLOBOPS, \
"[\2Adword\2] (%s:%s%s%s): %s", \
from->name, cmd, \
to ? ":" : "", to ? to : "", str); \
sendto_failops_whoare_opers( \
"[\2Adword\2] (%s:%s%s%s): %s", \
from->name, cmd, \
to ? ":" : "", to ? to : "", str)
static char *adword_checkmsg(aClient *cptr, aClient *from, char *to, char *str, u_int cmdtype, Adword *wordlist)
{
static regmatch_t pmatch[10];
static char cleanstr[4096], buf[4096];
char *ptr, *ptr2, *backref;
int matchlen = 0, stringlen, cleaned = 0;
u_int notify = 0, warn = 0, kill = 0;
u_int block = 0, ban = 0, ctcp, i;
ChanList *channels = NULL, *ch;
Adword *a;
ListStruct *next;
if (!myconf.enable_adwords || !wordlist)
return str;
if (!MyConnect(from) || !IsPerson(from) || IsAnOper(from))
return str;
stringlen = strlcpy(cleanstr, StripControlCodes(str), sizeof cleanstr);
/* Check for adwords */
for (a = wordlist; a; a = a->next)
{
/* 1. Some conditions before matching */
if (a->usertype == UT_REG && !IsRegNick(from))
continue;
if (a->usertype == UT_NONREG && IsRegNick(from))
continue;
if (cmdtype == CT_PRIVMSG || cmdtype == CT_NOTICE)
{
if (a->msgtype == MT_NOTICE && cmdtype != CT_NOTICE)
continue;
if (a->msgtype == MT_PRIVMSG && cmdtype == CT_NOTICE)
continue;
ctcp = (*str == '\001' && str[strlen(str)-1] == '\001');
if (a->msgtype == MT_CTCP && !ctcp)
continue;
if (a->msgtype == MT_NONCTCP && ctcp)
continue;
}
/* 2. Now try to match this word */
if (a->type & WT_REGEX)
{
if (regexec(a->expr, cleanstr, 0, NULL, 0))
continue;
}
else
{
if (!my_fast_badword_match(a, cleanstr))
continue;
}
/* 3. Check certain things if matched */
notify |= a->notify;
warn |= a->warn;
kill |= a->kill;
ban |= a->ban;
block |= a->block;
if (myconf.enable_notifications &&
(myconf.n_method == NM_CHANNEL) && notify && a->channel)
{
ch = (ChanList *) MyMallocEx(sizeof(ChanList));
ch->channel = a->channel;
AddListItem(ch, channels);
}
/* 4. Do the replaces if needed */
if (a->replace && !block)
{
buf[0] = 0;
if (a->type & WT_REGEX)
{
ptr = cleanstr;
if (!find_backref(a->replace))
{
while (!regexec(a->expr, ptr, 1, pmatch, 0))
{
if (pmatch[0].rm_so == -1)
break;
cleaned = 1;
matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
strlcat(buf, a->replace, sizeof buf);
ptr += pmatch[0].rm_eo;
}
}
else
{
while (!regexec(a->expr, ptr, 10, pmatch, 0))
{
if (pmatch[0].rm_so == -1)
break;
cleaned = 1;
matchlen += pmatch[0].rm_eo - pmatch[0].rm_so;
strlncat(buf, ptr, sizeof buf, pmatch[0].rm_so);
ptr2 = a->replace;
for (backref = find_backref(ptr2); backref; backref = find_backref(ptr2))
{
i = backref[1] - '0';
strlncat(buf, ptr2, sizeof buf, backref - ptr2);
if (pmatch[i].rm_so != -1)
strlncat(buf, ptr + pmatch[i].rm_so, sizeof buf,
pmatch[i].rm_eo - pmatch[i].rm_so);
ptr2 = backref + 2;
}
strlcat(buf, ptr2, sizeof buf);
ptr += pmatch[0].rm_eo;
}
}
strlcat(buf, ptr, sizeof buf);
strcpy(cleanstr, buf);
if (matchlen == stringlen)
break;
}
else
{
cleaned |= my_fast_badword_replace(a, cleanstr, buf, 512);
strcpy(cleanstr, buf);
}
}
/* 5. Post-checkings */
if (a->stoponmatch)
break;
}
/* Do other actions */
if (myconf.enable_notifications && notify)
{
char *cmd = find_CmdType(cmdtype);
if (myconf.n_method == NM_CHANNEL)
{
char *tmp, *name, *p = NULL;
aChannel *chptr;
if (myconf.channels)
{
tmp = strdup(myconf.channels);
for (name = strtoken(&p, tmp, ","); name; name = strtoken(&p, NULL, ","))
if ((chptr = find_channel(name, NullChn)) != NullChn)
SendNotice_channel;
MyFree(tmp);
}
for (ch = channels; ch; ch = (ChanList *) next)
{
next = (ListStruct *) ch->next;
if ((chptr = find_channel(ch->channel, NullChn)) != NullChn)
SendNotice_channel;
DelListItem(ch, channels);
MyFree(ch);
}
}
else
{
SendNotice_private;
}
}
if (myconf.enable_bans && ban)
{
#ifndef NO_PLACE_HOST_BAN
place_host_ban(from, myconf.ban_type,
myconf.ban_reason ? myconf.ban_reason
: DEF_BAN_REASON,
myconf.ban_period);
#else
char *bantype;
if ((bantype = find_BanFlag(myconf.ban_type)))
ban_client(from, bantype, myconf.ban_period,
myconf.ban_reason ? myconf.ban_reason
: DEF_BAN_REASON);
#endif
}
else if ((cmdtype != CT_QUIT) && myconf.enable_kills && kill)
{
/*
* Can't find a better solution for killing a user due to an adword;
* using the Event system seems to be working. The problem actually
* is we shouldn't kill a user more than one time (fe. when ppl use
* multiple targets in a PRIVMSG/NOTICE).
*/
strcpy(nickbuf, from->name);
EventAdd("adwords_kill", 0, 1, &adwords_event_kill, nickbuf);
}
else if (myconf.enable_warnings && warn)
{
if (myconf.enable_blockings && block)
sendto_one(from, ":%s NOTICE %s :%s",
me.name, from->name, myconf.block_message ?
myconf.block_message : DEF_BLOCK_MSG);
else
sendto_one(from, ":%s NOTICE %s :%s",
me.name, from->name, myconf.warning_message ?
myconf.warning_message : DEF_WARNING_MSG);
}
cleanstr[511] = '\0'; /* cutoff, just to be sure */
return (myconf.enable_blockings && block) ?
NULL : cleaned ? cleanstr : str;
}
/*
* cb_privmsg
* ==========
*
* from: who is sending the message
* to: who will receive it
* str: message text
* notice: tells whether it's a notice or privmsg
*/
static char *cb_privmsg(aClient *cptr, aClient *from, aClient *to, char *str, int notice)
{
if (!IsClient(from) || IsULine(from) || IsULine(to)
|| (myconf.require_mode_g && !IsFilteringWords(to)))
return str;
return adword_checkmsg(cptr, from, to->name, str,
notice ? CT_NOTICE : CT_PRIVMSG, AdwordsMessage);
}
/*
* cb_chanmsg
* ==========
*
* from: who is sending the message
* to: the channel where it will be sent to
* str: message text
* notice: tells whether it's a notice or privmsg
*/
static char *cb_chanmsg(aClient *cptr, aClient *from, aChannel *to, char *str, int notice)
{
ConfigItem_except *e;
if (!IsClient(from) || IsULine(from) || (myconf.require_mode_g
&& !(to->mode.mode & MODE_STRIPBADWORDS)))
return str;
for (e = conf_exceptchan; e; e = (ConfigItem_except *) e->next)
if (!match(e->mask, to->chname))
return str;
return adword_checkmsg(cptr, from, to->chname, str,
notice? CT_NOTICE : CT_PRIVMSG, AdwordsChannel);
}
/*
* cb_quit
* =======
*
* sptr: who is sending the message
* comment: message text
*/
static char *cb_quit(aClient *sptr, char *comment)
{
Membership *lp;
if (IsULine(sptr))
return comment;
if (myconf.require_mode_g)
{
u_int strip = 0;
for (lp = sptr->user->channel; lp; lp = lp->next)
if (lp->chptr->mode.mode & MODE_STRIPBADWORDS)
{
strip = 1;
break;
}
if (!strip)
return comment;
}
return adword_checkmsg(sptr, sptr, NULL, comment,
CT_QUIT, AdwordsQuit);
}
#ifndef HOOKTYPE_PRE_LOCAL_QUIT
/* ugly */
int override_quit(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
{
char *ocomment = (parc > 1 && parv[1]) ? parv[1] : parv[0];
static char comment[TOPICLEN + 1];
Membership *lp;
if (!IsServer(cptr) && IsPerson(sptr))
{
#ifdef STRIPBADWORDS
int blocked = 0;
#endif
char *s = comment;
if (STATIC_QUIT)
{
return exit_client(cptr, sptr, sptr, STATIC_QUIT);
}
if (!prefix_quit || strcmp(prefix_quit, "no"))
s = ircsprintf(comment, "%s ",
BadPtr(prefix_quit) ? "Quit:" : prefix_quit);
#ifdef STRIPBADWORDS
ocomment = (char *)stripbadwords_quit(ocomment, &blocked);
if (blocked)
ocomment = parv[0];
#endif
ocomment = cb_quit(sptr, ocomment);
if (!ocomment)
ocomment = parv[0];
if (!IsAnOper(sptr) && ANTI_SPAM_QUIT_MSG_TIME)
if (sptr->firsttime+ANTI_SPAM_QUIT_MSG_TIME > TStime())
ocomment = parv[0];
/* Strip color codes if any channel is +S, use nick as reason if +c. */
if (IsPerson(sptr) && (strchr(ocomment, '\003')))
{
unsigned char filtertype = 0; /* 1=filter, 2=block, highest wins. */
for (lp = sptr->user->channel; lp; lp = lp->next)
{
if (lp->chptr->mode.mode & MODE_NOCOLOR)
{
filtertype = 2;
break;
}
if (lp->chptr->mode.mode & MODE_STRIP)
{
if (!filtertype)
filtertype = 1;
}
}
if (filtertype == 1)
{
ocomment = StripColors(ocomment);
if (*ocomment == '\0')
ocomment = parv[0];
} else
if (filtertype == 2)
ocomment = parv[0];
} /* (strip color codes) */
strncpy(s, ocomment, TOPICLEN - (s - comment));
comment[TOPICLEN] = '\0';
return exit_client(cptr, sptr, sptr, comment);
}
else
{
return exit_client(cptr, sptr, sptr, ocomment);
}
}
#endif
#ifdef HOOKTYPE_PRE_LOCAL_PART
/*
* cb_partmsg
* ==========
*
* sptr: who is sending the message
* chptr: the channel where it will be sent to
* comment: message text
*/
static char *cb_partmsg(aClient *sptr, aChannel *chptr, char *comment)
{
ConfigItem_except *e;
if (!comment)
return NULL;
if (IsULine(sptr) || (myconf.require_mode_g && !(chptr->mode.mode & MODE_STRIPBADWORDS)))
return comment;
for (e = conf_exceptchan; e; e = (ConfigItem_except *) e->next)
if (!match(e->mask, chptr->chname))
return comment;
return adword_checkmsg(sptr, sptr, chptr->chname, comment, CT_PART, AdwordsPart);
}
#endif
/*
* m_adwords
* =========
*
* parv[0]: sender prefix
* parv[1]: option
* parv[2]: value (optional)
*
*/
static int m_adwords(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
ConfigItem_except *e = NULL;
if (!MyConnect(sptr) || !IsPerson(sptr) || !IsAnOper(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (parc < 2 || BadPtr(parv[1]))
{
sendto_one(sptr, ":%s NOTICE %s :Usage:",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : /adwords <option>",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s :Options:",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : message: shows you the adword message block list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : channel: shows you the adword channel block list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : quit: shows you the adword quit block list",
me.name, sptr->name);
#ifdef HOOKTYPE_PRE_LOCAL_PART
sendto_one(sptr, ":%s NOTICE %s : part: shows you the adword part block list",
me.name, sptr->name);
#endif
sendto_one(sptr, ":%s NOTICE %s : all: shows you all the adword block list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : exceptions: shows you the except channel mask list",
me.name, sptr->name);
sendto_one(sptr, ":%s NOTICE %s : config: displays adwords configuration",
me.name, sptr->name);
return 0;
}
if (!strcasecmp(parv[1], "message"))
{
stats_wordlist(sptr, AdwordsMessage, 'M');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
else if (!strcasecmp(parv[1], "channel"))
{
stats_wordlist(sptr, AdwordsChannel, 'C');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
else if (!strcasecmp(parv[1], "quit"))
{
stats_wordlist(sptr, AdwordsQuit, 'Q');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
#ifdef HOOKTYPE_PRE_LOCAL_PART
else if (!strcasecmp(parv[1], "part"))
{
stats_wordlist(sptr, AdwordsPart, 'P');
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
#endif
else if (!strcasecmp(parv[1], "all"))
{
stats_wordlist(sptr, AdwordsMessage, 'M');
stats_wordlist(sptr, AdwordsChannel, 'C');
stats_wordlist(sptr, AdwordsQuit, 'Q');
#ifdef HOOKTYPE_PRE_LOCAL_PART
stats_wordlist(sptr, AdwordsPart, 'P');
#endif
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'a');
}
else if (!strcasecmp(parv[1], "exceptions"))
{
for (e = conf_exceptchan; e; e = (ConfigItem_except *) e->next)
sendto_one(sptr, ":%s %i %s :m %s",
me.name, RPL_TEXT, sptr->name, e->mask);
sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], 'm');
}
else if (!strcasecmp(parv[1], "config"))
cb_stats(sptr);
else
{
sendto_one(sptr, ":%s NOTICE %s :Unknown option %s."
" Valid options are: message | channel | all | exceptions | config",
me.name, sptr->name, parv[1]);
return -1;
}
return 0;
}
static void stats_wordlist(aClient *sptr, Adword *wordlist, char wtype)
{
Adword *a;
for (a = wordlist; a; a = (Adword *) a->next)
sendto_one(sptr, ":%s %i %s :a %c %c %c %c %s %s%s%s" "%s%s" "%s%s",
me.name, RPL_TEXT, sptr->name,
wtype,
find_WordFlag(a->type),
find_MsgType(a->msgtype),
find_UserType(a->usertype),
make_optlist(a),
a->type & WT_FAST_L ? "*" : "",
a->word,
a->type & WT_FAST_R ? "*" : "",
a->replace ? " " : "",
a->replace ? a->replace : "",
a->channel ? " " : "",
a->channel ? a->channel : "");
}
static void adwords_event_kill(char *name)
{
aClient *cptr;
if ((cptr = find_person(name, NULL)))
exit_client(cptr, cptr, &me,
myconf.kill_reason ? myconf.kill_reason : DEF_KILL_REASON);
}