Initial commit.
This commit is contained in:
commit
740371b4e2
|
@ -0,0 +1,65 @@
|
|||
# Copyright (c) 2003-2004 E. Will et al.
|
||||
# Rights to this code are documented in doc/LICENSE.
|
||||
#
|
||||
# This file contains build instructions.
|
||||
#
|
||||
# $Id: Makefile.in 8375 2007-06-03 20:03:26Z pippijn $
|
||||
#
|
||||
|
||||
MODULE = contrib
|
||||
|
||||
SRCS = \
|
||||
cs_access_alias.c \
|
||||
cs_badwords.c \
|
||||
cs_fregister.c \
|
||||
cs_kickdots.c \
|
||||
cs_ping.c \
|
||||
cs_regmode.c \
|
||||
cs_regnotice.c \
|
||||
cs_updown.c \
|
||||
cs_userinfo.c \
|
||||
dnsbl.c \
|
||||
gen_echoserver.c \
|
||||
gen_listenerdemo.c \
|
||||
gen_vhostonreg.c \
|
||||
graphtastical.c \
|
||||
gs_roulette.c \
|
||||
ircd_announceserv.c \
|
||||
ircd_catserv.c \
|
||||
ms_fsend.c \
|
||||
ns_cleannick.c \
|
||||
ns_fenforce.c \
|
||||
ns_fregister.c \
|
||||
ns_forbid.c \
|
||||
ns_generatehash.c \
|
||||
ns_generatepass.c \
|
||||
ns_guestnoreg.c \
|
||||
ns_listlogins.c \
|
||||
ns_mxcheck.c \
|
||||
ns_mxcheck_async.c \
|
||||
ns_regnotice.c \
|
||||
ns_waitreg.c \
|
||||
on_db_save.c \
|
||||
os_akillnicklist.c \
|
||||
os_defcon.c \
|
||||
os_joinmon.c \
|
||||
os_kill.c \
|
||||
os_klinechan.c \
|
||||
os_modeall.c \
|
||||
os_pingspam.c \
|
||||
os_resolve.c \
|
||||
os_savechanmodes.c \
|
||||
os_tabletest.c \
|
||||
os_testcmd.c \
|
||||
os_testproc.c \
|
||||
os_trace.c \
|
||||
wumpus.c
|
||||
|
||||
include ../../extra.mk
|
||||
include ../../buildsys.mk
|
||||
include ../../buildsys.module.mk
|
||||
|
||||
CPPFLAGS += -I../../include
|
||||
CFLAGS += ${PLUGIN_CFLAGS}
|
||||
LIBS += -L../../libathemecore -lathemecore ${LDFLAGS_RPATH}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
This directory contains modules that are not included in the main modules
|
||||
folders for one reason or another. Either their code is a bit ugly, their
|
||||
functionality is frowned upon, they only work with a limited number of IRCd's
|
||||
or similar cases.
|
||||
|
||||
Modules
|
||||
=======
|
||||
|
||||
cs_babbler.c - Repeats what others users in a channel say back to a specific
|
||||
user. Useful for users that claim they have entire channels on
|
||||
ignore. NOT COMPILED BY DEFAULT.
|
||||
|
||||
cs_badwords.c - Takes actions against users (KICK, BAN, KICKBAN or QUIET) for
|
||||
using badwords in channel, specified on a per-channel basis
|
||||
with the BADWORDS command. Be aware it will check every message
|
||||
sent to channels that BLOCKBADWORDS is set on so it can be a bit
|
||||
CPU-heavy.
|
||||
|
||||
cs_kickdots.c - Kicks users from a channel when kickdots metadata is set on
|
||||
that channel and users send a line containing only "...".
|
||||
Deprecated by cs_badwords (/cs badwords #channel add ... kick).
|
||||
|
||||
cs_ping.c - Responds to users that ping ChanServ with "Pong!".
|
||||
|
||||
cs_regmode.c - Sets the stupid, pointless DALNet-style +/-r mode when a channel
|
||||
is registered or dropped. NOT RECOMMENDED TO USE.
|
||||
|
||||
cs_regnotice.c - Sends a user a notice with some information specified in a
|
||||
regnotice {} block inside the chanserv {} block of your
|
||||
atheme.conf when the user registers a channel.
|
||||
|
||||
cs_updown.c - Either gives or removes all your channel status modes at once.
|
||||
|
||||
cs_userinfo.c - Display a message when a user joins a channel. You must be able
|
||||
to edit the channel access list to add or remove a userinfo entry.
|
||||
|
||||
gen_echoserver.c - NOT RECOMMENDED TO USE.
|
||||
|
||||
gen_httpd.c - A small sample httpd for serving files. It is highly recommended
|
||||
to use misc/httpd.c instead.
|
||||
|
||||
gen_listenerdemo.c - NOT RECOMMENDED TO USE.
|
||||
|
||||
gen_vhostonreg.c - Assigns a $account.hidehostsuffix vhost to all users upon
|
||||
account registration. $account will be replaced by the users'
|
||||
accountname and hidehostsuffix is that config option from the
|
||||
serverinfo {} block of your atheme.conf.
|
||||
|
||||
graphtastical.c - Graphs user->channel relationships. Not recommended to use if
|
||||
there are privacy concerns.
|
||||
|
||||
gs_roulette.c - A nice GameServ game of Russian Roulette.
|
||||
|
||||
ircd_catserv.c - Little module showing a CatServ Services client.
|
||||
|
||||
ircd_announceserv.c - A services bot which allows users to request network
|
||||
announcements that will then (when approved by a soper)
|
||||
be sent to all users on the network. This is seperate
|
||||
from InfoServ so that users can easily ignore users'
|
||||
announcements but won't miss any important announcements
|
||||
from network staff.
|
||||
|
||||
ircd_loveserv.c - A services bot for sending love-related items to other users.
|
||||
NOT COMPILED BY DEFAULT.
|
||||
|
||||
ircd_crypto_trans.c - A encryption module for IRCServices weird password
|
||||
encryption scheme. NOT COMPILED BY DEFAULT.
|
||||
|
||||
mlocktweaker.c - Sets the mlock to all new channels to something specified in
|
||||
the source code of the module. See line 16 of the module's
|
||||
code for what to edit. NOT COMPILED BY DEFAULT.
|
||||
|
||||
ns_ajoin.c - Allows users to set a AJOIN/autojoin list of channels that Atheme
|
||||
will automatically join them to upon identify. Only works on
|
||||
ShadowIRCd, InspIRCd and UnrealIRCd. NOT COMPILED BY DEFAULT.
|
||||
|
||||
ns_cleannick.c - Detects and cleans 'lame' nicknames using case normalization.
|
||||
|
||||
ns_fenforce.c - Allows opers to force the ENFORCE flag on/off on other users'
|
||||
accounts.
|
||||
|
||||
ns_forbid.c - Allows opers to forbid the registration and use of a nickname.
|
||||
|
||||
ns_fregister.c - Allows opers to register an account on behalf of another user.
|
||||
A oper must have the user:fregister priv to use this command.
|
||||
|
||||
ns_generatehash.c - Generates a password hash from the password given as part
|
||||
of the command. Extremely useful if your passwords are
|
||||
encrypted and you want to set SOPER passwords.
|
||||
|
||||
ns_generatepass.c - Generates a random password.
|
||||
|
||||
ns_guestnoreg.c - Disallows the registration of nicks beginning with a string
|
||||
specified in the guestnicks {} block inside the nickserv {}
|
||||
block of your atheme.conf.
|
||||
|
||||
ns_listlogins.c - Allows users to list the other clients currently logged in
|
||||
to the same account as them.
|
||||
|
||||
ns_mxcheck.c - Checks if a email address provided by a user upon registration
|
||||
is valid and fails registration if it is not.
|
||||
|
||||
ns_mxcheck_async.c - Same as ns_mxcheck.c, but asynchronous.
|
||||
|
||||
ns_regnotice.c - Sends a user a notice with some information specified in a
|
||||
regnotice {} block inside the nickserv {} block of your
|
||||
atheme.conf when the user registers an account.
|
||||
|
||||
ns_waitreg.c - Requires a user to have been connected for waitreg_time (in
|
||||
the nickserv {} block of your atheme.conf) seconds before
|
||||
they are allowed to register their nick.
|
||||
|
||||
on_db_save.c - Allows you to specify a command that is run every time the
|
||||
Atheme database is saved.
|
||||
|
||||
os_akillnicklist.c - AKILLs users matched in a nicklist specified in your
|
||||
atheme.conf. See the comment at the top of the module's
|
||||
source code for details.
|
||||
|
||||
os_defcon.c - Allows you to use DEFCON-based security on your network.
|
||||
*HIGHLY* NOT RECOMMENDED AND NOT COMPILED BY DEFAULT.
|
||||
|
||||
os_helpme.c - Sets usermode +h on all users listed with the general:helper
|
||||
soper priv upon recieving soper status. Requires an IRCd that has
|
||||
+h (helper) usermode support. NOT COMPILED BY DEFAULT.
|
||||
|
||||
os_joinmon.c - Allows adding nick patterns to a joinmon list and when a user
|
||||
matching one of the patterns joins a channel, a message will
|
||||
be sent to the logchan (with the info loglevel).
|
||||
|
||||
os_kill.c - Allows opers to KILL users via services.
|
||||
|
||||
os_klinechan.c - KLINEs all users who join a KLINECHAN.
|
||||
|
||||
os_pingspam.c - Spam a user with pings and various messages either on-demand or
|
||||
spams all users a bit upon connect.
|
||||
|
||||
os_procwatch.c - Watch a specified process and log a message when it finishes
|
||||
running. Requires kqueue (FreeBSD). NOT COMPILED BY DEFAULT.
|
||||
|
||||
os_savechanmodes.c - Allows you to dump and restore channelmodes of all channels
|
||||
on the network.
|
||||
|
||||
os_tabletest.c - NOT RECOMMENDED TO USE.
|
||||
|
||||
os_testcmd.c - Run a test command.
|
||||
|
||||
os_testproc.c - Runs a test of child processes.
|
||||
|
||||
os_trace.c - Looks up users by certain criteria and allows you to perform
|
||||
various actions on them.
|
||||
|
||||
wumpus.c - Allows users to play a game of Hunt the Wumpus!
|
|
@ -0,0 +1,42 @@
|
|||
#include <execinfo.h>
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/backtrace", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void __segv_hdl(int whocares)
|
||||
{
|
||||
void *array[256];
|
||||
char **strings;
|
||||
size_t sz, i;
|
||||
|
||||
sz = backtrace(array, 256);
|
||||
strings = backtrace_symbols(array, sz);
|
||||
|
||||
slog(LG_INFO, "---------------- [ CRASH ] -----------------");
|
||||
slog(LG_INFO, "%zu stack frames, flags %s", sz, get_conf_opts());
|
||||
for (i = 0; i < sz; i++)
|
||||
slog(LG_INFO, "#%zu --> %p (%s)", i, array[i], strings[i]);
|
||||
slog(LG_INFO, "Report to http://jira.atheme.org/");
|
||||
slog(LG_INFO, "--------------------------------------------");
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
signal(SIGSEGV, __segv_hdl);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
signal(SIGSEGV, NULL);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
Binary file not shown.
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Jilles Tjoelker, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* ChanServ ACCESS command
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "template.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_access_alias", FALSE, _modinit, _moddeinit,
|
||||
"$Id$",
|
||||
"freenode <http://www.freenode.net>"
|
||||
);
|
||||
|
||||
static void cs_cmd_access(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cs_access = { "ACCESS", "Manipulates channel access lists.",
|
||||
AC_NONE, 4, cs_cmd_access, { .path = "contrib/access" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("chanserv", &cs_access);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("chanserv", &cs_access);
|
||||
}
|
||||
|
||||
static void compat_cmd(sourceinfo_t *si, const char *cmdname, char *channel, char *arg1, char *arg2, char *arg3)
|
||||
{
|
||||
int newparc;
|
||||
char *newparv[5];
|
||||
command_t *cmd;
|
||||
|
||||
newparv[0] = channel;
|
||||
newparv[1] = arg1;
|
||||
newparv[2] = arg2;
|
||||
newparv[3] = arg3;
|
||||
newparv[4] = NULL;
|
||||
/* this assumes arg3!=NULL implies arg2!=NULL implies arg1!=NULL */
|
||||
newparc = 1 + (arg1 != NULL) + (arg2 != NULL) + (arg3 != NULL);
|
||||
cmd = command_find(si->service->commands, cmdname);
|
||||
if (cmd != NULL)
|
||||
command_exec(si->service, si, cmd, newparc, newparv);
|
||||
else
|
||||
command_fail(si, fault_unimplemented, _("Command \2%s\2 not loaded?"), cmdname);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char *res;
|
||||
unsigned int level;
|
||||
} template_iter_t;
|
||||
|
||||
static int global_template_search(const char *key, void *data, void *privdata)
|
||||
{
|
||||
template_iter_t *iter = privdata;
|
||||
default_template_t *def_t = data;
|
||||
|
||||
if (def_t->flags == iter->level)
|
||||
iter->res = key;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *get_template_name(mychan_t *mc, unsigned int level)
|
||||
{
|
||||
metadata_t *md;
|
||||
const char *p, *q, *r;
|
||||
char *s;
|
||||
char ss[40];
|
||||
static char flagname[400];
|
||||
template_iter_t iter;
|
||||
|
||||
md = metadata_find(mc, "private:templates");
|
||||
if (md != NULL)
|
||||
{
|
||||
p = md->value;
|
||||
while (p != NULL)
|
||||
{
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
q = strchr(p, '=');
|
||||
if (q == NULL)
|
||||
break;
|
||||
r = strchr(q, ' ');
|
||||
if (r != NULL && r < q)
|
||||
break;
|
||||
mowgli_strlcpy(ss, q, sizeof ss);
|
||||
if (r != NULL && r - q < (int)(sizeof ss - 1))
|
||||
{
|
||||
ss[r - q] = '\0';
|
||||
}
|
||||
if (level == flags_to_bitmask(ss, 0))
|
||||
{
|
||||
mowgli_strlcpy(flagname, p, sizeof flagname);
|
||||
s = strchr(flagname, '=');
|
||||
if (s != NULL)
|
||||
*s = '\0';
|
||||
return flagname;
|
||||
}
|
||||
p = r;
|
||||
}
|
||||
}
|
||||
|
||||
iter.res = NULL;
|
||||
iter.level = level;
|
||||
mowgli_patricia_foreach(global_template_dict, global_template_search, &iter);
|
||||
|
||||
return iter.res;
|
||||
}
|
||||
|
||||
static void access_list(sourceinfo_t *si, mychan_t *mc, int parc, char *parv[])
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
chanacs_t *ca;
|
||||
const char *str1, *str2;
|
||||
int i = 1;
|
||||
bool operoverride = false;
|
||||
|
||||
/* Copied from modules/chanserv/flags.c */
|
||||
/* Note: This overrides the normal need of +A access unless private */
|
||||
if (use_channel_private && mc->flags & MC_PRIVATE &&
|
||||
!chanacs_source_has_flag(mc, si, CA_ACLVIEW))
|
||||
{
|
||||
if (has_priv(si, PRIV_CHAN_AUSPEX))
|
||||
operoverride = true;
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
command_success_nodata(si, _("Entry Nickname/Host Flags"));
|
||||
command_success_nodata(si, "----- ---------------------- -----");
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, mc->chanacs.head)
|
||||
{
|
||||
ca = n->data;
|
||||
/* Change: don't show akicks */
|
||||
if (ca->level == CA_AKICK)
|
||||
continue;
|
||||
str1 = get_template_name(mc, ca->level);
|
||||
str2 = ca->tmodified ? time_ago(ca->tmodified) : "?";
|
||||
if (str1 != NULL)
|
||||
command_success_nodata(si, _("%-5d %-22s %s (%s) [modified %s ago]"), i, ca->entity ? ca->entity->name : ca->host, bitmask_to_flags(ca->level), str1,
|
||||
str2);
|
||||
else
|
||||
command_success_nodata(si, _("%-5d %-22s %s [modified %s ago]"), i, ca->entity ? ca->entity->name : ca->host, bitmask_to_flags(ca->level),
|
||||
str2);
|
||||
i++;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "----- ---------------------- -----");
|
||||
command_success_nodata(si, _("End of \2%s\2 FLAGS listing."), mc->name);
|
||||
|
||||
if (operoverride)
|
||||
logcommand(si, CMDLOG_ADMIN, "%s ACCESS LIST (oper override)", mc->name);
|
||||
else
|
||||
logcommand(si, CMDLOG_GET, "%s ACCESS LIST", mc->name);
|
||||
}
|
||||
|
||||
static void cs_cmd_access(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *chan, *cmd;
|
||||
mychan_t *mc;
|
||||
char killit[] = "-*";
|
||||
char deftemplate[] = "OP";
|
||||
char defaccess[] = "=votirA";
|
||||
|
||||
if (parc < 2)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: ACCESS <#channel> ADD|DEL|LIST [nick] [level]"));
|
||||
return;
|
||||
}
|
||||
if (parv[0][0] == '#')
|
||||
chan = parv[0], cmd = parv[1];
|
||||
else if (parv[1][0] == '#')
|
||||
cmd = parv[0], chan = parv[1];
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "ACCESS");
|
||||
command_fail(si, fault_badparams, _("Syntax: ACCESS <#channel> ADD|DEL|LIST [nick] [level]"));
|
||||
return;
|
||||
}
|
||||
|
||||
mc = mychan_find(chan);
|
||||
if (mc == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), chan);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(cmd, "LIST"))
|
||||
access_list(si, mc, parc - 2, parv + 2);
|
||||
else if (parc < 3)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACCESS");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: ACCESS <#channel> ADD|DEL <nick> [level]"));
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp(cmd, "ADD"))
|
||||
compat_cmd(si, "FLAGS", chan, parv[2], parc > 3 ? parv[3] : (get_template_flags(mc, deftemplate) ? deftemplate : defaccess), NULL);
|
||||
else if (!strcasecmp(cmd, "DEL"))
|
||||
compat_cmd(si, "FLAGS", chan, parv[2], killit, NULL);
|
||||
else
|
||||
command_fail(si, fault_badparams, _("Invalid command. Use \2/%s%s help\2 for a command listing."), (ircd->uses_rcommand == FALSE) ? "msg " : "", si->service->disp);
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (c) 2008 William Pitcock
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Because sometimes premadonna assholes with large ignore lists
|
||||
* piss entire channels the hell off...
|
||||
*
|
||||
* So what does this do?
|
||||
* =====================
|
||||
*
|
||||
* It repeats everything someone says and to be extra annoying, highlights
|
||||
* the person who has public ignore notification spam.
|
||||
*
|
||||
* It was written for the purpose of mockery of someone on #atheme-project
|
||||
* who makes claims like "I have the whole channel on ignore", etc.
|
||||
*
|
||||
* Pro tip: we don't care about your ignore list.
|
||||
*
|
||||
* How do I use it? I have an asshole on my channel too!
|
||||
* =====================================================
|
||||
*
|
||||
* Load the module, set these options:
|
||||
*
|
||||
* - babbler:enable to actually enable babbler
|
||||
* - babbler:nicks, the actual ignore list of the asshole
|
||||
* - babbler:target, the nick of the person who needs to be pwnt
|
||||
* - babbler:source, the nick of a psuedoclient to send the message
|
||||
* from.
|
||||
*
|
||||
* Will you make it PM them instead?
|
||||
* =================================
|
||||
*
|
||||
* Absolutely not. Then it could be used for spambots, etc. That's a really
|
||||
* bad idea.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_babbler", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"William Pitcock <nenolod -at- nenolod.net>"
|
||||
);
|
||||
|
||||
static void
|
||||
on_channel_message(void *p)
|
||||
{
|
||||
hook_cmessage_data_t *data = p;
|
||||
|
||||
if (data != NULL && data->msg != NULL)
|
||||
{
|
||||
mychan_t *mc = MYCHAN_FROM(data->c);
|
||||
metadata_t *md;
|
||||
|
||||
if (!mc)
|
||||
return;
|
||||
|
||||
if (!metadata_find(mc, "babbler:enable"))
|
||||
return;
|
||||
|
||||
if (!(md = metadata_find(mc, "babbler:nicks")))
|
||||
return;
|
||||
|
||||
if (strstr(md->value, data->u->nick))
|
||||
{
|
||||
char *source = NULL;
|
||||
char *target;
|
||||
|
||||
if (!(md = metadata_find(mc, "babbler:target")))
|
||||
return;
|
||||
|
||||
target = md->value;
|
||||
|
||||
if (!(md = metadata_find(mc, "babbler:source")))
|
||||
source = chansvs.nick;
|
||||
else
|
||||
source = md->value;
|
||||
|
||||
msg(source, data->c->name, "%s: <%s> %s", target, data->u->nick, data->msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("channel_message");
|
||||
hook_add_channel_message(on_channel_message);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_message(on_channel_message);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock <nenolod -at- nenolod.net>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_badwords", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.net>"
|
||||
);
|
||||
|
||||
static void on_channel_message(hook_cmessage_data_t *data);
|
||||
static void cs_cmd_badwords(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void cs_set_cmd_blockbadwords(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
static void write_badword_db(database_handle_t *db);
|
||||
static void db_h_bw(database_handle_t *db, const char *type);
|
||||
|
||||
command_t cs_badwords = { "BADWORDS", N_("Manage the list of channel bad words."), AC_AUTHENTICATED, 4, cs_cmd_badwords, { .path = "contrib/badwords" } };
|
||||
command_t cs_set_blockbadwords = { "BLOCKBADWORDS", N_("Set whether users can say badwords in channel or not."), AC_NONE, 2, cs_set_cmd_blockbadwords, { .path = "contrib/set_blockbadwords" } };
|
||||
|
||||
struct badword_ {
|
||||
char *badword;
|
||||
time_t add_ts;
|
||||
char *creator;
|
||||
char *channel;
|
||||
char *action;
|
||||
mowgli_node_t node;
|
||||
};
|
||||
|
||||
typedef struct badword_ badword_t;
|
||||
|
||||
mowgli_patricia_t **cs_set_cmdtree;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
MODULE_TRY_REQUEST_SYMBOL(m, cs_set_cmdtree, "chanserv/set_core", "cs_set_cmdtree");
|
||||
|
||||
if (!module_find_published("backend/opensex"))
|
||||
{
|
||||
slog(LG_INFO, "Module %s requires use of the OpenSEX database backend, refusing to load.", m->name);
|
||||
m->mflags = MODTYPE_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
hook_add_event("channel_message");
|
||||
hook_add_channel_message(on_channel_message);
|
||||
|
||||
hook_add_db_write(write_badword_db);
|
||||
|
||||
db_register_type_handler("BW", db_h_bw);
|
||||
|
||||
service_named_bind_command("chanserv", &cs_badwords);
|
||||
command_add(&cs_set_blockbadwords, *cs_set_cmdtree);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_message(on_channel_message);
|
||||
hook_del_db_write(write_badword_db);
|
||||
|
||||
db_unregister_type_handler("BW");
|
||||
|
||||
service_named_unbind_command("chanserv", &cs_badwords);
|
||||
command_delete(&cs_set_blockbadwords, *cs_set_cmdtree);
|
||||
}
|
||||
|
||||
static inline mowgli_list_t *badwords_list_of(mychan_t *mc)
|
||||
{
|
||||
mowgli_list_t *l;
|
||||
|
||||
return_val_if_fail(mc != NULL, NULL);
|
||||
|
||||
l = privatedata_get(mc, "badword:list");
|
||||
if (l != NULL)
|
||||
return l;
|
||||
|
||||
l = mowgli_list_create();
|
||||
privatedata_set(mc, "badword:list", l);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void write_badword_db(database_handle_t *db)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
mychan_t *mc;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
mowgli_list_t *l;
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(mc, &state, mclist)
|
||||
{
|
||||
l = badwords_list_of(mc);
|
||||
|
||||
if (l == NULL)
|
||||
return;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, l->head)
|
||||
{
|
||||
badword_t *bw = n->data;
|
||||
|
||||
db_start_row(db, "BW");
|
||||
db_write_word(db, bw->badword);
|
||||
db_write_time(db, bw->add_ts);
|
||||
db_write_word(db, bw->creator);
|
||||
db_write_word(db, bw->channel);
|
||||
db_write_word(db, bw->action);
|
||||
db_commit_row(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void db_h_bw(database_handle_t *db, const char *type)
|
||||
{
|
||||
mychan_t *mc;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
mowgli_list_t *l;
|
||||
|
||||
const char *badword = db_sread_word(db);
|
||||
time_t add_ts = db_sread_time(db);
|
||||
const char *creator = db_sread_word(db);
|
||||
const char *channel = db_sread_word(db);
|
||||
const char *action = db_sread_word(db);
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(mc, &state, mclist)
|
||||
{
|
||||
if (irccasecmp(mc->name, channel))
|
||||
continue;
|
||||
|
||||
l = badwords_list_of(mc);
|
||||
|
||||
badword_t *bw = smalloc(sizeof(badword_t));
|
||||
|
||||
bw->badword = sstrdup(badword);
|
||||
bw->add_ts = add_ts;
|
||||
bw->creator = sstrdup(creator);
|
||||
bw->channel = sstrdup(channel);
|
||||
bw->action = sstrdup(action);
|
||||
|
||||
mowgli_node_add(bw, &bw->node, l);
|
||||
}
|
||||
}
|
||||
|
||||
static void on_channel_message(hook_cmessage_data_t *data)
|
||||
{
|
||||
badword_t *bw;
|
||||
mowgli_node_t *n;
|
||||
mowgli_list_t *l;
|
||||
|
||||
mychan_t *mc = MYCHAN_FROM(data->c);
|
||||
|
||||
if (mc == NULL)
|
||||
return;
|
||||
|
||||
if (metadata_find(mc, "blockbadwords") == NULL)
|
||||
return;
|
||||
|
||||
l = badwords_list_of(mc);
|
||||
if (MOWGLI_LIST_LENGTH(l) == 0)
|
||||
return;
|
||||
|
||||
char *kickstring = "Foul language is prohibited here.";
|
||||
|
||||
if (data != NULL && data->msg != NULL)
|
||||
{
|
||||
MOWGLI_ITER_FOREACH(n, l->head)
|
||||
{
|
||||
bw = n->data;
|
||||
|
||||
if (!match(bw->badword, data->msg))
|
||||
{
|
||||
if (!strcasecmp("KICKBAN", bw->action))
|
||||
{
|
||||
char hostbuf[BUFSIZE];
|
||||
|
||||
hostbuf[0] = '\0';
|
||||
|
||||
mowgli_strlcat(hostbuf, "*!*@", BUFSIZE);
|
||||
mowgli_strlcat(hostbuf, data->u->vhost, BUFSIZE);
|
||||
|
||||
modestack_mode_param(chansvs.nick, data->c, MTYPE_ADD, 'b', hostbuf);
|
||||
chanban_add(data->c, hostbuf, 'b');
|
||||
kick(chansvs.me->me, data->c, data->u, kickstring);
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("KICK", bw->action))
|
||||
{
|
||||
kick(chansvs.me->me, data->c, data->u, kickstring);
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("QUIET", bw->action))
|
||||
{
|
||||
char hostbuf[BUFSIZE];
|
||||
|
||||
hostbuf[0] = '\0';
|
||||
|
||||
mowgli_strlcat(hostbuf, "*!*@", BUFSIZE);
|
||||
mowgli_strlcat(hostbuf, data->u->vhost, BUFSIZE);
|
||||
|
||||
modestack_mode_param(chansvs.nick, data->c, MTYPE_ADD, 'q', hostbuf);
|
||||
chanban_add(data->c, hostbuf, 'q');
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("BAN", bw->action))
|
||||
{
|
||||
char hostbuf[BUFSIZE];
|
||||
|
||||
hostbuf[0] = '\0';
|
||||
|
||||
mowgli_strlcat(hostbuf, "*!*@", BUFSIZE);
|
||||
mowgli_strlcat(hostbuf, data->u->vhost, BUFSIZE);
|
||||
|
||||
modestack_mode_param(chansvs.nick, data->c, MTYPE_ADD, 'b', hostbuf);
|
||||
chanban_add(data->c, hostbuf, 'b');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* SET BADWORD */
|
||||
static void cs_cmd_badwords(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *channel = parv[0];
|
||||
char *command = parv[1];
|
||||
char *word = parv[2];
|
||||
char *action = parv[3];
|
||||
mychan_t *mc;
|
||||
mowgli_node_t *n, *tn;
|
||||
badword_t *bw;
|
||||
mowgli_list_t *l;
|
||||
|
||||
if (!channel || !command)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET BADWORDS");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: BADWORDS <#channel> ADD|DEL|LIST [badword] [action]"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mc = mychan_find(channel)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), channel);
|
||||
return;
|
||||
}
|
||||
|
||||
l = badwords_list_of(mc);
|
||||
if (!strcasecmp("ADD", command))
|
||||
{
|
||||
|
||||
if (!word || !action)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "BADWORDS");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: BADWORDS <#channel> ADD <badword> <action>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chanacs_source_has_flag(mc, si, CA_SET))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this command."));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!strcasecmp("KICK", action) || !strcasecmp("KICKBAN", action) || !strcasecmp("BAN", action) || (!strcasecmp("QUIET", action) && ircd != NULL && strchr(ircd->ban_like_modes, 'q')))
|
||||
{
|
||||
if (l != NULL)
|
||||
{
|
||||
MOWGLI_ITER_FOREACH(n, l->head)
|
||||
{
|
||||
bw = n->data;
|
||||
|
||||
if (!irccasecmp(bw->badword, word))
|
||||
{
|
||||
command_success_nodata(si, _("\2%s\2 has already been entered into the bad word list."), word);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bw = smalloc(sizeof(badword_t));
|
||||
bw->add_ts = CURRTIME;;
|
||||
bw->creator = sstrdup(get_source_name(si));
|
||||
bw->channel = sstrdup(mc->name);
|
||||
bw->badword = sstrdup(word);
|
||||
bw->action = sstrdup(action);
|
||||
mowgli_node_add(bw, &bw->node, l);
|
||||
|
||||
command_success_nodata(si, _("You have added \2%s\2 as a bad word."), word);
|
||||
logcommand(si, CMDLOG_SET, "BADWORDS:ADD: \2%s\2 \2%s\2 \2%s\2", channel, word, action);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, _("Invalid action given."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (!strcasecmp("DEL", command))
|
||||
{
|
||||
|
||||
if (!word)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "BADWORDS");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: BADWORDS <#channel> DEL <badword>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chanacs_source_has_flag(mc, si, CA_SET))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this command."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (l == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("There are no badwords set in this channel."));
|
||||
return;
|
||||
}
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, l->head)
|
||||
{
|
||||
bw = n->data;
|
||||
|
||||
if (!irccasecmp(bw->badword, word))
|
||||
{
|
||||
logcommand(si, CMDLOG_SET, "BADWORDS:DEL: \2%s\2 \2%s\2", mc->name, bw->badword);
|
||||
command_success_nodata(si, _("Bad word \2%s\2 has been deleted."), bw->badword);
|
||||
|
||||
mowgli_node_delete(&bw->node, l);
|
||||
|
||||
free(bw->creator);
|
||||
free(bw->channel);
|
||||
free(bw->badword);
|
||||
free(bw->action);
|
||||
free(bw);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
command_success_nodata(si, _("Word \2%s\2 not found in bad word database."), word);
|
||||
}
|
||||
else if (!strcasecmp("LIST", command))
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
struct tm tm;
|
||||
|
||||
if (!chanacs_source_has_flag(mc, si, CA_ACLVIEW))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this command."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (l == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("There are no badwords set in this channel."));
|
||||
return;
|
||||
}
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, l->head)
|
||||
{
|
||||
bw = n->data;
|
||||
|
||||
tm = *localtime(&bw->add_ts);
|
||||
strftime(buf, BUFSIZE, TIME_FORMAT, &tm);
|
||||
command_success_nodata(si, "Word: \2%s\2 Action: \2%s\2 (%s - %s)",
|
||||
bw->badword, bw->action, bw->creator, buf);
|
||||
}
|
||||
command_success_nodata(si, "End of list.");
|
||||
logcommand(si, CMDLOG_GET, "BADWORDS:LIST");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INVALID_PARAMS, "BADWORDS");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: BADWORDS <#channel> ADD|DEL|LIST [badword] [action]"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void cs_set_cmd_blockbadwords(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
mychan_t *mc;
|
||||
|
||||
if (!(mc = mychan_find(parv[0])))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Channel \2%s\2 is not registered."), parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!parv[1])
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SET BLOCKBADWORDS");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chanacs_source_has_flag(mc, si, CA_SET))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this command."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp("ON", parv[1]))
|
||||
{
|
||||
metadata_t *md = metadata_find(mc, "blockbadwords");
|
||||
|
||||
if (md)
|
||||
{
|
||||
command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for channel \2%s\2."), "BLOCKBADWORDS", mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_add(mc, "blockbadwords", "on");
|
||||
|
||||
logcommand(si, CMDLOG_SET, "SET:BLOCKBADWORDS:ON: \2%s\2", mc->name);
|
||||
command_success_nodata(si, _("The \2%s\2 flag has been set for channel \2%s\2."), "BLOCKBADWORDS", mc->name);
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("OFF", parv[1]))
|
||||
{
|
||||
metadata_t *md = metadata_find(mc, "blockbadwords");
|
||||
|
||||
if (!md)
|
||||
{
|
||||
command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for channel \2%s\2."), "BLOCKBADWORDS", mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_delete(mc, "blockbadwords");
|
||||
|
||||
logcommand(si, CMDLOG_SET, "SET:BLOCKBADWORDS:OFF: \2%s\2", mc->name);
|
||||
command_success_nodata(si, _("The \2%s\2 flag has been removed for channel \2%s\2."), "BLOCKBADWORDS", mc->name);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "BLOCKBADWORDS");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the CService FREGISTER function.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "../chanserv/chanserv.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_fregister", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void cs_cmd_fregister(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cs_fregister = { "FREGISTER", N_("Forcibly registers a channel."),
|
||||
PRIV_CHAN_ADMIN, 3, cs_cmd_fregister, { .path = "contrib/cs_fregister" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("chanserv", &cs_fregister);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("chanserv", &cs_fregister);
|
||||
}
|
||||
|
||||
static void cs_cmd_fregister(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
channel_t *c;
|
||||
chanuser_t *cu;
|
||||
mychan_t *mc;
|
||||
char *name = parv[0];
|
||||
char str[21];
|
||||
hook_channel_register_check_t hdatac;
|
||||
hook_channel_req_t hdata;
|
||||
unsigned int fl;
|
||||
|
||||
/* This command is not useful on registered channels, ignore it if
|
||||
* it is a fantasy command so users can program bots to react on
|
||||
* it without interference from ChanServ.
|
||||
*/
|
||||
if (si->c != NULL)
|
||||
return;
|
||||
|
||||
if (!name)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FREGISTER");
|
||||
command_fail(si, fault_needmoreparams, _("To forcibly register a channel: FREGISTER <#channel>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (*name != '#')
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "FREGISTER");
|
||||
command_fail(si, fault_badparams, _("Syntax: FREGISTER <#channel>"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure they're logged in */
|
||||
if (!si->smu)
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not logged in."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (si->smu->flags & MU_WAITAUTH)
|
||||
{
|
||||
command_fail(si, fault_notverified, _("You need to verify your email address before you may register channels."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure it isn't already registered */
|
||||
if ((mc = mychan_find(name)))
|
||||
{
|
||||
if (!use_channel_private || !(mc->flags & MC_PRIVATE))
|
||||
command_fail(si, fault_alreadyexists, _("\2%s\2 is already registered to \2%s\2."), mc->name, mychan_founder_names(mc));
|
||||
else
|
||||
command_fail(si, fault_alreadyexists, _("\2%s\2 is already registered."), mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure the channel exists */
|
||||
if (!(c = channel_find(name)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("The channel \2%s\2 must exist in order to register it."), name);
|
||||
return;
|
||||
}
|
||||
|
||||
hdatac.si = si;
|
||||
hdatac.name = name;
|
||||
hdatac.chan = c;
|
||||
hdatac.approved = 0;
|
||||
hook_call_channel_can_register(&hdatac);
|
||||
if (hdatac.approved != 0)
|
||||
return;
|
||||
|
||||
logcommand(si, CMDLOG_REGISTER | CMDLOG_ADMIN, "FREGISTER: \2%s\2", name);
|
||||
|
||||
mc = mychan_add(name);
|
||||
mc->registered = CURRTIME;
|
||||
mc->used = CURRTIME;
|
||||
mc->mlock_on |= (CMODE_NOEXT | CMODE_TOPIC);
|
||||
if (c->limit == 0)
|
||||
mc->mlock_off |= CMODE_LIMIT;
|
||||
if (c->key == NULL)
|
||||
mc->mlock_off |= CMODE_KEY;
|
||||
mc->flags |= config_options.defcflags;
|
||||
|
||||
chanacs_add(mc, entity(si->smu), custom_founder_check(), CURRTIME, entity(si->smu));
|
||||
|
||||
if (c->ts > 0)
|
||||
{
|
||||
snprintf(str, sizeof str, "%lu", (unsigned long)c->ts);
|
||||
metadata_add(mc, "private:channelts", str);
|
||||
}
|
||||
|
||||
if (chansvs.deftemplates != NULL && *chansvs.deftemplates != '\0')
|
||||
metadata_add(mc, "private:templates",
|
||||
chansvs.deftemplates);
|
||||
|
||||
command_success_nodata(si, _("\2%s\2 is now registered to \2%s\2."), mc->name, entity(si->smu)->name);
|
||||
|
||||
hdata.si = si;
|
||||
hdata.mc = mc;
|
||||
hook_call_channel_register(&hdata);
|
||||
/* Allow the hook to override this. */
|
||||
fl = chanacs_source_flags(mc, si);
|
||||
cu = chanuser_find(mc->chan, si->su);
|
||||
if (cu == NULL)
|
||||
;
|
||||
else if (ircd->uses_owner && fl & CA_USEOWNER && fl & CA_AUTOOP &&
|
||||
!(cu->modes & CSTATUS_OWNER))
|
||||
{
|
||||
modestack_mode_param(si->service->nick, mc->chan, MTYPE_ADD,
|
||||
ircd->owner_mchar[1], CLIENT_NAME(si->su));
|
||||
cu->modes |= CSTATUS_OWNER;
|
||||
}
|
||||
else if (ircd->uses_protect && fl & CA_USEPROTECT && fl & CA_AUTOOP &&
|
||||
!(cu->modes & CSTATUS_PROTECT))
|
||||
{
|
||||
modestack_mode_param(si->service->nick, mc->chan, MTYPE_ADD,
|
||||
ircd->protect_mchar[1], CLIENT_NAME(si->su));
|
||||
cu->modes |= CSTATUS_PROTECT;
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2006 William Pitcock
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Kicks people saying "..." on channels with "kickdots" metadata set.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_kickdots", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"William Pitcock <nenolod -at- nenolod.net>"
|
||||
);
|
||||
|
||||
static void
|
||||
on_channel_message(hook_cmessage_data_t *data)
|
||||
{
|
||||
if (data != NULL && data->msg != NULL && !strncmp(data->msg, "...", 3))
|
||||
{
|
||||
mychan_t *mc = MYCHAN_FROM(data->c);
|
||||
|
||||
if (mc == NULL)
|
||||
return;
|
||||
|
||||
if (metadata_find(mc, "kickdots"))
|
||||
{
|
||||
kick(chansvs.me->me, data->c, data->u, data->msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("channel_message");
|
||||
hook_add_channel_message(on_channel_message);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_message(on_channel_message);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,35 @@
|
|||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_ping", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void cs_cmd_ping(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cs_ping = { "PING", "Verifies network connectivity by responding with pong.",
|
||||
AC_NONE, 0, cs_cmd_ping, { .path = "contrib/cs_ping" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("chanserv", &cs_ping);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("chanserv", &cs_ping);
|
||||
}
|
||||
|
||||
static void cs_cmd_ping(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
command_success_nodata(si, "Pong!");
|
||||
return;
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2011 William Pitcock <nenolod@atheme.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Set/unset DALnet channel mode +r on registration/deregistration.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_regmode", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void register_hook(hook_channel_req_t *hdata)
|
||||
{
|
||||
mychan_t *mc = hdata->mc;
|
||||
|
||||
if (mc == NULL || mc->chan == NULL)
|
||||
return;
|
||||
|
||||
modestack_mode_simple(chansvs.nick, mc->chan, MTYPE_ADD, CMODE_CHANREG);
|
||||
}
|
||||
|
||||
static void drop_hook(mychan_t *mc)
|
||||
{
|
||||
if (mc == NULL || mc->chan == NULL)
|
||||
return;
|
||||
|
||||
modestack_mode_simple(chansvs.nick, mc->chan, MTYPE_DEL, CMODE_CHANREG);
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("channel_register");
|
||||
hook_add_channel_register(register_hook);
|
||||
|
||||
hook_add_event("channel_drop");
|
||||
hook_add_channel_drop(drop_hook);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_register(register_hook);
|
||||
hook_del_channel_drop(drop_hook);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 2010 William Pitcock <nenolod@atheme.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Sends a customized welcome message on channel registration.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "conf.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_regnotice", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static mowgli_list_t regnotices = { NULL, NULL, 0 };
|
||||
|
||||
static void regnotice_hook(hook_channel_req_t *hdata)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
sourceinfo_t *si = hdata->si;
|
||||
mychan_t *mc = hdata->mc;
|
||||
|
||||
if (si == NULL || mc == NULL)
|
||||
return;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, regnotices.head)
|
||||
{
|
||||
char *line = n->data;
|
||||
|
||||
command_success_nodata(si, "%s", line);
|
||||
}
|
||||
}
|
||||
|
||||
static int regnotice_config_handler(mowgli_config_file_entry_t *ce)
|
||||
{
|
||||
mowgli_config_file_entry_t *cce;
|
||||
|
||||
MOWGLI_ITER_FOREACH(cce, ce->entries)
|
||||
{
|
||||
char *line = sstrdup(cce->varname);
|
||||
mowgli_node_add(line, mowgli_node_create(), ®notices);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void regnotice_config_purge(void *unused)
|
||||
{
|
||||
mowgli_node_t *n, *tn;
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, regnotices.head)
|
||||
{
|
||||
char *line = n->data;
|
||||
|
||||
free(line);
|
||||
mowgli_node_delete(n, ®notices);
|
||||
mowgli_node_free(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("config_purge");
|
||||
hook_add_config_purge(regnotice_config_purge);
|
||||
|
||||
hook_add_event("channel_register");
|
||||
hook_add_channel_register(regnotice_hook);
|
||||
|
||||
add_conf_item("REGNOTICE", &chansvs.me->conf_table, regnotice_config_handler);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_register(regnotice_hook);
|
||||
hook_del_config_purge(regnotice_config_purge);
|
||||
|
||||
del_conf_item("REGNOTICE", &chansvs.me->conf_table);
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Atheme Development Group
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the CService UP/DOWN functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_updown", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void cs_cmd_up(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void cs_cmd_down(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cs_up = { "UP", "Grants all access you have permission to on a given channel.", AC_NONE, 1, cs_cmd_up, { .path = "contrib/up" } };
|
||||
command_t cs_down = { "DOWN", "Removes all current access you posess on a given channel.", AC_NONE, 1, cs_cmd_down, { .path = "contrib/down" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("chanserv", &cs_up);
|
||||
service_named_bind_command("chanserv", &cs_down);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("chanserv", &cs_up);
|
||||
service_named_unbind_command("chanserv", &cs_down);
|
||||
}
|
||||
|
||||
|
||||
static void cs_cmd_up(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
chanuser_t *cu;
|
||||
mychan_t *mc;
|
||||
char *name = parv[0];
|
||||
int fl;
|
||||
|
||||
if (!name)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "UP");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: UP <#channel>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mc = mychan_find(name)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 is not registered.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadata_find(mc, "private:close:closer"))
|
||||
{
|
||||
command_fail(si, fault_noprivs, "\2%s\2 is closed.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mc->chan)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 does not exist.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!si->su)
|
||||
return; // needs to be done over IRC
|
||||
|
||||
cu = chanuser_find(mc->chan, si->su);
|
||||
|
||||
if (!cu)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "You are not on \2%s\2.", mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
fl = chanacs_user_flags(mc, cu->user);
|
||||
|
||||
// Don't check NOOP, because they are explicitly requesting status
|
||||
if (ircd->uses_owner)
|
||||
{
|
||||
if (fl & CA_USEOWNER)
|
||||
{
|
||||
if (fl & CA_AUTOOP && !(ircd->owner_mode & cu->modes))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->owner_mchar[1], CLIENT_NAME(cu->user));
|
||||
cu->modes |= ircd->owner_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ircd->uses_protect)
|
||||
{
|
||||
if (fl & CA_USEPROTECT)
|
||||
{
|
||||
if (fl & CA_AUTOOP && !(ircd->protect_mode & cu->modes) && !(ircd->uses_owner && cu->modes & ircd->owner_mode))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->protect_mchar[1], CLIENT_NAME(cu->user));
|
||||
cu->modes |= ircd->protect_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fl & (CA_AUTOOP | CA_OP))
|
||||
{
|
||||
if (fl & CA_AUTOOP && !(CSTATUS_OP & cu->modes))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, 'o', CLIENT_NAME(cu->user));
|
||||
cu->modes |= CSTATUS_OP;
|
||||
}
|
||||
}
|
||||
|
||||
if (ircd->uses_halfops)
|
||||
{
|
||||
if (fl & (CA_AUTOHALFOP | CA_HALFOP))
|
||||
{
|
||||
if (fl & CA_AUTOHALFOP && !(ircd->halfops_mode & cu->modes))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, ircd->halfops_mchar[1], CLIENT_NAME(cu->user));
|
||||
cu->modes |= ircd->halfops_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fl & (CA_AUTOVOICE | CA_VOICE))
|
||||
{
|
||||
if (fl & CA_AUTOVOICE && !(CSTATUS_VOICE & cu->modes))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_ADD, 'v', CLIENT_NAME(cu->user));
|
||||
cu->modes |= CSTATUS_VOICE;
|
||||
}
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Upped successfully on \2%s\2.", mc->name);
|
||||
}
|
||||
|
||||
|
||||
static void cs_cmd_down(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
chanuser_t *cu;
|
||||
mychan_t *mc;
|
||||
char *name = parv[0];
|
||||
|
||||
if (!name)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DOWN");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: DOWN <#channel>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mc = mychan_find(name)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 is not registered.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadata_find(mc, "private:close:closer"))
|
||||
{
|
||||
command_fail(si, fault_noprivs, "\2%s\2 is closed.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mc->chan)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 does not exist.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!si->su)
|
||||
return; // needs to be done over IRC
|
||||
|
||||
cu = chanuser_find(mc->chan, si->su);
|
||||
|
||||
if (!cu)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "You are not on \2%s\2.", mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
chanacs_user_flags(mc, cu->user);
|
||||
|
||||
// Don't check NOOP, because they are explicitly requesting status
|
||||
if (ircd->uses_owner)
|
||||
{
|
||||
if (ircd->owner_mode & cu->modes)
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_DEL, ircd->owner_mchar[1], CLIENT_NAME(cu->user));
|
||||
cu->modes &= ~ircd->owner_mode;
|
||||
}
|
||||
}
|
||||
|
||||
if (ircd->uses_protect)
|
||||
{
|
||||
if (ircd->protect_mode & cu->modes)
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_DEL, ircd->protect_mchar[1], CLIENT_NAME(cu->user));
|
||||
cu->modes &= ~ircd->protect_mode;
|
||||
}
|
||||
}
|
||||
|
||||
if ((CSTATUS_OP & cu->modes))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_DEL, 'o', CLIENT_NAME(cu->user));
|
||||
cu->modes &= ~CSTATUS_OP;
|
||||
}
|
||||
|
||||
if (ircd->uses_halfops)
|
||||
{
|
||||
if (ircd->halfops_mode & cu->modes)
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_DEL, ircd->halfops_mchar[1], CLIENT_NAME(cu->user));
|
||||
cu->modes &= ~ircd->halfops_mode;
|
||||
}
|
||||
}
|
||||
|
||||
if ((CSTATUS_VOICE & cu->modes))
|
||||
{
|
||||
modestack_mode_param(chansvs.nick, mc->chan, MTYPE_DEL, 'v', CLIENT_NAME(cu->user));
|
||||
cu->modes &= ~CSTATUS_VOICE;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Downed successfully on \2%s\2.", mc->name);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Jilles Tjoelker, et al
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Per-channel userinfo thingie
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/cs_userinfo", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void userinfo_check_join(hook_channel_joinpart_t *hdata);
|
||||
static void cs_cmd_userinfo(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cs_userinfo = { "USERINFO", N_("Sets a userinfo message."),
|
||||
AC_NONE, 3, cs_cmd_userinfo, { .path = "contrib/userinfo" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("channel_join");
|
||||
hook_add_channel_join(userinfo_check_join);
|
||||
service_named_bind_command("chanserv", &cs_userinfo);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_join(userinfo_check_join);
|
||||
service_named_unbind_command("chanserv", &cs_userinfo);
|
||||
}
|
||||
|
||||
/* USERINFO <channel> [user] [message] */
|
||||
static void cs_cmd_userinfo(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
myuser_t *mu;
|
||||
mychan_t *mc;
|
||||
chanacs_t *ca;
|
||||
metadata_t *md;
|
||||
unsigned int restrictflags;
|
||||
|
||||
if (parc < 1)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "USERINFO");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: USERINFO <channel> [target] [info]"));
|
||||
return;
|
||||
}
|
||||
|
||||
mc = mychan_find(parv[0]);
|
||||
if (!mc)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadata_find(mc, "private:close:closer") && !has_priv(si, PRIV_CHAN_AUSPEX))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("\2%s\2 is closed."), mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
restrictflags = chanacs_source_flags(mc, si);
|
||||
|
||||
if (parc == 1)
|
||||
{
|
||||
if (!(restrictflags & CA_ACLVIEW))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
|
||||
return;
|
||||
}
|
||||
command_success_nodata(si, _("Nickname Info"));
|
||||
command_success_nodata(si, "------------------- ---------------");
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, mc->chanacs.head)
|
||||
{
|
||||
ca = n->data;
|
||||
if (ca->entity == NULL)
|
||||
continue;
|
||||
md = metadata_find(ca, "userinfo");
|
||||
if (md == NULL)
|
||||
continue;
|
||||
command_success_nodata(si, "%-19s %s", ca->entity->name, md->value);
|
||||
}
|
||||
|
||||
command_success_nodata(si, "------------------- ---------------");
|
||||
command_success_nodata(si, _("End of \2%s\2 USERINFO listing."), mc->name);
|
||||
logcommand(si, CMDLOG_GET, "USERINFO:LIST: \2%s\2", mc->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(restrictflags & CA_FLAGS))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to perform this operation."));
|
||||
return;
|
||||
}
|
||||
mu = myuser_find_ext(parv[1]);
|
||||
if (mu == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), parv[1]);
|
||||
return;
|
||||
}
|
||||
ca = chanacs_find_literal(mc, entity(mu), 0);
|
||||
if (ca == NULL || ca->level & CA_AKICK)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 has no access to \2%s\2."), entity(mu)->name, mc->name);
|
||||
return;
|
||||
}
|
||||
if (ca->level & ~allow_flags(mc, restrictflags))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not authorized to modify the access entry for \2%s\2 on \2%s\2."), entity(mu)->name, mc->name);
|
||||
return;
|
||||
}
|
||||
if (parc == 2)
|
||||
{
|
||||
metadata_delete(ca, "userinfo");
|
||||
command_success_nodata(si, _("Deleted userinfo for \2%s\2 on \2%s\2."),
|
||||
entity(mu)->name, mc->name);
|
||||
logcommand(si, CMDLOG_SET, "USERINFO:DEL: \2%s\2 on \2%s\2", entity(mu)->name, mc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_add(ca, "userinfo", parv[2]);
|
||||
command_success_nodata(si, _("Added userinfo for \2%s\2 on \2%s\2."),
|
||||
entity(mu)->name, mc->name);
|
||||
logcommand(si, CMDLOG_SET, "USERINFO:ADD: \2%s\2 on \2%s\2 (\2%s\2)", entity(mu)->name, mc->name, parv[2]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void userinfo_check_join(hook_channel_joinpart_t *hdata)
|
||||
{
|
||||
chanuser_t *cu = hdata->cu;
|
||||
myuser_t *mu;
|
||||
mychan_t *mc;
|
||||
chanacs_t *ca;
|
||||
metadata_t *md;
|
||||
|
||||
if (cu == NULL)
|
||||
return;
|
||||
if (!(cu->user->server->flags & SF_EOB))
|
||||
return;
|
||||
mu = cu->user->myuser;
|
||||
mc = MYCHAN_FROM(cu->chan);
|
||||
if (mu == NULL || mc == NULL)
|
||||
return;
|
||||
ca = chanacs_find_literal(mc, entity(mu), 0);
|
||||
if (ca == NULL || ca->level & CA_AKICK)
|
||||
return;
|
||||
if (!(md = metadata_find(ca, "userinfo")))
|
||||
return;
|
||||
msg(chansvs.nick, cu->chan->name, "[%s] %s", cu->user->nick, md->value);
|
||||
}
|
|
@ -0,0 +1,615 @@
|
|||
/*
|
||||
* charybdis: A slightly useful ircd.
|
||||
* blacklist.c: Manages DNS blacklist entries and lookups
|
||||
*
|
||||
* Copyright (C) 2006-2008 charybdis development team
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
/* To configure/use, add a block to the general{} section of your atheme.conf
|
||||
* like this:
|
||||
*
|
||||
* blacklists {
|
||||
* "dnsbl.dronebl.org";
|
||||
* "rbl.efnetrbl.org";
|
||||
* };
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "conf.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/dnsbl", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
mowgli_list_t blacklist_list = { NULL, NULL, 0 };
|
||||
mowgli_patricia_t **os_set_cmdtree;
|
||||
static char *action = NULL;
|
||||
|
||||
/* A configured DNSBL */
|
||||
struct Blacklist {
|
||||
unsigned int status; /* If CONF_ILLEGAL, delete when no clients */
|
||||
int refcount;
|
||||
char host[IRCD_RES_HOSTLEN + 1];
|
||||
unsigned int hits;
|
||||
time_t lastwarning;
|
||||
};
|
||||
|
||||
/* A lookup in progress for a particular DNSBL for a particular client */
|
||||
struct BlacklistClient {
|
||||
struct Blacklist *blacklist;
|
||||
user_t *u;
|
||||
dns_query_t dns_query;
|
||||
mowgli_node_t node;
|
||||
};
|
||||
|
||||
struct dnsbl_exempt_ {
|
||||
char *ip;
|
||||
time_t exempt_ts;
|
||||
char *creator;
|
||||
char *reason;
|
||||
};
|
||||
|
||||
typedef struct dnsbl_exempt_ dnsbl_exempt_t;
|
||||
|
||||
mowgli_list_t dnsbl_elist;
|
||||
|
||||
static void os_cmd_set_dnsblaction(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void dnsbl_hit(user_t *u, struct Blacklist *blptr);
|
||||
static void os_cmd_dnsblexempt(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void os_cmd_dnsblscan(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void write_dnsbl_exempt_db(database_handle_t *db);
|
||||
static void db_h_ble(database_handle_t *db, const char *type);
|
||||
static void lookup_blacklists(user_t *u);
|
||||
|
||||
command_t os_set_dnsblaction = { "DNSBLACTION", N_("Changes what happens to a user when they hit a DNSBL."), PRIV_USER_ADMIN, 1, os_cmd_set_dnsblaction, { .path = "contrib/set_dnsblaction" } };
|
||||
command_t os_dnsblexempt = { "DNSBLEXEMPT", N_("Manage the list of IP's exempt from DNSBL checking."), PRIV_USER_ADMIN, 3, os_cmd_dnsblexempt, { .path = "contrib/dnsblexempt" } };
|
||||
command_t os_dnsblscan = { "DNSBLSCAN", N_("Manually scan if a user is in a DNSBL."), PRIV_USER_ADMIN, 1, os_cmd_dnsblscan, { .path = "contrib/dnsblscan" } };
|
||||
|
||||
static inline mowgli_list_t *dnsbl_queries(user_t *u)
|
||||
{
|
||||
mowgli_list_t *l;
|
||||
|
||||
return_val_if_fail(u != NULL, NULL);
|
||||
|
||||
l = privatedata_get(u, "dnsbl:queries");
|
||||
if (l != NULL)
|
||||
return l;
|
||||
|
||||
l = mowgli_list_create();
|
||||
privatedata_set(u, "dnsbl:queries", l);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static void os_cmd_set_dnsblaction(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *act = parv[0];
|
||||
|
||||
if (!act)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DNSBLACTION");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: SET DNSBLACTION <action>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp("SNOOP", act) || !strcasecmp("KLINE", act) || !strcasecmp("NOTIFY", act))
|
||||
{
|
||||
action = sstrdup(act);
|
||||
command_success_nodata(si, _("DNSBLACTION successfully set to \2%s\2"), act);
|
||||
logcommand(si, CMDLOG_ADMIN, "SET:DNSBLACTION: \2%s\2", act);
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("NONE", act))
|
||||
{
|
||||
action = NULL;
|
||||
command_success_nodata(si, _("DNSBLACTION successfully set to \2%s\2"), act);
|
||||
logcommand(si, CMDLOG_ADMIN, "SET:DNSBLACTION: \2%s\2", act);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, _("Invalid action given."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void os_cmd_dnsblexempt(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *command = parv[0];
|
||||
char *ip = parv[1];
|
||||
char *reason = parv[2];
|
||||
mowgli_node_t *n, *tn;
|
||||
dnsbl_exempt_t *de;
|
||||
|
||||
if (!command)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DNSBLEXEMPT");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: DNSBLEXEMPT ADD|DEL|LIST [ip] [reason]"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp("ADD", command))
|
||||
{
|
||||
|
||||
if (!ip || !reason)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DNSBLEXEMPT");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: DNSBLEXEMPT ADD <ip> <reason>"));
|
||||
return;
|
||||
}
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, dnsbl_elist.head)
|
||||
{
|
||||
de = n->data;
|
||||
|
||||
if (!irccasecmp(de->ip, ip))
|
||||
{
|
||||
command_success_nodata(si, _("\2%s\2 has already been entered into the DNSBL exempts list."), ip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
de = smalloc(sizeof(dnsbl_exempt_t));
|
||||
de->exempt_ts = CURRTIME;;
|
||||
de->creator = sstrdup(get_source_name(si));
|
||||
de->reason = sstrdup(reason);
|
||||
de->ip = sstrdup(ip);
|
||||
mowgli_node_add(de, mowgli_node_create(), &dnsbl_elist);
|
||||
|
||||
command_success_nodata(si, _("You have added \2%s\2 to the DNSBL exempts list."), ip);
|
||||
logcommand(si, CMDLOG_ADMIN, "DNSBL:EXEMPT:ADD: \2%s\2 \2%s\2", ip, reason);
|
||||
}
|
||||
else if (!strcasecmp("DEL", command))
|
||||
{
|
||||
|
||||
if (!ip)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DNSBLEXEMPT");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: DNSBLEXEMPT DEL <ip>"));
|
||||
return;
|
||||
}
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, dnsbl_elist.head)
|
||||
{
|
||||
de = n->data;
|
||||
|
||||
if (!irccasecmp(de->ip, ip))
|
||||
{
|
||||
logcommand(si, CMDLOG_SET, "DNSBL:EXEMPT:DEL: \2%s\2", de->ip);
|
||||
command_success_nodata(si, _("DNSBL Exempt IP \2%s\2 has been deleted."), de->ip);
|
||||
|
||||
mowgli_node_delete(n, &dnsbl_elist);
|
||||
|
||||
free(de->creator);
|
||||
free(de->reason);
|
||||
free(de->ip);
|
||||
free(de);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
command_success_nodata(si, _("IP \2%s\2 not found in DNSBL Exempt database."), ip);
|
||||
}
|
||||
else if (!strcasecmp("LIST", command))
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
struct tm tm;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, dnsbl_elist.head)
|
||||
{
|
||||
de = n->data;
|
||||
|
||||
tm = *localtime(&de->exempt_ts);
|
||||
strftime(buf, BUFSIZE, TIME_FORMAT, &tm);
|
||||
command_success_nodata(si, "IP: \2%s\2 Reason: \2%s\2 (%s - %s)",
|
||||
de->ip, de->reason, de->creator, buf);
|
||||
}
|
||||
command_success_nodata(si, "End of list.");
|
||||
logcommand(si, CMDLOG_GET, "DNSBL:EXEMPT:LIST");
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INVALID_PARAMS, "DNSBLEXEMPT");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: DNSBLEXEMPT ADD|DEL|LIST [ip] [reason]"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void os_cmd_dnsblscan(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *user = parv[0];
|
||||
user_t *u;
|
||||
|
||||
if (!user)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "DNSBLSCAN");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: DNSBLSCAN <user>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((u = user_find_named(user)))
|
||||
{
|
||||
lookup_blacklists(u);
|
||||
logcommand(si, CMDLOG_ADMIN, "DNSBLSCAN: %s", user);
|
||||
command_success_nodata(si, "%s has been scanned.", user);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, "User %s is not on the network, you can not scan them.", user);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* private interfaces */
|
||||
static struct Blacklist *find_blacklist(char *name)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, blacklist_list.head)
|
||||
{
|
||||
struct Blacklist *blptr = (struct Blacklist *) n->data;
|
||||
|
||||
if (!strcasecmp(blptr->host, name))
|
||||
return blptr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void blacklist_dns_callback(void *vptr, dns_reply_t *reply)
|
||||
{
|
||||
struct BlacklistClient *blcptr = (struct BlacklistClient *) vptr;
|
||||
int listed = 0;
|
||||
mowgli_list_t *l;
|
||||
|
||||
if (blcptr == NULL)
|
||||
return;
|
||||
|
||||
if (blcptr->u == NULL)
|
||||
{
|
||||
free(blcptr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reply != NULL)
|
||||
{
|
||||
/* only accept 127.x.y.z as a listing */
|
||||
if (reply->addr.saddr.sa.sa_family == AF_INET &&
|
||||
!memcmp(&((struct sockaddr_in *)&reply->addr)->sin_addr, "\177", 1))
|
||||
listed++;
|
||||
else if (blcptr->blacklist->lastwarning + 3600 < CURRTIME)
|
||||
{
|
||||
slog(LG_DEBUG,
|
||||
"Garbage reply from blacklist %s",
|
||||
blcptr->blacklist->host);
|
||||
blcptr->blacklist->lastwarning = CURRTIME;
|
||||
}
|
||||
}
|
||||
|
||||
/* they have a blacklist entry for this client */
|
||||
if (listed)
|
||||
{
|
||||
dnsbl_hit(blcptr->u, blcptr->blacklist);
|
||||
return;
|
||||
}
|
||||
|
||||
l = dnsbl_queries(blcptr->u);
|
||||
mowgli_node_delete(&blcptr->node, l);
|
||||
|
||||
free(blcptr);
|
||||
}
|
||||
|
||||
/* XXX: no IPv6 implementation, not to concerned right now though. */
|
||||
static void initiate_blacklist_dnsquery(struct Blacklist *blptr, user_t *u)
|
||||
{
|
||||
struct BlacklistClient *blcptr = malloc(sizeof(struct BlacklistClient));
|
||||
char buf[IRCD_RES_HOSTLEN + 1];
|
||||
int ip[4];
|
||||
mowgli_list_t *l;
|
||||
|
||||
blcptr->blacklist = blptr;
|
||||
blcptr->u = u;
|
||||
|
||||
blcptr->dns_query.ptr = blcptr;
|
||||
blcptr->dns_query.callback = blacklist_dns_callback;
|
||||
|
||||
/* A sscanf worked fine for chary for many years, it'll be fine here */
|
||||
sscanf(u->ip, "%d.%d.%d.%d", &ip[3], &ip[2], &ip[1], &ip[0]);
|
||||
|
||||
/* becomes 2.0.0.127.torbl.ahbl.org or whatever */
|
||||
snprintf(buf, sizeof buf, "%d.%d.%d.%d.%s", ip[0], ip[1], ip[2], ip[3], blptr->host);
|
||||
|
||||
gethost_byname_type(buf, &blcptr->dns_query, T_A);
|
||||
|
||||
l = dnsbl_queries(u);
|
||||
mowgli_node_add(blcptr, &blcptr->node, l);
|
||||
blptr->refcount++;
|
||||
}
|
||||
|
||||
/* public interfaces */
|
||||
static struct Blacklist *new_blacklist(char *name)
|
||||
{
|
||||
struct Blacklist *blptr;
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
blptr = find_blacklist(name);
|
||||
|
||||
if (blptr == NULL)
|
||||
{
|
||||
blptr = malloc(sizeof(struct Blacklist));
|
||||
mowgli_node_add(blptr, mowgli_node_create(), &blacklist_list);
|
||||
}
|
||||
|
||||
mowgli_strlcpy(blptr->host, name, IRCD_RES_HOSTLEN + 1);
|
||||
blptr->lastwarning = 0;
|
||||
|
||||
return blptr;
|
||||
}
|
||||
|
||||
static void lookup_blacklists(user_t *u)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, blacklist_list.head)
|
||||
{
|
||||
struct Blacklist *blptr = (struct Blacklist *) n->data;
|
||||
blptr->status = 0;
|
||||
|
||||
if (u == NULL)
|
||||
return;
|
||||
|
||||
initiate_blacklist_dnsquery(blptr, u);
|
||||
}
|
||||
}
|
||||
|
||||
/* This appears to be unnecessary on Atheme and only causes crashes so #if 0
|
||||
* it out, at least for now. --jdhore
|
||||
*/
|
||||
#if 0
|
||||
static void abort_blacklist_queries(user_t *u)
|
||||
{
|
||||
mowgli_node_t *n, *tn;
|
||||
mowgli_list_t *l;
|
||||
struct BlacklistClient *blcptr;
|
||||
|
||||
if (u == NULL)
|
||||
return;
|
||||
|
||||
l = dnsbl_queries(u);
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, l->head)
|
||||
{
|
||||
blcptr = n->data;
|
||||
mowgli_node_delete(&blcptr->node, l);
|
||||
unref_blacklist(blcptr->blacklist);
|
||||
delete_resolver_queries(&blcptr->dns_query);
|
||||
free(blcptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void destroy_blacklists(void)
|
||||
{
|
||||
mowgli_node_t *n, *tn;
|
||||
struct Blacklist *blptr;
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, blacklist_list.head)
|
||||
{
|
||||
blptr = n->data;
|
||||
blptr->hits = 0; /* keep it simple and consistent */
|
||||
free(n->data);
|
||||
mowgli_node_delete(n, &blacklist_list);
|
||||
mowgli_node_free(n);
|
||||
}
|
||||
}
|
||||
|
||||
static int dnsbl_config_handler(mowgli_config_file_entry_t *ce)
|
||||
{
|
||||
mowgli_config_file_entry_t *cce;
|
||||
|
||||
MOWGLI_ITER_FOREACH(cce, ce->entries)
|
||||
{
|
||||
char *line = sstrdup(cce->varname);
|
||||
new_blacklist(line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dnsbl_config_purge(void *unused)
|
||||
{
|
||||
destroy_blacklists();
|
||||
}
|
||||
|
||||
static void check_dnsbls(hook_user_nick_t *data)
|
||||
{
|
||||
user_t *u = data->u;
|
||||
mowgli_node_t *n;
|
||||
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
|
||||
if (!action)
|
||||
return;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, dnsbl_elist.head)
|
||||
{
|
||||
dnsbl_exempt_t *de = n->data;
|
||||
|
||||
if (!irccasecmp(de->ip, u->ip))
|
||||
return;
|
||||
}
|
||||
|
||||
lookup_blacklists(u);
|
||||
}
|
||||
|
||||
static void dnsbl_hit(user_t *u, struct Blacklist *blptr)
|
||||
{
|
||||
service_t *svs;
|
||||
|
||||
svs = service_find("operserv");
|
||||
|
||||
if (!strcasecmp("SNOOP", action))
|
||||
{
|
||||
slog(LG_INFO, "DNSBL: \2%s\2!%s@%s [%s] is listed in DNS Blacklist %s.", u->nick, u->user, u->host, u->gecos, blptr->host);
|
||||
/* abort_blacklist_queries(u); */
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("NOTIFY", action))
|
||||
{
|
||||
slog(LG_INFO, "DNSBL: \2%s\2!%s@%s [%s] is listed in DNS Blacklist %s.", u->nick, u->user, u->host, u->gecos, blptr->host);
|
||||
notice(svs->nick, u->nick, "Your IP address %s is listed in DNS Blacklist %s", u->ip, blptr->host);
|
||||
/* abort_blacklist_queries(u); */
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("KLINE", action))
|
||||
{
|
||||
slog(LG_INFO, "DNSBL: k-lining \2%s\2!%s@%s [%s] who is listed in DNS Blacklist %s.", u->nick, u->user, u->host, u->gecos, blptr->host);
|
||||
/* abort_blacklist_queries(u); */
|
||||
notice(svs->nick, u->nick, "Your IP address %s is listed in DNS Blacklist %s", u->ip, blptr->host);
|
||||
kline_sts("*", "*", u->host, 86400, "Banned (DNS Blacklist)");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void osinfo_hook(sourceinfo_t *si)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
if (action)
|
||||
command_success_nodata(si, "Action taken when a user is an a DNSBL: %s", action);
|
||||
else
|
||||
command_success_nodata(si, "Action taken when a user is an a DNSBL: %s", "None");
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, blacklist_list.head)
|
||||
{
|
||||
struct Blacklist *blptr = (struct Blacklist *) n->data;
|
||||
|
||||
command_success_nodata(si, "Blacklist(s): %s", blptr->host);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_dnsbl_exempt_db(database_handle_t *db)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, dnsbl_elist.head)
|
||||
{
|
||||
dnsbl_exempt_t *de = n->data;
|
||||
|
||||
db_start_row(db, "BW");
|
||||
db_write_word(db, de->ip);
|
||||
db_write_time(db, de->exempt_ts);
|
||||
db_write_word(db, de->creator);
|
||||
db_write_word(db, de->reason);
|
||||
db_commit_row(db);
|
||||
}
|
||||
}
|
||||
|
||||
static void db_h_ble(database_handle_t *db, const char *type)
|
||||
{
|
||||
const char *ip = db_sread_word(db);
|
||||
time_t exempt_ts = db_sread_time(db);
|
||||
const char *creator = db_sread_word(db);
|
||||
const char *reason = db_sread_word(db);
|
||||
|
||||
dnsbl_exempt_t *de = smalloc(sizeof(dnsbl_exempt_t));
|
||||
|
||||
de->ip = sstrdup(ip);
|
||||
de->exempt_ts = exempt_ts;
|
||||
de->creator = sstrdup(creator);
|
||||
de->reason = sstrdup(reason);
|
||||
|
||||
mowgli_node_add(de, mowgli_node_create(), &dnsbl_elist);
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
MODULE_TRY_REQUEST_SYMBOL(m, os_set_cmdtree, "operserv/set", "os_set_cmdtree");
|
||||
|
||||
if (!module_find_published("backend/opensex"))
|
||||
{
|
||||
slog(LG_INFO, "Module %s requires use of the OpenSEX database backend, refusing to load.", m->name);
|
||||
m->mflags = MODTYPE_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
hook_add_db_write(write_dnsbl_exempt_db);
|
||||
|
||||
db_register_type_handler("BLE", db_h_ble);
|
||||
|
||||
service_named_bind_command("operserv", &os_dnsblexempt);
|
||||
service_named_bind_command("operserv", &os_dnsblscan);
|
||||
|
||||
hook_add_event("config_purge");
|
||||
hook_add_config_purge(dnsbl_config_purge);
|
||||
|
||||
hook_add_event("user_add");
|
||||
hook_add_user_add(check_dnsbls);
|
||||
|
||||
hook_add_event("operserv_info");
|
||||
hook_add_operserv_info(osinfo_hook);
|
||||
|
||||
add_dupstr_conf_item("dnsbl_action", &conf_gi_table, 0, &action, NULL);
|
||||
add_conf_item("BLACKLISTS", &conf_gi_table, dnsbl_config_handler);
|
||||
command_add(&os_set_dnsblaction, *os_set_cmdtree);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_db_write(write_dnsbl_exempt_db);
|
||||
hook_del_user_add(check_dnsbls);
|
||||
hook_del_config_purge(dnsbl_config_purge);
|
||||
hook_del_operserv_info(osinfo_hook);
|
||||
|
||||
db_unregister_type_handler("BLE");
|
||||
|
||||
del_conf_item("dnsbl_action", &conf_gi_table);
|
||||
del_conf_item("BLACKLISTS", &conf_gi_table);
|
||||
command_delete(&os_set_dnsblaction, *os_set_cmdtree);
|
||||
service_named_unbind_command("operserv", &os_dnsblexempt);
|
||||
service_named_unbind_command("operserv", &os_dnsblscan);
|
||||
}
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock <nenolod -at- nenolod.net>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* An echo server. (proof of concept for integrated XMLRPC HTTPD)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "datastream.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/gen_echoserver", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"William Pitcock <nenolod -at- nenolod.net>"
|
||||
);
|
||||
|
||||
connection_t *listener;
|
||||
|
||||
static int my_read(connection_t *cptr, char *buf)
|
||||
{
|
||||
int n;
|
||||
|
||||
if ((n = read(cptr->fd, buf, BUFSIZE)) > 0)
|
||||
{
|
||||
buf[n] = '\0';
|
||||
cnt.bin += n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void do_packet(connection_t *cptr, char *buf)
|
||||
{
|
||||
char *ptr, buf2[BUFSIZE * 2];
|
||||
static char tmp[BUFSIZE * 2 + 1];
|
||||
|
||||
while ((ptr = strchr(buf, '\n')))
|
||||
{
|
||||
snprintf(buf2, (BUFSIZE * 2), "%s%s", tmp, buf);
|
||||
*tmp = '\0';
|
||||
|
||||
slog(LG_DEBUG, "-{incoming}-> %s", buf2);
|
||||
sendq_add(cptr, buf2, strlen(buf2));
|
||||
|
||||
buf = ptr + 1;
|
||||
}
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
mowgli_strlcpy(tmp, buf, BUFSIZE * 2);
|
||||
tmp[BUFSIZE * 2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void my_rhandler(connection_t * cptr)
|
||||
{
|
||||
char buf[BUFSIZE * 2];
|
||||
|
||||
if (!my_read(cptr, buf))
|
||||
connection_close(cptr);
|
||||
|
||||
do_packet(cptr, buf);
|
||||
}
|
||||
|
||||
static void do_listen(connection_t *cptr)
|
||||
{
|
||||
connection_t *newptr;
|
||||
newptr = connection_accept_tcp(cptr, my_rhandler, NULL);
|
||||
slog(LG_DEBUG, "do_listen(): accepted %d", cptr->fd);
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
listener = connection_open_listener_tcp("127.0.0.1", 7100, do_listen);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
connection_close(listener);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock <nenolod -at- nenolod.net>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Listener code demo.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "datastream.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/gen_listenerdemo", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"William Pitcock <nenolod -at- nenolod.net>"
|
||||
);
|
||||
|
||||
connection_t *listener;
|
||||
|
||||
static int my_read(connection_t * cptr, char *buf)
|
||||
{
|
||||
int n;
|
||||
|
||||
if ((n = read(cptr->fd, buf, BUFSIZE)) > 0)
|
||||
{
|
||||
buf[n] = '\0';
|
||||
cnt.bin += n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void do_packet(char *buf)
|
||||
{
|
||||
char *ptr, buf2[BUFSIZE * 2];
|
||||
static char tmp[BUFSIZE * 2 + 1];
|
||||
|
||||
while ((ptr = strchr(buf, '\n')))
|
||||
{
|
||||
*ptr = '\0';
|
||||
|
||||
if (ptr != buf && *(ptr - 1) == '\r')
|
||||
*(ptr - 1) = '\0';
|
||||
|
||||
snprintf(buf2, (BUFSIZE * 2), "%s%s", tmp, buf);
|
||||
*tmp = '\0';
|
||||
|
||||
slog(LG_DEBUG, "-{incoming}-> %s", buf2);
|
||||
|
||||
buf = ptr + 1;
|
||||
}
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
mowgli_strlcpy(tmp, buf, BUFSIZE * 2);
|
||||
tmp[BUFSIZE * 2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static void my_rhandler(connection_t * cptr)
|
||||
{
|
||||
char buf[BUFSIZE * 2];
|
||||
|
||||
if (!my_read(cptr, buf))
|
||||
connection_close(cptr);
|
||||
|
||||
do_packet(buf);
|
||||
}
|
||||
|
||||
static void do_listen(connection_t *cptr)
|
||||
{
|
||||
connection_t *newptr;
|
||||
newptr = connection_accept_tcp(cptr, my_rhandler, NULL);
|
||||
slog(LG_DEBUG, "do_listen(): accepted %d", cptr->fd);
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
listener = connection_open_listener_tcp("127.0.0.1", 7100, do_listen);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
connection_close(listener);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2006 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Sets usercloak metadata on register.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/gen_vhostonreg", false, _modinit, _moddeinit,
|
||||
"$Revision: 7785 $",
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
/* allow us-ascii letters, digits and the following characters */
|
||||
#define VALID_SPECIALS "-"
|
||||
|
||||
static int counter;
|
||||
|
||||
static void handle_verify_register(hook_user_req_t *req);
|
||||
static void hook_user_identify(user_t *u);
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("user_verify_register");
|
||||
hook_add_user_verify_register(handle_verify_register);
|
||||
hook_add_event("user_identify");
|
||||
hook_add_user_identify(hook_user_identify);
|
||||
counter = (CURRTIME << 8) % 100000;
|
||||
if (counter < 0)
|
||||
counter += 100000;
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_verify_register(handle_verify_register);
|
||||
hook_del_user_identify(hook_user_identify);
|
||||
}
|
||||
|
||||
static void user_add_host(myuser_t *mu)
|
||||
{
|
||||
int maxlen1, i;
|
||||
char newhost[HOSTLEN];
|
||||
const char *p;
|
||||
bool invalidchar = false;
|
||||
|
||||
maxlen1 = HOSTLEN - 2 - strlen(me.hidehostsuffix);
|
||||
if (maxlen1 < 9)
|
||||
return;
|
||||
p = entity(mu)->name;
|
||||
i = 0;
|
||||
while (i < maxlen1 && *p != '\0')
|
||||
{
|
||||
if (isalnum(*p) || strchr(VALID_SPECIALS, *p))
|
||||
newhost[i++] = *p;
|
||||
else
|
||||
invalidchar = true;
|
||||
p++;
|
||||
}
|
||||
if (invalidchar || *p != '\0')
|
||||
{
|
||||
if (i > maxlen1 - 6)
|
||||
i = maxlen1 - 6;
|
||||
snprintf(newhost + i, sizeof newhost - i, "-%05d", counter);
|
||||
counter++;
|
||||
if (counter >= 100000)
|
||||
counter = 0;
|
||||
if (nicksvs.me != NULL)
|
||||
{
|
||||
myuser_notice(nicksvs.nick, mu, "Your account name cannot be used in a vhost directly. To ensure uniqueness, a number was added.");
|
||||
myuser_notice(nicksvs.nick, mu, "To avoid this, register an account name containing only letters, digits and %s.", VALID_SPECIALS);
|
||||
if (!nicksvs.no_nick_ownership && command_find(nicksvs.me->commands, "GROUP"))
|
||||
myuser_notice(nicksvs.nick, mu, "If you drop %s you can group it to your new account.", entity(mu)->name);
|
||||
}
|
||||
}
|
||||
else
|
||||
newhost[i] = '\0';
|
||||
mowgli_strlcat(newhost, ".", sizeof newhost);
|
||||
mowgli_strlcat(newhost, me.hidehostsuffix, sizeof newhost);
|
||||
|
||||
metadata_add(mu, "private:usercloak", newhost);
|
||||
}
|
||||
|
||||
static void handle_verify_register(hook_user_req_t *req)
|
||||
{
|
||||
myuser_t *mu = req->mu;
|
||||
mowgli_node_t *n;
|
||||
user_t *u;
|
||||
|
||||
if (me.hidehostsuffix == NULL)
|
||||
return;
|
||||
|
||||
user_add_host(mu);
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, mu->logins.head)
|
||||
{
|
||||
u = n->data;
|
||||
hook_call_user_identify(u); /* XXX */
|
||||
}
|
||||
}
|
||||
|
||||
static void hook_user_identify(user_t *u)
|
||||
{
|
||||
/* if they have an existing cloak, don't do anything */
|
||||
if ((metadata_find(u->myuser, "private:usercloak")) || (me.hidehostsuffix == NULL))
|
||||
return;
|
||||
|
||||
/* they do not, add one. */
|
||||
user_add_host(u->myuser);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2007 William Pitcock
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Creates a .dot file for use with neato which displays
|
||||
* user->channel relationships.
|
||||
*
|
||||
* == How to generate the graphs and How It Works ==
|
||||
* Graphtastical creates a .dot file for graphviz's neato
|
||||
* filter to use. The DOT language describes a graph's
|
||||
* structure to graphviz in an opaque way.
|
||||
*
|
||||
* Because Graphviz nodes use unique identifiers for
|
||||
* interconnection, the channels.dot file contains also
|
||||
* information about social networks.
|
||||
*
|
||||
* Eventually Graphtastical will dump other graph datafiles
|
||||
* too.
|
||||
*
|
||||
* To make a file from the data dumped by Graphtastical,
|
||||
* the following commands will do:
|
||||
*
|
||||
* $ cat channels.dot | neato -Tgif -o map-channels.gif
|
||||
* $ cat channels.dot | neato -Tsvg -o map-channels.svg
|
||||
*
|
||||
* Some maps (for larger networks) are going to be large,
|
||||
* so you may want to provide links to both the GIF and
|
||||
* SVG files as some people may only be able to make use of
|
||||
* one or the other. Why that is, I'm not sure, and I'm not
|
||||
* covering it here.
|
||||
*
|
||||
* == Privacy concerns ==
|
||||
* If you are running Graphtastical on a network that has
|
||||
* privacy concerns; you probably shouldn't.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/graphtastical", true, _modinit, NULL,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static mowgli_eventloop_timer_t *channels_timer = NULL;
|
||||
static mowgli_eventloop_timer_t *uchannels_timer = NULL;
|
||||
|
||||
/* write channels.dot */
|
||||
static void write_channels_dot_file(void *arg)
|
||||
{
|
||||
mychan_t *mc;
|
||||
chanacs_t *ca;
|
||||
mowgli_node_t *tn;
|
||||
FILE *f;
|
||||
int errno1, was_errored = 0;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
int root = 1;
|
||||
mychan_t *pmc;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* write to a temporary file first */
|
||||
if (!(f = fopen(DATADIR "/channels.dot.new", "w")))
|
||||
{
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "graphtastical: cannot create channels.dot.new: %s", strerror(errno1));
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f, "graph channels {\n");
|
||||
fprintf(f, "edge [color=blue len=7.5 fontname=\"Verdana\" fontsize=8]\n");
|
||||
fprintf(f, "node [fontname=\"Verdana\" fontsize=8]\n");
|
||||
|
||||
slog(LG_DEBUG, "graphtastical: dumping mychans");
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(mc, &state, mclist)
|
||||
{
|
||||
fprintf(f, "\"%s\"", mc->name);
|
||||
|
||||
if (!root)
|
||||
fprintf(f, "-- \"%s\"", pmc->name);
|
||||
|
||||
pmc = mc;
|
||||
|
||||
fprintf(f, "[fontname=\"Verdana\" fontsize=8]\n");
|
||||
|
||||
MOWGLI_ITER_FOREACH(tn, mc->chanacs.head)
|
||||
{
|
||||
ca = (chanacs_t *)tn->data;
|
||||
|
||||
if (ca->level & CA_AKICK)
|
||||
continue;
|
||||
|
||||
fprintf(f, "\"%s\" -- \"%s\" [fontname=\"Verdana\" fontsize=8]\n", ca->entity ? ca->entity->name : ca->host, mc->name);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
|
||||
was_errored = ferror(f);
|
||||
was_errored |= fclose(f);
|
||||
if (was_errored)
|
||||
{
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "graphtastical: cannot write to channels.dot.new: %s", strerror(errno1));
|
||||
return;
|
||||
}
|
||||
|
||||
/* now, replace the old database with the new one, using an atomic rename */
|
||||
if ((srename(DATADIR "/channels.dot.new", DATADIR "/channels.dot")) < 0)
|
||||
{
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "graphtastical: cannot rename channels.dot.new to channels.dot: %s", strerror(errno1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* write uchannels.dot */
|
||||
static void write_uchannels_dot_file(void *arg)
|
||||
{
|
||||
channel_t *c;
|
||||
chanuser_t *cu;
|
||||
mowgli_node_t *tn;
|
||||
FILE *f;
|
||||
int errno1, was_errored = 0;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* write to a temporary file first */
|
||||
if (!(f = fopen(DATADIR "/uchannels.dot.new", "w")))
|
||||
{
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "graphtastical: cannot create channels.dot.new: %s", strerror(errno1));
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(f, "graph uchannels {\n");
|
||||
fprintf(f, "edge [color=blue len=7.5 fontname=\"Verdana\" fontsize=8]\n");
|
||||
fprintf(f, "node [fontname=\"Verdana\" fontsize=8]\n");
|
||||
|
||||
slog(LG_DEBUG, "graphtastical: dumping chans");
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(c, &state, chanlist)
|
||||
{
|
||||
fprintf(f, "\"%s\"", c->name);
|
||||
|
||||
fprintf(f, "[fontname=\"Verdana\" fontsize=8]\n");
|
||||
|
||||
MOWGLI_ITER_FOREACH(tn, c->members.head)
|
||||
{
|
||||
cu = (chanuser_t *)tn->data;
|
||||
|
||||
fprintf(f, "\"%s\" -- \"%s\" [fontname=\"Verdana\" fontsize=8]\n", cu->user->nick, c->name);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(f, "}\n");
|
||||
|
||||
was_errored = ferror(f);
|
||||
was_errored |= fclose(f);
|
||||
if (was_errored)
|
||||
{
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "graphtastical: cannot write to uchannels.dot.new: %s", strerror(errno1));
|
||||
return;
|
||||
}
|
||||
|
||||
/* now, replace the old database with the new one, using an atomic rename */
|
||||
if ((srename(DATADIR "/uchannels.dot.new", DATADIR "/uchannels.dot")) < 0)
|
||||
{
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "graphtastical: cannot rename uchannels.dot.new to uchannels.dot: %s", strerror(errno1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
write_channels_dot_file(NULL);
|
||||
write_uchannels_dot_file(NULL);
|
||||
|
||||
channels_timer = mowgli_timer_add(base_eventloop, "write_channels_dot_file", write_channels_dot_file, NULL, 60);
|
||||
uchannels_timer = mowgli_timer_add(base_eventloop, "write_uchannels_dot_file", write_uchannels_dot_file, NULL, 60);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
mowgli_timer_destroy(base_eventloop, channels_timer);
|
||||
mowgli_timer_destroy(base_eventloop, uchannels_timer);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2006 William Pitcock <nenolod@nenolod.net> et al
|
||||
* Rights to this code are documented in doc/LICENSE.
|
||||
*
|
||||
* Russian Roulette game. Will actually /KILL the user that gets "shot".
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/gs_roulette", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void command_roulette(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cmd_roulette = { "ROULETTE", N_("A game of Russian Roulette."), AC_NONE, 0, command_roulette, { .path = "contrib/roulette" } };
|
||||
|
||||
void _modinit(module_t * m)
|
||||
{
|
||||
service_named_bind_command("gameserv", &cmd_roulette);
|
||||
|
||||
service_named_bind_command("chanserv", &cmd_roulette);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("gameserv", &cmd_roulette);
|
||||
|
||||
service_named_unbind_command("chanserv", &cmd_roulette);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle reporting for both fantasy commands and normal commands in GameServ
|
||||
* quickly and easily. Of course, sourceinfo has a vtable that can be manipulated,
|
||||
* but this is quicker and easier... -- nenolod
|
||||
*/
|
||||
static void gs_command_report(sourceinfo_t *si, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[BUFSIZE];
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, BUFSIZE, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (si->c != NULL)
|
||||
msg(chansvs.nick, si->c->name, "%s", buf);
|
||||
else
|
||||
command_success_nodata(si, "%s", buf);
|
||||
|
||||
if (!strcasecmp(buf, "*BANG*"))
|
||||
kill_user(si->service->me, si->su, "Lost at Russian Roulette.");
|
||||
}
|
||||
|
||||
static void command_roulette(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
static const char *roulette_responses[2] = {
|
||||
N_("*BANG*"),
|
||||
N_("*CLICK*")
|
||||
};
|
||||
|
||||
srand(time(NULL));
|
||||
gs_command_report(si, "%s", roulette_responses[rand() % 6 == 0]);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
* Copyright (c) 2005 Atheme Development Group
|
||||
* Rights to this code are documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains the main() routine.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ircd_announceserv", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"JD and Taros"
|
||||
);
|
||||
|
||||
service_t *announcesvs;
|
||||
|
||||
static void as_cmd_help(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void account_drop_request(myuser_t *mu);
|
||||
static void as_cmd_request(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void as_cmd_waiting(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void as_cmd_reject(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void as_cmd_activate(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void as_cmd_cancel(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void write_asreqdb(database_handle_t *db);
|
||||
static void db_h_ar(database_handle_t *db, const char *type);
|
||||
|
||||
command_t as_help = { "HELP", N_(N_("Displays contextual help information.")), AC_NONE, 2, as_cmd_help, { .path = "help/help" } };
|
||||
command_t as_request = { "REQUEST", N_("Requests new announcement."), AC_AUTHENTICATED, 2, as_cmd_request, { .path = "contrib/as_request" } };
|
||||
command_t as_waiting = { "WAITING", N_("Lists announcements currently waiting for activation."), PRIV_GLOBAL, 1, as_cmd_waiting, { .path = "contrib/as_waiting" } };
|
||||
command_t as_reject = { "REJECT", N_("Reject the requested announcement for the given nick."), PRIV_GLOBAL, 2, as_cmd_reject, { .path = "contrib/as_reject" } };
|
||||
command_t as_activate = { "ACTIVATE", N_("Activate the requested announcement for a given nick."), PRIV_GLOBAL, 2, as_cmd_activate, { .path = "contrib/as_activate" } };
|
||||
command_t as_cancel = { "CANCEL", N_("Cancels your requested announcement."), AC_AUTHENTICATED, 0, as_cmd_cancel, { .path = "contrib/as_cancel" } };
|
||||
|
||||
struct asreq_ {
|
||||
char *nick;
|
||||
char *subject;
|
||||
time_t announce_ts;
|
||||
char *creator;
|
||||
char *text;
|
||||
};
|
||||
|
||||
typedef struct asreq_ asreq_t;
|
||||
|
||||
mowgli_list_t as_reqlist;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
announcesvs = service_add("announceserv", NULL);
|
||||
|
||||
hook_add_event("user_drop");
|
||||
hook_add_user_drop(account_drop_request);
|
||||
|
||||
hook_add_db_write(write_asreqdb);
|
||||
db_register_type_handler("AR", db_h_ar);
|
||||
|
||||
if (announcesvs == NULL)
|
||||
return;
|
||||
|
||||
service_bind_command(announcesvs, &as_help);
|
||||
service_bind_command(announcesvs, &as_request);
|
||||
service_bind_command(announcesvs, &as_waiting);
|
||||
service_bind_command(announcesvs, &as_reject);
|
||||
service_bind_command(announcesvs, &as_activate);
|
||||
service_bind_command(announcesvs, &as_cancel);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_drop(account_drop_request);
|
||||
hook_del_db_write(write_asreqdb);
|
||||
db_unregister_type_handler("AR");
|
||||
|
||||
if (announcesvs != NULL)
|
||||
{
|
||||
service_unbind_command(announcesvs, &as_help);
|
||||
service_unbind_command(announcesvs, &as_request);
|
||||
service_unbind_command(announcesvs, &as_waiting);
|
||||
service_unbind_command(announcesvs, &as_reject);
|
||||
service_unbind_command(announcesvs, &as_activate);
|
||||
service_unbind_command(announcesvs, &as_cancel);
|
||||
|
||||
service_delete(announcesvs);
|
||||
announcesvs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void write_asreqdb(database_handle_t *db)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
asreq_t *l = n->data;
|
||||
|
||||
db_start_row(db, "AR");
|
||||
db_write_word(db, l->nick);
|
||||
db_write_word(db, l->subject);
|
||||
db_write_time(db, l->announce_ts);
|
||||
db_write_word(db, l->creator);
|
||||
db_write_str(db, l->text);
|
||||
db_commit_row(db);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void db_h_ar(database_handle_t *db, const char *type)
|
||||
{
|
||||
const char *nick = db_sread_word(db);
|
||||
const char *subject = db_sread_word(db);
|
||||
time_t announce_ts = db_sread_time(db);
|
||||
const char *creator = db_sread_word(db);
|
||||
const char *text = db_sread_str(db);
|
||||
|
||||
asreq_t *l = smalloc(sizeof(asreq_t));
|
||||
l->nick = strshare_get(nick);
|
||||
l->creator = strshare_get(creator);
|
||||
l->subject = sstrdup(subject);
|
||||
l->announce_ts = announce_ts;
|
||||
l->text = sstrdup(text);
|
||||
mowgli_node_add(l, mowgli_node_create(), &as_reqlist);
|
||||
}
|
||||
|
||||
/* Properly remove announcement requests from the DB if an account is dropped */
|
||||
static void account_drop_request(myuser_t *mu)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
asreq_t *l;
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
if (!irccasecmp(l->nick, entity(mu)->name))
|
||||
{
|
||||
slog(LG_REGISTER, "ANNOUNCEREQ:DROPACCOUNT: \2%s\2 %s\2", l->nick, l->text);
|
||||
|
||||
mowgli_node_delete(n, &as_reqlist);
|
||||
|
||||
strshare_unref(l->nick);
|
||||
strshare_unref(l->creator);
|
||||
free(l->subject);
|
||||
free(l->text);
|
||||
free(l);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* HELP <command> [params] */
|
||||
void as_cmd_help(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *command = parv[0];
|
||||
|
||||
if (!command)
|
||||
{
|
||||
command_success_nodata(si, _("***** \2%s Help\2 *****"), si->service->nick);
|
||||
command_success_nodata(si, _("\2%s\2 allows users to request a network announcement."), si->service->nick);
|
||||
command_success_nodata(si, " ");
|
||||
command_success_nodata(si, _("For more information on a command, type:"));
|
||||
command_success_nodata(si, "\2/%s%s help <command>\2", (ircd->uses_rcommand == false) ? "msg " : "", si->service->disp);
|
||||
command_success_nodata(si, " ");
|
||||
|
||||
command_help(si, si->service->commands);
|
||||
|
||||
command_success_nodata(si, _("***** \2End of Help\2 *****"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* take the command through the hash table */
|
||||
help_display(si, si->service, command, si->service->commands);
|
||||
}
|
||||
|
||||
static void as_cmd_request(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *subject = parv[0];
|
||||
char *text = parv[1];
|
||||
char *target;
|
||||
char *subject2;
|
||||
char buf [BUFSIZE];
|
||||
mowgli_node_t *n;
|
||||
asreq_t *l;
|
||||
|
||||
if (!text || !subject)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "REQUEST");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: REQUEST <subject> <text>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadata_find(si->smu, "private:restrict:setter"))
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You have been restricted from requesting announcements by network staff."));
|
||||
return;
|
||||
}
|
||||
|
||||
target = entity(si->smu)->name;
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
if (!irccasecmp(l->nick, target))
|
||||
{
|
||||
command_fail(si, fault_badparams, _("You cannot request more than one announcement. Use CANCEL if you wish to cancel your current announcement and submit another."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the subject for being too long as well. 35 chars is probably a safe limit here.
|
||||
* Used here because we don't want users that don't know any better making too-long messages.
|
||||
*/
|
||||
if (strlen(subject) > 35)
|
||||
{
|
||||
command_fail(si, fault_badparams, _("Your subject is too long. Subjects need to be under 35 characters."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the announcement is too long or not. 450 characters is safe for our usecase */
|
||||
if (strlen(text) > 450)
|
||||
{
|
||||
command_fail(si, fault_badparams, _("Your announcement is too long. Announcements need to be under 450 characters."));
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, BUFSIZE, "%s", text);
|
||||
|
||||
l = smalloc(sizeof(asreq_t));
|
||||
l->nick = strshare_ref(target);
|
||||
l->subject = sstrdup(subject);
|
||||
l->announce_ts = CURRTIME;;
|
||||
l->creator = strshare_ref(target);
|
||||
l->text = sstrdup(buf);
|
||||
|
||||
n = mowgli_node_create();
|
||||
mowgli_node_add(l, n, &as_reqlist);
|
||||
|
||||
subject2 = sstrdup(l->subject);
|
||||
/* This doesn't need to be as efficient as InfoServ, so let's just use replace() */
|
||||
replace(subject2, BUFSIZE, "_", " ");
|
||||
|
||||
command_success_nodata(si, _("You have requested the following announcement: "));
|
||||
command_success_nodata(si, _("[%s - %s] %s"), subject2, l->creator, buf);
|
||||
/* This is kind of hacky, and the slog will come from operserv, not announceserv.
|
||||
* Still, it's required so the message will cut off properly, and I can't find a less hacky way to do it. */
|
||||
logcommand(si, CMDLOG_REQUEST, "REQUEST:");
|
||||
slog(CMDLOG_REQUEST, "[%s - %s] %s", subject2, l->creator, buf);
|
||||
free(subject2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void as_cmd_activate(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *nick = parv[0];
|
||||
user_t *u;
|
||||
char *subject2;
|
||||
char buf[BUFSIZE];
|
||||
asreq_t *l;
|
||||
mowgli_node_t *n;
|
||||
|
||||
if (!nick)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ACTIVATE");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: ACTIVATE <nick>"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
if (!irccasecmp(l->nick, nick))
|
||||
{
|
||||
if ((u = user_find_named(nick)) != NULL)
|
||||
notice(si->service->nick, u->nick, "[auto memo] Your requested announcement has been approved.");
|
||||
subject2 = sstrdup(l->subject);
|
||||
replace(subject2, BUFSIZE, "_", " ");
|
||||
logcommand(si, CMDLOG_REQUEST, "ACTIVATE: \2%s\2", nick);
|
||||
snprintf(buf, BUFSIZE, "[%s - %s] %s", subject2, l->creator, l->text);
|
||||
|
||||
mowgli_node_delete(n, &as_reqlist);
|
||||
|
||||
free(subject2);
|
||||
free(l->nick);
|
||||
free(l->subject);
|
||||
free(l->creator);
|
||||
free(l->text);
|
||||
free(l);
|
||||
|
||||
notice_global_sts(si->service->me, "*", buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
command_success_nodata(si, _("Nick \2%s\2 not found in announce request database."), nick);
|
||||
}
|
||||
|
||||
static void as_cmd_reject(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *nick = parv[0];
|
||||
user_t *u;
|
||||
asreq_t *l;
|
||||
mowgli_node_t *n;
|
||||
|
||||
if (!nick)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "REJECT");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: REJECT <nick>"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
if (!irccasecmp(l->nick, nick))
|
||||
{
|
||||
if ((u = user_find_named(nick)) != NULL)
|
||||
notice(si->service->nick, u->nick, "[auto memo] Your requested announcement has been rejected.");
|
||||
logcommand(si, CMDLOG_REQUEST, "REJECT: \2%s\2", nick);
|
||||
|
||||
mowgli_node_delete(n, &as_reqlist);
|
||||
free(l->nick);
|
||||
free(l->subject);
|
||||
free(l->creator);
|
||||
free(l->text);
|
||||
free(l);
|
||||
return;
|
||||
}
|
||||
}
|
||||
command_success_nodata(si, _("Nick \2%s\2 not found in announcement request database."), nick);
|
||||
}
|
||||
|
||||
static void as_cmd_waiting(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
asreq_t *l;
|
||||
mowgli_node_t *n;
|
||||
char *subject2;
|
||||
char buf[BUFSIZE];
|
||||
struct tm tm;
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
tm = *localtime(&l->announce_ts);
|
||||
strftime(buf, BUFSIZE, TIME_FORMAT, &tm);
|
||||
subject2 = sstrdup(l->subject);
|
||||
replace(subject2, BUFSIZE, "_", " ");
|
||||
/* This needs to be two lines for cutoff purposes */
|
||||
command_success_nodata(si, "Account:\2%s\2, Subject: %s, Requested On: \2%s\2, Announcement:",
|
||||
l->nick, subject2, buf);
|
||||
command_success_nodata(si, "%s", l->text);
|
||||
free(subject2);
|
||||
}
|
||||
command_success_nodata(si, "End of list.");
|
||||
logcommand(si, CMDLOG_GET, "WAITING");
|
||||
}
|
||||
|
||||
static void as_cmd_cancel(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
asreq_t *l;
|
||||
mowgli_node_t *n;
|
||||
char *target;
|
||||
|
||||
target = entity(si->smu)->name;
|
||||
|
||||
MOWGLI_LIST_FOREACH(n, as_reqlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
if (!irccasecmp(l->nick, target))
|
||||
{
|
||||
mowgli_node_delete(n, &as_reqlist);
|
||||
|
||||
strshare_unref(l->nick);
|
||||
strshare_unref(l->creator);
|
||||
free(l->subject);
|
||||
free(l->text);
|
||||
free(l);
|
||||
|
||||
command_success_nodata(si, "Your pending announcement has been canceled.");
|
||||
|
||||
logcommand(si, CMDLOG_REQUEST, "CANCEL");
|
||||
return;
|
||||
}
|
||||
}
|
||||
command_fail(si, fault_badparams, _("You do not have a pending announcement to cancel."));
|
||||
}
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock, et al.
|
||||
* The rights to this code are as documented under doc/LICENSE.
|
||||
*
|
||||
* Meow!
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ircd_catserv", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
service_t *catserv;
|
||||
|
||||
static void catserv_cmd_meow(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void catserv_cmd_help(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t catserv_meow = { "MEOW", "Makes the cute little kitty-cat meow!",
|
||||
AC_NONE, 0, catserv_cmd_meow, { .path = "" } };
|
||||
command_t catserv_help = { "HELP", "Displays contextual help information.",
|
||||
AC_NONE, 1, catserv_cmd_help, { .path = "help" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
catserv = service_add("catserv", NULL);
|
||||
|
||||
service_bind_command(catserv, &catserv_meow);
|
||||
service_bind_command(catserv, &catserv_help);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_unbind_command(catserv, &catserv_meow);
|
||||
service_unbind_command(catserv, &catserv_help);
|
||||
|
||||
service_delete(catserv);
|
||||
}
|
||||
|
||||
static void catserv_cmd_meow(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
command_success_nodata(si, "Meow!");
|
||||
}
|
||||
|
||||
static void catserv_cmd_help(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
command_help(si, si->service->commands);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Copyright (c) 2006 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* LoveServ implementation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ircd_loveserv", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
service_t *loveserv;
|
||||
|
||||
static void _ls_admirer(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ADMIRER");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: ADMIRER <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "%s has been told that they have a secret admirer. :)", target);
|
||||
notice(loveserv->nick, target, "You have a secret admirer ;)");
|
||||
}
|
||||
|
||||
command_t ls_admirer = { "ADMIRER", "Tell somebody they have a secret admirer.", AC_NONE, 1, _ls_admirer, { .path = "" } };
|
||||
|
||||
static void _ls_rose(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "ROSE");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: ROSE <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your rose has been sent to %s! :)", target);
|
||||
notice(loveserv->nick, target, "%s has sent you a pretty rose: \00303--<--<--<{\00304@", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_rose = { "ROSE", "Sends a rose to somebody.", AC_NONE, 1, _ls_rose, { .path = "" } };
|
||||
|
||||
static void _ls_chocolate(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "CHOCOLATE");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: CHOCOLATE <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your chocolates have been sent to %s! :)", target);
|
||||
notice(loveserv->nick, target, "%s would like you to have this YUMMY box of chocolates.", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_chocolate = { "CHOCOLATE", "Sends chocolates to somebody.", AC_NONE, 1, _ls_chocolate, { .path = "" } };
|
||||
|
||||
static void _ls_candy(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "CANDY");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: CANDY <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your bag of candy has been sent to %s! :)", target);
|
||||
notice(loveserv->nick, target, "%s would like you to have this bag of heart-shaped candies.", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_candy = { "CANDY", "Sends a bag of candy to somebody.", AC_NONE, 1, _ls_candy, { .path = "" } };
|
||||
|
||||
static void _ls_hug(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "HUG");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: HUG <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "You have virtually hugged %s!", target);
|
||||
notice(loveserv->nick, target, "%s has sent you a \002BIG WARM HUG\002.", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_hug = { "HUG", "Reach out and hug somebody.", AC_NONE, 1, _ls_hug, { .path = "" } };
|
||||
|
||||
static void _ls_kiss(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "KISS");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: KISS <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "You have virtually kissed %s!", target);
|
||||
notice(loveserv->nick, target, "%s has sent you a \00304kiss\003.", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_kiss = { "KISS", "Kiss somebody.", AC_NONE, 1, _ls_kiss, { .path = "" } };
|
||||
|
||||
static void _ls_lovenote(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
char *note = parv[1];
|
||||
|
||||
if (!target || !note)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "LOVENOTE");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: LOVENOTE <target> <message>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your love-note to %s has been sent.", target);
|
||||
notice(loveserv->nick, target, "%s has sent you a love-note which reads: %s", si->su->nick, note);
|
||||
}
|
||||
|
||||
command_t ls_lovenote = { "LOVENOTE", "Sends a lovenote to somebody.", AC_NONE, 2, _ls_lovenote, { .path = "" } };
|
||||
|
||||
static void _ls_apology(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
char *note = parv[1];
|
||||
|
||||
if (!target || !note)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "APOLOGY");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: APOLOGY <target> <message>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your apology to %s has been sent.", target);
|
||||
notice(loveserv->nick, target, "%s would like to apologize for: %s", si->su->nick, note);
|
||||
}
|
||||
|
||||
command_t ls_apology = { "APOLOGY", "Sends an apology to somebody.", AC_NONE, 2, _ls_apology, { .path = "" } };
|
||||
|
||||
static void _ls_thankyou(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
char *note = parv[1];
|
||||
|
||||
if (!target || !note)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "THANKYOU");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: THANKYOU <target> <message>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your thank-you note to %s has been sent.", target);
|
||||
notice(loveserv->nick, target, "%s would like to thank you for: %s", si->su->nick, note);
|
||||
}
|
||||
|
||||
command_t ls_thankyou = { "THANKYOU", "Sends a thank-you note to somebody.", AC_NONE, 2, _ls_thankyou, { .path = "" } };
|
||||
|
||||
static void _ls_spank(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "SPANK");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: SPANK <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "You have virtually spanked %s!", target);
|
||||
notice(loveserv->nick, target, "%s has given you a virtual playful spanking.", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_spank = { "SPANK", "Gives somebody a spanking.", AC_NONE, 1, _ls_spank, { .path = "" } };
|
||||
|
||||
static void _ls_chocobo(sourceinfo_t *si, int parc, char *parv[]) /* silly */
|
||||
{
|
||||
char *target = parv[0];
|
||||
|
||||
if (!target)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "CHOCOBO");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: CHOCOBO <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user_find_named(target))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "As much as I'd love to do this, you need to specify a person who really exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Your chocobo has been sent to %s.", target);
|
||||
notice(loveserv->nick, target, "%s would like you to have this chocobo. \00308Kweh!\003", si->su->nick);
|
||||
}
|
||||
|
||||
command_t ls_chocobo = { "CHOCOBO", "Sends a chocobo to somebody.", AC_NONE, 1, _ls_chocobo, { .path = "" } };
|
||||
|
||||
static void _ls_help(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
command_help(si, si->service->commands);
|
||||
}
|
||||
|
||||
command_t ls_help = { "HELP", "Displays contextual help information.",
|
||||
AC_NONE, 1, _ls_help, { .path = "help" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
loveserv = service_add("LoveServ", NULL);
|
||||
|
||||
service_bind_command(loveserv, &ls_admirer);
|
||||
service_bind_command(loveserv, &ls_rose);
|
||||
service_bind_command(loveserv, &ls_chocolate);
|
||||
service_bind_command(loveserv, &ls_candy);
|
||||
service_bind_command(loveserv, &ls_hug);
|
||||
service_bind_command(loveserv, &ls_kiss);
|
||||
service_bind_command(loveserv, &ls_lovenote);
|
||||
service_bind_command(loveserv, &ls_apology);
|
||||
service_bind_command(loveserv, &ls_thankyou);
|
||||
service_bind_command(loveserv, &ls_spank);
|
||||
service_bind_command(loveserv, &ls_chocobo);
|
||||
service_bind_command(loveserv, &ls_help);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_unbind_command(loveserv, &ls_admirer);
|
||||
service_unbind_command(loveserv, &ls_rose);
|
||||
service_unbind_command(loveserv, &ls_chocolate);
|
||||
service_unbind_command(loveserv, &ls_candy);
|
||||
service_unbind_command(loveserv, &ls_hug);
|
||||
service_unbind_command(loveserv, &ls_kiss);
|
||||
service_unbind_command(loveserv, &ls_lovenote);
|
||||
service_unbind_command(loveserv, &ls_apology);
|
||||
service_unbind_command(loveserv, &ls_thankyou);
|
||||
service_unbind_command(loveserv, &ls_spank);
|
||||
service_unbind_command(loveserv, &ls_chocobo);
|
||||
service_unbind_command(loveserv, &ls_help);
|
||||
|
||||
if (loveserv)
|
||||
service_delete(loveserv);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2005 Atheme Development Group
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* IRCServices's weird password encryption thingy, taken from Anope 1.6.3.
|
||||
*
|
||||
*/
|
||||
/* Include file for high-level encryption routines.
|
||||
*
|
||||
* (C) 2003 Anope Team
|
||||
* Contact us at info@anope.org
|
||||
*
|
||||
* Please read COPYING and README for furhter details.
|
||||
*
|
||||
* Based on the original code of Epona by Lara.
|
||||
* Based on the original code of Services by Andy Church.
|
||||
*
|
||||
* $\Id: myencrypt.c 5 2004-03-29 01:29:50Z dane $
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
// Record password transition log?
|
||||
// #define PW_TRANSITION_LOG "./pwtransition.sh"
|
||||
|
||||
/* necessary anope defines */
|
||||
#define PASSMAX 32
|
||||
#define ENCRYPT_MD5
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
/******** Our own high-level routines. ********/
|
||||
|
||||
|
||||
#define XTOI(c) ((c)>9 ? (c)-'A'+10 : (c)-'0')
|
||||
/* Result of this:
|
||||
* c in [-128,9] => [-183,-46]
|
||||
* c in [10,127] => [-38,79]
|
||||
*/
|
||||
|
||||
/* Encrypt `src' of length `len' and store the result in `dest'. If the
|
||||
* resulting string would be longer than `size', return -1 and leave `dest'
|
||||
* unchanged; else return 0.
|
||||
*/
|
||||
static int myencrypt(const char *src, int len, char *dest, int size)
|
||||
{
|
||||
|
||||
#ifdef ENCRYPT_MD5
|
||||
|
||||
MD5_CTX context;
|
||||
char digest[33];
|
||||
char dest2[16];
|
||||
int i;
|
||||
#ifdef PW_TRANSITION_LOG
|
||||
FILE *tp;
|
||||
#endif
|
||||
if (size < 32)
|
||||
return -1;
|
||||
|
||||
memset(&context, 0, sizeof(context));
|
||||
memset(&digest, 0, sizeof(digest));
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, (unsigned const char *) src, (size_t) len);
|
||||
MD5Final((unsigned char *) digest, &context);
|
||||
|
||||
/* convert to hex, skipping last 8 bytes (constant) -- jilles */
|
||||
// strcpy(digest, "$ircservices$");
|
||||
for (i = 0; i <= 7; i++)
|
||||
// sprintf(dest + 13 + 2 * i, "%02x", 255 & digest[i]);
|
||||
sprintf(dest + 2 * i, "%02x", 255 & digest[i]);
|
||||
#ifdef PW_TRANSITION_LOG
|
||||
tp = popen(PW_TRANSITION_LOG,"w");
|
||||
if (tp != NULL)
|
||||
{
|
||||
fprintf(tp,"%s\n%s\n",src,dest);
|
||||
pclose(tp);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
#endif
|
||||
|
||||
return -1; /* unknown encryption algorithm */
|
||||
}
|
||||
|
||||
#if 0 /* unused */
|
||||
/* Shortcut for encrypting a null-terminated string in place. */
|
||||
static int encrypt_in_place(char *buf, int size)
|
||||
{
|
||||
return myencrypt(buf, strlen(buf), buf, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Compare a plaintext string against an encrypted password. Return 1 if
|
||||
* they match, 0 if not, and -1 if something went wrong. */
|
||||
|
||||
static int check_password(const char *plaintext, const char *password)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
|
||||
if (myencrypt(plaintext, strlen(plaintext), buf, sizeof(buf)) < 0)
|
||||
return -1;
|
||||
#ifdef ENCRYPT_MD5
|
||||
if (strcmp(buf, password) == 0)
|
||||
#else
|
||||
if (0)
|
||||
#endif
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"crypto/ircservices", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Jilles Tjoelker <jilles@stack.nl>"
|
||||
);
|
||||
|
||||
static char *ircservices_crypt_string(char *key, char *salt)
|
||||
{
|
||||
static char output[PASSMAX];
|
||||
if (salt[0] == '$' && salt[1] == '1') /* this is a new pw XXX */
|
||||
{
|
||||
myencrypt(key, strlen(key), output, PASSMAX);
|
||||
return output;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (check_password(key, salt))
|
||||
return salt;
|
||||
else
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
crypt_string = &ircservices_crypt_string;
|
||||
|
||||
crypto_module_loaded = true;
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
crypt_string = &generic_crypt_string;
|
||||
|
||||
crypto_module_loaded = false;
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2007 William Pitcock
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* mlocktweaker.c: A module which tweaks mlock on registration.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
/*
|
||||
* Set this to the string of mlock changes you want to make.
|
||||
* This is in addition to the default mlock, so -nt if you want to
|
||||
* remove those mlocks, etcetera.
|
||||
*/
|
||||
#define MLOCK_CHANGE "-t+c"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/mlocktweaker", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"William Pitcock <nenolod@atheme.org>"
|
||||
);
|
||||
|
||||
static void handle_channel_register(void *vptr);
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("channel_register");
|
||||
hook_add_first_channel_register(handle_channel_register);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_register(handle_channel_register);
|
||||
}
|
||||
|
||||
static void handle_channel_register(void *vptr)
|
||||
{
|
||||
hook_channel_req_t *hdata = vptr;
|
||||
mychan_t *mc = hdata->mc;
|
||||
unsigned int *target;
|
||||
char *it, *str = MLOCK_CHANGE;
|
||||
|
||||
if (mc == NULL)
|
||||
return;
|
||||
|
||||
target = &mc->mlock_on;
|
||||
it = str;
|
||||
|
||||
switch(*it++ != '\0')
|
||||
{
|
||||
case '+':
|
||||
target = &mc->mlock_on;
|
||||
break;
|
||||
case '-':
|
||||
target = &mc->mlock_off;
|
||||
break;
|
||||
default:
|
||||
*target |= mode_to_flag(*it);
|
||||
break;
|
||||
}
|
||||
|
||||
mc->mlock_off &= ~mc->mlock_on;
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* Copyright (c) 2005 Atheme Development Group
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the Memoserv FSEND function
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
/* MEMOLEN + 8, so the "[FORCE] " string will fit */
|
||||
#define FMEMOLEN 308
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ms_fsend", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void ms_cmd_fsend(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
/* MARK is prolly the most appropriate priv (that I can think of), if you can
|
||||
* think of a better one, feel free to change it. --jdhore
|
||||
*/
|
||||
command_t ms_fsend = { "FSEND", N_("Forcibly sends a memo to a user."),
|
||||
PRIV_MARK, 2, ms_cmd_fsend, { .path = "contrib/fsend" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("memoserv", &ms_fsend);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("memoserv", &ms_fsend);
|
||||
}
|
||||
|
||||
static void ms_cmd_fsend(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
/* misc structs etc */
|
||||
user_t *tu;
|
||||
myuser_t *tmu;
|
||||
mowgli_node_t *n;
|
||||
mymemo_t *memo;
|
||||
service_t *memoserv;
|
||||
|
||||
/* Grab args */
|
||||
char *target = parv[0];
|
||||
char *m = parv[1];
|
||||
|
||||
/* Arg validation */
|
||||
if (!target || !m)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams,
|
||||
STR_INSUFFICIENT_PARAMS, "FSEND");
|
||||
|
||||
command_fail(si, fault_needmoreparams,
|
||||
"Syntax: FSEND <user> <memo>");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!si->smu)
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not logged in."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* rate limit it -- jilles */
|
||||
if (CURRTIME - si->smu->memo_ratelimit_time > MEMO_MAX_TIME)
|
||||
si->smu->memo_ratelimit_num = 0;
|
||||
if (si->smu->memo_ratelimit_num > MEMO_MAX_NUM && !has_priv(si, PRIV_FLOOD))
|
||||
{
|
||||
command_fail(si, fault_toomany, _("You have used this command too many times; please wait a while and try again."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check for memo text length -- includes/common.h */
|
||||
if (strlen(m) >= MEMOLEN)
|
||||
{
|
||||
command_fail(si, fault_badparams,
|
||||
"Please make sure your memo is less than %d characters", MEMOLEN);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check to make sure the memo doesn't contain hostile CTCP responses.
|
||||
* realistically, we'll probably want to check the _entire_ message for this... --nenolod
|
||||
*/
|
||||
if (*m == '\001')
|
||||
{
|
||||
command_fail(si, fault_badparams, _("Your memo contains invalid characters."));
|
||||
return;
|
||||
}
|
||||
|
||||
memoserv = service_find("memoserv");
|
||||
if (memoserv == NULL)
|
||||
memoserv = si->service;
|
||||
|
||||
if (*target != '#' && *target != '!')
|
||||
{
|
||||
/* See if target is valid */
|
||||
if (!(tmu = myuser_find_ext(target)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target,
|
||||
"\2%s\2 is not registered.", target);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
si->smu->memo_ratelimit_num++;
|
||||
si->smu->memo_ratelimit_time = CURRTIME;
|
||||
|
||||
/* Check to make sure target inbox not full */
|
||||
if (tmu->memos.count >= me.mdlimit)
|
||||
{
|
||||
command_fail(si, fault_toomany, _("%s's inbox is full"), target);
|
||||
logcommand(si, CMDLOG_SET, "failed SEND to \2%s\2 (target inbox full)", entity(tmu)->name);
|
||||
return;
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_ADMIN, "FSEND: to \2%s\2", entity(tmu)->name);
|
||||
|
||||
/* Malloc and populate struct */
|
||||
memo = smalloc(sizeof(mymemo_t));
|
||||
memo->sent = CURRTIME;
|
||||
memo->status = 0;
|
||||
mowgli_strlcpy(memo->sender,entity(si->smu)->name,NICKLEN);
|
||||
mowgli_strlcpy(memo->text, "[FORCE] ", FMEMOLEN);
|
||||
mowgli_strlcat(memo->text, m, FMEMOLEN);
|
||||
|
||||
/* Create a linked list node and add to memos */
|
||||
n = mowgli_node_create();
|
||||
mowgli_node_add(memo, n, &tmu->memos);
|
||||
tmu->memoct_new++;
|
||||
|
||||
/* Should we email this? */
|
||||
if (tmu->flags & MU_EMAILMEMOS)
|
||||
{
|
||||
sendemail(si->su, EMAIL_MEMO, tmu, memo->text);
|
||||
}
|
||||
|
||||
/* Note: do not disclose other nicks they're logged in with
|
||||
* -- jilles
|
||||
*
|
||||
* Actually, I don't see the point in this at all. If they want this information,
|
||||
* they should use WHOIS. --nenolod
|
||||
*/
|
||||
tu = user_find_named(target);
|
||||
if (tu != NULL && tu->myuser == tmu)
|
||||
command_success_nodata(si, _("%s is currently online, and you may talk directly, by sending a private message."), target);
|
||||
|
||||
/* Is the user online? If so, tell them about the new memo. */
|
||||
if (si->su == NULL || !irccasecmp(si->su->nick, entity(si->smu)->name))
|
||||
myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (%zu).", entity(si->smu)->name, MOWGLI_LIST_LENGTH(&tmu->memos));
|
||||
else
|
||||
myuser_notice(memoserv->nick, tmu, "You have a new memo from %s (nick: %s) (%zu).", entity(si->smu)->name, si->su->nick, MOWGLI_LIST_LENGTH(&tmu->memos));
|
||||
myuser_notice(memoserv->nick, tmu, _("To read it, type /%s%s READ %zu"),
|
||||
ircd->uses_rcommand ? "" : "msg ", memoserv->disp, MOWGLI_LIST_LENGTH(&tmu->memos));
|
||||
|
||||
/* Tell user memo sent */
|
||||
command_success_nodata(si, _("The memo has been successfully sent to \2%s\2."), target);
|
||||
}
|
||||
else if (*target == '#')
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Channel memos may not be forced."));
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Group memos may not be forced."));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (c) 2007 Jilles Tjoelker
|
||||
* Copyright (c) 2008 Robin Burchell
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Services-side autojoin using SVSJOIN
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "uplink.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_ajoin", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void ajoin_on_identify(user_t *u);
|
||||
|
||||
static void ns_cmd_ajoin(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char buf[512];
|
||||
char *chan;
|
||||
metadata_t *md;
|
||||
|
||||
if (!parv[0])
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN");
|
||||
command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del> [#channel]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(parv[0], "LIST"))
|
||||
{
|
||||
command_success_nodata(si, "\2AJOIN LIST\2:");
|
||||
if ((md = metadata_find(si->smu, "private:autojoin")))
|
||||
{
|
||||
mowgli_strlcpy(buf, md->value, sizeof buf);
|
||||
|
||||
chan = strtok(buf, ",");
|
||||
while (chan != NULL)
|
||||
{
|
||||
command_success_nodata(si, "%s", chan);
|
||||
chan = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
command_success_nodata(si, "End of \2AJOIN LIST\2");
|
||||
}
|
||||
else if (!strcasecmp(parv[0], "ADD"))
|
||||
{
|
||||
if (!parv[1])
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN");
|
||||
command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del|clear> [#channel]");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((md = metadata_find(si->smu, "private:autojoin")))
|
||||
{
|
||||
mowgli_strlcpy(buf, md->value, sizeof buf);
|
||||
|
||||
chan = strtok(buf, ",");
|
||||
while (chan != NULL)
|
||||
{
|
||||
if (!strcasecmp(chan, parv[1]))
|
||||
{
|
||||
command_fail(si, fault_badparams, "%s is already on your AJOIN list.", parv[1]);
|
||||
return;
|
||||
}
|
||||
chan = strtok(NULL, ",");
|
||||
}
|
||||
|
||||
// Little arbitrary, but stop both overflow and RAM consumption going out of control
|
||||
if (strlen(md->value) + strlen(parv[1]) > 400)
|
||||
{
|
||||
command_fail(si, fault_badparams, "Sorry, you have too many AJOIN entries set.");
|
||||
return;
|
||||
}
|
||||
|
||||
mowgli_strlcpy(buf, md->value, sizeof buf);
|
||||
mowgli_strlcat(buf, ",", sizeof buf);
|
||||
mowgli_strlcat(buf, parv[1], sizeof buf);
|
||||
metadata_delete(si->smu, "private:autojoin");
|
||||
metadata_add(si->smu, "private:autojoin", buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
metadata_add(si->smu, "private:autojoin", parv[1]);
|
||||
}
|
||||
command_success_nodata(si, "%s added to AJOIN successfully.", parv[1]);
|
||||
}
|
||||
else if (!strcasecmp(parv[0], "CLEAR"))
|
||||
{
|
||||
metadata_delete(si->smu, "private:autojoin");
|
||||
command_success_nodata(si, "AJOIN list cleared successfully.");
|
||||
}
|
||||
else if (!strcasecmp(parv[0], "DEL"))
|
||||
{
|
||||
if (!parv[1])
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN");
|
||||
command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del|clear> [#channel]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(md = metadata_find(si->smu, "private:autojoin")))
|
||||
{
|
||||
command_fail(si, fault_badparams, "%s is not on your AJOIN list.", parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Thanks to John Brooks for his help with this.
|
||||
char *list = md->value;
|
||||
char *remove1 = parv[1];
|
||||
|
||||
int listlen = 0;
|
||||
int rmlen = 0;
|
||||
int itempos = 0;
|
||||
int i = 0, j = 0;
|
||||
// This loop will find the item (if present), find the length of the item, and find the length of the entire string.
|
||||
for (; list[i]; i++)
|
||||
{
|
||||
if (!rmlen)
|
||||
{
|
||||
// We have not found the string yet
|
||||
if (tolower(list[i]) == tolower(remove1[j]))
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
// First character of a potential match; remember it's location
|
||||
itempos = i;
|
||||
}
|
||||
|
||||
j++;
|
||||
if (!remove1[j])
|
||||
{
|
||||
// Found the entire string
|
||||
rmlen = j;
|
||||
}
|
||||
}
|
||||
else
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (remove1[j])
|
||||
{
|
||||
command_fail(si, fault_badparams, "%s is not on your AJOIN list.", parv[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
listlen = i;
|
||||
|
||||
// listlen is the length of the list, rmlen is the length of the item to remove, itempos is the beginning of that item.
|
||||
if (!list[itempos + rmlen])
|
||||
{
|
||||
// This item is the last item in the list, so we can simply truncate
|
||||
if (itempos > 0)
|
||||
{
|
||||
itempos--;
|
||||
list[itempos] = '\0';
|
||||
}
|
||||
else
|
||||
metadata_delete(si->smu, "private:autojoin");
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are items after this one, so we must copy memory
|
||||
// Account for the comma following this item (if there is a space, account for that too, depends on how you format your list)
|
||||
rmlen += 1;
|
||||
memmove(list + itempos, list + itempos + rmlen, listlen - rmlen - itempos);
|
||||
list[listlen - rmlen] = '\0';
|
||||
}
|
||||
|
||||
command_success_nodata(si, "%s removed from AJOIN successfully.", parv[1]);
|
||||
}
|
||||
}
|
||||
|
||||
command_t ns_ajoin = { "AJOIN", "Manages automatic-join on identify.", AC_AUTHENTICATED, 2, ns_cmd_ajoin, { .path = "contrib/ajoin" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("user_identify");
|
||||
hook_add_user_identify(ajoin_on_identify);
|
||||
service_named_bind_command("nickserv", &ns_ajoin);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_identify(ajoin_on_identify);
|
||||
service_named_unbind_command("nickserv", &ns_ajoin);
|
||||
}
|
||||
|
||||
static void ajoin_on_identify(user_t *u)
|
||||
{
|
||||
myuser_t *mu = u->myuser;
|
||||
metadata_t *md;
|
||||
char buf[512];
|
||||
char *chan;
|
||||
|
||||
if (!(md = metadata_find(mu, "private:autojoin")))
|
||||
return;
|
||||
|
||||
mowgli_strlcpy(buf, md->value, sizeof buf);
|
||||
chan = strtok(buf, " ,");
|
||||
while (chan != NULL)
|
||||
{
|
||||
if(ircd->type == PROTOCOL_SHADOWIRCD)
|
||||
{
|
||||
sts(":%s ENCAP * SVSJOIN %s %s", ME, CLIENT_NAME(u), chan);
|
||||
}
|
||||
else
|
||||
{
|
||||
sts(":%s SVSJOIN %s %s", CLIENT_NAME(nicksvs.me->me), CLIENT_NAME(u), chan);
|
||||
}
|
||||
|
||||
chan = strtok(NULL, ",");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Clean obnoxious nicknames, such as LaMENiCK -> lamenick.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_cleannick", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
#define LAMENESS_WEIGHT 0.35f
|
||||
|
||||
/*
|
||||
* Determine if a nickname is lame. Non-alphabetical characters
|
||||
* are penalized twice, uppercase characters are penalized once.
|
||||
*/
|
||||
static bool is_nickname_lame(const char *nickname)
|
||||
{
|
||||
const char *p;
|
||||
unsigned int capcount = 0;
|
||||
float score;
|
||||
|
||||
return_val_if_fail(nickname != NULL, false);
|
||||
|
||||
for (p = nickname; *p != '\0'; p++)
|
||||
{
|
||||
if (IsUpper(*p))
|
||||
capcount++;
|
||||
|
||||
#ifdef NOTYET
|
||||
if (!IsAlpha(*p))
|
||||
capcount += 2;
|
||||
#endif
|
||||
}
|
||||
|
||||
score = (float) capcount / (float) strlen(nickname);
|
||||
slog(LG_DEBUG, "is_nickname_lame(%s): score %0.3f %d/%zu caps", nickname, score, capcount, strlen(nickname));
|
||||
|
||||
if (score > LAMENESS_WEIGHT)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanitize a nickname and then change it to the sanitized version forcefully.
|
||||
*/
|
||||
static void clean_nickname(user_t *u)
|
||||
{
|
||||
char nickbuf[NICKLEN];
|
||||
char *p;
|
||||
|
||||
return_if_fail(u != NULL);
|
||||
|
||||
mowgli_strlcpy(nickbuf, u->nick, NICKLEN);
|
||||
|
||||
p = nickbuf;
|
||||
|
||||
while (*p++)
|
||||
{
|
||||
if (IsUpper(*p))
|
||||
*p = ToLower(*p);
|
||||
}
|
||||
|
||||
if (is_nickname_lame(nickbuf))
|
||||
{
|
||||
slog(LG_DEBUG, "clean_nickname(%s): cleaned nickname %s is still lame", u->nick, nickbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
notice(nicksvs.nick, u->nick, "Your nick has been changed to \2%s\2 per %s nickname quality guidelines.",
|
||||
nickbuf, me.netname);
|
||||
|
||||
fnc_sts(nicksvs.me->me, u, nickbuf, FNC_FORCE);
|
||||
}
|
||||
|
||||
static void user_state_changed(hook_user_nick_t *data)
|
||||
{
|
||||
return_if_fail(data != NULL);
|
||||
return_if_fail(data->u != NULL);
|
||||
|
||||
if (!is_internal_client(data->u) && is_nickname_lame(data->u->nick))
|
||||
{
|
||||
#ifdef TAUNT_LAME_USERS
|
||||
if (data->oldnick != NULL && !is_nickname_lame(data->oldnick))
|
||||
notice(nicksvs.nick, data->u->nick, "\2%s\2 was much less lame, \2%s\2.",
|
||||
data->oldnick, data->u->nick);
|
||||
#endif
|
||||
|
||||
clean_nickname(data->u);
|
||||
}
|
||||
}
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("user_add");
|
||||
hook_add_user_add(user_state_changed);
|
||||
|
||||
hook_add_event("user_nickchange");
|
||||
hook_add_user_nickchange(user_state_changed);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_add(user_state_changed);
|
||||
hook_del_user_nickchange(user_state_changed);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2007 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the NickServ FENFORCE function.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_fenforce", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void ns_cmd_fenforce(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t ns_fenforce = { "FENFORCE", "Enables or disables protection of another user's nicknames.", PRIV_USER_ADMIN, 2, ns_cmd_fenforce, { .path = "contrib/fenforce" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
MODULE_TRY_REQUEST_DEPENDENCY(m, "nickserv/enforce");
|
||||
|
||||
service_named_bind_command("nickserv", &ns_fenforce);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("nickserv", &ns_fenforce);
|
||||
}
|
||||
|
||||
static void ns_cmd_fenforce(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *setting;
|
||||
myuser_t *mu;
|
||||
|
||||
if (parc < 2)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FENFORCE");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: FENFORCE <account> ON|OFF"));
|
||||
return;
|
||||
}
|
||||
|
||||
mu = myuser_find_ext(parv[0]);
|
||||
if (!mu)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), parv[0]);
|
||||
return;
|
||||
}
|
||||
setting = parv[1];
|
||||
|
||||
if (strcasecmp(setting, "ON") == 0)
|
||||
{
|
||||
if (metadata_find(mu, "private:doenforce"))
|
||||
{
|
||||
command_fail(si, fault_nochange, _("The \2%s\2 flag is already set for account \2%s\2."), "ENFORCE", entity(mu)->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
wallops("%s enabled ENFORCE on the account \2%s\2.", get_oper_name(si), entity(mu)->name);
|
||||
logcommand(si, CMDLOG_ADMIN, "FENFORCE:ON: \2%s\2", entity(mu)->name);
|
||||
metadata_add(mu, "private:doenforce", "1");
|
||||
command_success_nodata(si, _("The \2%s\2 flag has been set for account \2%s\2."), "ENFORCE", entity(mu)->name);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(setting, "OFF") == 0)
|
||||
{
|
||||
if (metadata_find(mu, "private:doenforce"))
|
||||
{
|
||||
wallops("%s disabled ENFORCE on the account \2%s\2.", get_oper_name(si), entity(mu)->name);
|
||||
logcommand(si, CMDLOG_ADMIN, "FENFORCE:OFF: \2%s\2", entity(mu)->name);
|
||||
metadata_delete(mu, "private:doenforce");
|
||||
command_success_nodata(si, _("The \2%s\2 flag has been removed for account \2%s\2."), "ENFORCE", entity(mu)->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_nochange, _("The \2%s\2 flag is not set for account \2%s\2."), "ENFORCE", entity(mu)->name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "FENFORCE");
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2007 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the NickServ FORBID function.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_forbid", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
#define FORBID_EMAIL "noemail"
|
||||
|
||||
static void ns_cmd_forbid(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t ns_forbid = { "FORBID", "Disallows use of a nickname.", PRIV_USER_ADMIN, 3, ns_cmd_forbid, { .path = "contrib/forbid" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("nickserv", &ns_forbid);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("nickserv", &ns_forbid);
|
||||
}
|
||||
|
||||
static void make_forbid(sourceinfo_t *si, const char *account, const char *reason)
|
||||
{
|
||||
myuser_t *mu;
|
||||
mynick_t *mn = NULL;
|
||||
user_t *u;
|
||||
|
||||
if (!nicksvs.no_nick_ownership && IsDigit(*account))
|
||||
{
|
||||
command_fail(si, fault_badparams, "For security reasons, you can't forbid a UID.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strchr(account, ' ') || strchr(account, '\n') || strchr(account, '\r') || account[0] == '=' || account[0] == '#' || account[0] == '@' || account[0] == '+' || account[0] == '%' || account[0] == '!' || strchr(account, ','))
|
||||
{
|
||||
command_fail(si, fault_badparams, "The account name \2%s\2 is invalid.", account);
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure it isn't registered already */
|
||||
if (nicksvs.no_nick_ownership ? myuser_find(account) != NULL : mynick_find(account) != NULL)
|
||||
{
|
||||
command_fail(si, fault_alreadyexists, "\2%s\2 is already registered.", account);
|
||||
return;
|
||||
}
|
||||
|
||||
mu = myuser_add(account, "*", FORBID_EMAIL, MU_CRYPTPASS | MU_ENFORCE | MU_HOLD | MU_NOBURSTLOGIN);
|
||||
mu->registered = CURRTIME;
|
||||
mu->lastlogin = CURRTIME;
|
||||
metadata_add(mu, "private:freeze:freezer", get_oper_name(si));
|
||||
metadata_add(mu, "private:freeze:reason", reason);
|
||||
metadata_add(mu, "private:freeze:timestamp", number_to_string(CURRTIME));
|
||||
if (!nicksvs.no_nick_ownership)
|
||||
{
|
||||
mn = mynick_add(mu, entity(mu)->name);
|
||||
mn->registered = CURRTIME;
|
||||
mn->lastseen = CURRTIME;
|
||||
u = user_find_named(entity(mu)->name);
|
||||
if (u != NULL)
|
||||
{
|
||||
notice(si->service->nick, u->nick,
|
||||
_("The nick \2%s\2 is now forbidden."),
|
||||
entity(mu)->name);
|
||||
hook_call_nick_enforce((&(hook_nick_enforce_t){ .u = u, .mn = mn }));
|
||||
}
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_ADMIN | CMDLOG_REGISTER, "FORBID:ON: \2%s\2 (reason: \2%s\2)", account, reason);
|
||||
wallops("%s forbade the nickname \2%s\2 (%s).", get_oper_name(si), account, reason);
|
||||
command_success_nodata(si, "\2%s\2 is now forbidden.", entity(mu)->name);
|
||||
/* don't call hooks, hmm */
|
||||
}
|
||||
|
||||
static void destroy_forbid(sourceinfo_t *si, const char *account)
|
||||
{
|
||||
myuser_t *mu;
|
||||
metadata_t *md;
|
||||
|
||||
mu = myuser_find(account);
|
||||
if (!mu)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 is not registered."), account);
|
||||
return;
|
||||
}
|
||||
|
||||
md = metadata_find(mu, "private:freeze:freezer");
|
||||
if (md == NULL || mu->registered != mu->lastlogin ||
|
||||
MOWGLI_LIST_LENGTH(&mu->nicks) != 1 ||
|
||||
strcmp(mu->email, FORBID_EMAIL))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("\2%s\2 is not a forbidden nickname."), account);
|
||||
return;
|
||||
}
|
||||
logcommand(si, CMDLOG_ADMIN | CMDLOG_REGISTER, "FORBID:OFF: \2%s\2", entity(mu)->name);
|
||||
wallops("%s unforbade the nickname \2%s\2.", get_oper_name(si), account);
|
||||
command_success_nodata(si, "\2%s\2 is no longer forbidden.", entity(mu)->name);
|
||||
/* no hooks here either, hmm */
|
||||
object_unref(mu);
|
||||
}
|
||||
|
||||
static void ns_cmd_forbid(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
const char *account;
|
||||
const char *action;
|
||||
const char *reason;
|
||||
|
||||
account = parv[0], action = parv[1], reason = parv[2];
|
||||
|
||||
if (!account || !action)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FORBID");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: FORBID <nickname> ON|OFF [reason]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(action, "ON"))
|
||||
{
|
||||
if (!reason)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FORBID");
|
||||
command_fail(si, fault_needmoreparams, _("Usage: FORBID <nickname> ON <reason>"));
|
||||
return;
|
||||
}
|
||||
make_forbid(si, account, reason);
|
||||
}
|
||||
else if (!strcasecmp(action, "OFF"))
|
||||
destroy_forbid(si, account);
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FORBID");
|
||||
command_fail(si, fault_needmoreparams, _("Usage: FORBID <nickname> ON|OFF [reason]"));
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2007 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the NickServ FREGISTER function.
|
||||
*
|
||||
* Remember to give the user:fregister priv to any soper you want
|
||||
* to be able to use this command.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_fregister", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void ns_cmd_fregister(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t ns_fregister = { "FREGISTER", "Registers a nickname on behalf of another user.", PRIV_USER_FREGISTER, 20, ns_cmd_fregister, { .path = "contrib/fregister" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("nickserv", &ns_fregister);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("nickserv", &ns_fregister);
|
||||
}
|
||||
|
||||
static void ns_cmd_fregister(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
myuser_t *mu;
|
||||
mynick_t *mn = NULL;
|
||||
char *account;
|
||||
char *pass;
|
||||
char *email;
|
||||
int i, uflags = 0;
|
||||
hook_user_req_t req;
|
||||
|
||||
account = parv[0], pass = parv[1], email = parv[2];
|
||||
|
||||
if (!account || !pass || !email)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "FREGISTER");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: FREGISTER <account> <password> <email> [CRYPTPASS]");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 3; i < parc; i++)
|
||||
{
|
||||
if (!strcasecmp(parv[i], "CRYPTPASS"))
|
||||
uflags |= MU_CRYPTPASS;
|
||||
else if (!strcasecmp(parv[i], "HIDEMAIL"))
|
||||
uflags |= MU_HIDEMAIL;
|
||||
else if (!strcasecmp(parv[i], "NOOP"))
|
||||
uflags |= MU_NOOP;
|
||||
else if (!strcasecmp(parv[i], "NEVEROP"))
|
||||
uflags |= MU_NEVEROP;
|
||||
}
|
||||
|
||||
if (!(uflags & MU_CRYPTPASS) && strlen(pass) > 32)
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "FREGISTER");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nicksvs.no_nick_ownership && IsDigit(*account))
|
||||
{
|
||||
command_fail(si, fault_badparams, "For security reasons, you can't register your UID.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (strchr(account, ' ') || strchr(account, '\n') || strchr(account, '\r') || account[0] == '=' || account[0] == '#' || account[0] == '@' || account[0] == '+' || account[0] == '%' || account[0] == '!' || strchr(account, ','))
|
||||
{
|
||||
command_fail(si, fault_badparams, "The account name \2%s\2 is invalid.", account);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validemail(email))
|
||||
{
|
||||
command_fail(si, fault_badparams, "\2%s\2 is not a valid email address.", email);
|
||||
return;
|
||||
}
|
||||
|
||||
/* make sure it isn't registered already */
|
||||
if (nicksvs.no_nick_ownership ? myuser_find(account) != NULL : mynick_find(account) != NULL)
|
||||
{
|
||||
command_fail(si, fault_alreadyexists, "\2%s\2 is already registered.", account);
|
||||
return;
|
||||
}
|
||||
|
||||
mu = myuser_add(account, pass, email, uflags | config_options.defuflags | MU_NOBURSTLOGIN);
|
||||
mu->registered = CURRTIME;
|
||||
mu->lastlogin = CURRTIME;
|
||||
if (!nicksvs.no_nick_ownership)
|
||||
{
|
||||
mn = mynick_add(mu, entity(mu)->name);
|
||||
mn->registered = CURRTIME;
|
||||
mn->lastseen = CURRTIME;
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_REGISTER, "FREGISTER: \2%s\2 to \2%s\2", account, email);
|
||||
if (is_soper(mu))
|
||||
{
|
||||
wallops("%s used FREGISTER on account \2%s\2 with services operator privileges.", get_oper_name(si), entity(mu)->name);
|
||||
slog(LG_INFO, "SOPER: \2%s\2", entity(mu)->name);
|
||||
}
|
||||
|
||||
command_success_nodata(si, "\2%s\2 is now registered to \2%s\2.", entity(mu)->name, mu->email);
|
||||
hook_call_user_register(mu);
|
||||
req.si = si;
|
||||
req.mu = mu;
|
||||
req.mn = mn;
|
||||
hook_call_user_verify_register(&req);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2010 Atheme development group
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Generates a hash for use as a operserv "password".
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_generatehash", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme development group"
|
||||
);
|
||||
|
||||
static void ns_cmd_generatehash(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t ns_generatehash = { "GENERATEHASH", "Generates a hash for SOPER.",
|
||||
AC_NONE, 1, ns_cmd_generatehash, { .path = "contrib/generatehash" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("nickserv", &ns_generatehash);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("nickserv", &ns_generatehash);
|
||||
}
|
||||
|
||||
static void ns_cmd_generatehash(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *pass = parv[0];
|
||||
char hash[PASSLEN];
|
||||
|
||||
if (parc < 1)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "GENERATEHASH");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: GENERATEHASH <password>"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (crypto_module_loaded)
|
||||
{
|
||||
mowgli_strlcpy(hash, crypt_string(pass, gen_salt()), PASSLEN);
|
||||
command_success_string(si, hash, "Hash is: %s", hash);
|
||||
}
|
||||
else
|
||||
command_success_nodata(si, "No crypto module loaded so could not hash anything.");
|
||||
|
||||
logcommand(si, CMDLOG_GET, "GENERATEHASH");
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2005 Greg Feigenson
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Generates a new password, either n digits long (w/ nickserv arg), or 7 digits
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_generatepass", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Epiphanic Networks <http://www.epiphanic.org>"
|
||||
);
|
||||
|
||||
static void ns_cmd_generatepass(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t ns_generatepass = { "GENERATEPASS", "Generates a random password.",
|
||||
AC_NONE, 1, ns_cmd_generatepass, { .path = "contrib/generatepass" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("nickserv", &ns_generatepass);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("nickserv", &ns_generatepass);
|
||||
}
|
||||
|
||||
static void ns_cmd_generatepass(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
int n = 0;
|
||||
char *newpass;
|
||||
|
||||
if (parc >= 1)
|
||||
n = atoi(parv[0]);
|
||||
|
||||
if (n <= 0 || n > 127)
|
||||
n = 7;
|
||||
|
||||
newpass = random_string(n);
|
||||
|
||||
command_success_string(si, newpass, "Randomly generated password: %s", newpass);
|
||||
free(newpass);
|
||||
logcommand(si, CMDLOG_GET, "GENERATEPASS");
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2010 William Pitcock <nenolod@atheme.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for blocking registrations of guest nicks.
|
||||
* Particularly for use with webchat clients.
|
||||
*
|
||||
* To actually use this, add a something like the following to
|
||||
* the nickserv {} block of your atheme.conf:
|
||||
* guestnicks {
|
||||
* "mib_";
|
||||
* "WebUser";
|
||||
* };
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "conf.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_guestnoreg", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static mowgli_list_t guestnicks = { NULL, NULL, 0 };
|
||||
|
||||
static void guestnoreg_hook(hook_user_register_check_t *hdata)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
return_if_fail(hdata != NULL);
|
||||
return_if_fail(hdata->si != NULL);
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, guestnicks.head)
|
||||
{
|
||||
char *nick = n->data;
|
||||
int nicklen = strlen(nick);
|
||||
|
||||
if (!strncasecmp(hdata->account, nick, nicklen))
|
||||
{
|
||||
command_fail(hdata->si, fault_badparams, _("Registering of guest nicknames is disallowed."));
|
||||
hdata->approved++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static int guestnoreg_config_handler(mowgli_config_file_entry_t *ce)
|
||||
{
|
||||
mowgli_config_file_entry_t *cce;
|
||||
|
||||
MOWGLI_ITER_FOREACH(cce, ce->entries)
|
||||
{
|
||||
char *nick = sstrdup(cce->varname);
|
||||
mowgli_node_add(nick, mowgli_node_create(), &guestnicks);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void guestnoreg_config_purge(void *unused)
|
||||
{
|
||||
mowgli_node_t *n, *tn;
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, guestnicks.head)
|
||||
{
|
||||
char *nick = n->data;
|
||||
|
||||
free(nick);
|
||||
mowgli_node_delete(n, &guestnicks);
|
||||
mowgli_node_free(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("config_purge");
|
||||
hook_add_config_purge(guestnoreg_config_purge);
|
||||
|
||||
hook_add_event("user_can_register");
|
||||
hook_add_user_can_register(guestnoreg_hook);
|
||||
|
||||
add_conf_item("GUESTNICKS", &nicksvs.me->conf_table, guestnoreg_config_handler);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_can_register(guestnoreg_hook);
|
||||
hook_del_config_purge(guestnoreg_config_purge);
|
||||
|
||||
del_conf_item("GUESTNICKS", &nicksvs.me->conf_table);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2007 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for the NickServ LISTLOGINS function.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_listlogins", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void ns_cmd_listlogins(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t ns_listlogins = { "LISTLOGINS", N_("Lists details of clients authenticated as you."), AC_AUTHENTICATED, 1, ns_cmd_listlogins, { .path = "contrib/listlogins" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("nickserv", &ns_listlogins);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("nickserv", &ns_listlogins);
|
||||
}
|
||||
|
||||
static void ns_cmd_listlogins(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
user_t *u;
|
||||
mowgli_node_t *n;
|
||||
int matches = 0;
|
||||
|
||||
if (si->smu->flags & MU_WAITAUTH)
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You have to verify your email address before you can perform this operation."));
|
||||
return;
|
||||
}
|
||||
|
||||
command_success_nodata(si, "Clients identified to account \2%s\2", entity(si->smu)->name);
|
||||
MOWGLI_ITER_FOREACH(n, si->smu->logins.head)
|
||||
{
|
||||
u = n->data;
|
||||
command_success_nodata(si, "- %s!%s@%s (real host: %s)", u->nick, u->user, u->vhost, u->host);
|
||||
matches++;
|
||||
}
|
||||
command_success_nodata(si, ngettext(N_("\2%d\2 client found"), N_("\2%d\2 clients found"), matches), matches);
|
||||
logcommand(si, CMDLOG_GET, "LISTLOGINS: (\2%d\2 matches)", matches);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,89 @@
|
|||
#include "atheme.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_mxcheck", false, _modinit, _moddeinit,
|
||||
"1.1",
|
||||
"Jamie L. Penman-Smithson <jamie@slacked.org>"
|
||||
);
|
||||
|
||||
static void check_registration(hook_user_register_check_t *hdata);
|
||||
int count_mx (const char *host);
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("user_can_register");
|
||||
hook_add_user_can_register(check_registration);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_can_register(check_registration);
|
||||
}
|
||||
|
||||
static void check_registration(hook_user_register_check_t *hdata)
|
||||
{
|
||||
char buf[1024];
|
||||
const char *user;
|
||||
const char *domain;
|
||||
int count;
|
||||
|
||||
if (hdata->approved)
|
||||
return;
|
||||
|
||||
mowgli_strlcpy(buf, hdata->email, sizeof buf);
|
||||
user = strtok(buf, "@");
|
||||
domain = strtok(NULL, "@");
|
||||
count = count_mx(domain);
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
/* there are MX records for this domain */
|
||||
slog(LG_INFO, "REGISTER: mxcheck: %d MX records for %s", count, domain);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no MX records or error */
|
||||
struct hostent *host;
|
||||
|
||||
/* attempt to resolve host (fallback to A) */
|
||||
if((host = gethostbyname(domain)) == NULL)
|
||||
{
|
||||
slog(LG_INFO, "REGISTER: mxcheck: no A/MX records for %s - "
|
||||
"REGISTER failed", domain);
|
||||
command_fail(hdata->si, fault_noprivs, "Sorry, \2%s\2 does not exist, "
|
||||
"I can't send mail there. Please check and try again.", domain);
|
||||
hdata->approved = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int count_mx (const char *host)
|
||||
{
|
||||
u_char nsbuf[4096];
|
||||
ns_msg amsg;
|
||||
int l;
|
||||
|
||||
l = res_query (host, ns_c_any, ns_t_mx, nsbuf, sizeof (nsbuf));
|
||||
if (l < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ns_initparse (nsbuf, l, &amsg);
|
||||
l = ns_msg_count (amsg, ns_s_an);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,152 @@
|
|||
#include "atheme.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/nameser.h>
|
||||
#include <resolv.h>
|
||||
#include <netdb.h>
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_mxcheck_async", false, _modinit, _moddeinit,
|
||||
"1.1",
|
||||
"Jamie L. Penman-Smithson <jamie@slacked.org>"
|
||||
);
|
||||
|
||||
struct procdata
|
||||
{
|
||||
char name[NICKLEN];
|
||||
char email[EMAILLEN];
|
||||
};
|
||||
|
||||
#define MAX_CHILDPROCS 10
|
||||
|
||||
static unsigned int proccount;
|
||||
static struct procdata procdata[MAX_CHILDPROCS];
|
||||
|
||||
static void childproc_cb(pid_t pid, int status, void *data);
|
||||
static void check_registration(hook_user_register_check_t *hdata);
|
||||
|
||||
int count_mx (const char *host);
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("user_can_register");
|
||||
hook_add_user_can_register(check_registration);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_can_register(check_registration);
|
||||
childproc_delete_all(childproc_cb);
|
||||
}
|
||||
|
||||
static void childproc_cb(pid_t pid, int status, void *data)
|
||||
{
|
||||
struct procdata *pd = data;
|
||||
myuser_t *mu;
|
||||
const char *domain;
|
||||
|
||||
return_if_fail(proccount > 0);
|
||||
proccount--;
|
||||
|
||||
if (!WIFEXITED(status))
|
||||
return;
|
||||
|
||||
mu = myuser_find(pd->name);
|
||||
if (mu == NULL || strcmp(pd->email, mu->email))
|
||||
return;
|
||||
domain = strchr(pd->email, '@');
|
||||
if (domain == NULL)
|
||||
return;
|
||||
domain++;
|
||||
|
||||
if (WEXITSTATUS(status) == 1)
|
||||
{
|
||||
slog(LG_INFO, "REGISTER: mxcheck: no A/MX records for %s - "
|
||||
"REGISTER failed", domain);
|
||||
myuser_notice(nicksvs.nick, mu, "Sorry, \2%s\2 does not exist, "
|
||||
"I can't send mail there. Please check and try again.", domain);
|
||||
object_unref(mu);
|
||||
}
|
||||
else if (WEXITSTATUS(status) == 0)
|
||||
{
|
||||
slog(LG_INFO, "REGISTER: mxcheck: valid MX records for %s", domain);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_registration(hook_user_register_check_t *hdata)
|
||||
{
|
||||
char buf[1024];
|
||||
const char *user;
|
||||
const char *domain;
|
||||
int count;
|
||||
pid_t pid;
|
||||
struct procdata *pd;
|
||||
|
||||
if (hdata->approved)
|
||||
return;
|
||||
|
||||
if (proccount >= MAX_CHILDPROCS)
|
||||
{
|
||||
command_fail(hdata->si, fault_toomany, "Sorry, too many registrations in progress. Try again later.");
|
||||
hdata->approved = 1;
|
||||
return;
|
||||
}
|
||||
switch (pid = fork())
|
||||
{
|
||||
case 0: /* child */
|
||||
connection_close_all_fds();
|
||||
mowgli_strlcpy(buf, hdata->email, sizeof buf);
|
||||
user = strtok(buf, "@");
|
||||
domain = strtok(NULL, "@");
|
||||
count = count_mx(domain);
|
||||
|
||||
if (count <= 0)
|
||||
{
|
||||
/* no MX records or error */
|
||||
struct hostent *host;
|
||||
|
||||
/* attempt to resolve host (fallback to A) */
|
||||
if((host = gethostbyname(domain)) == NULL)
|
||||
_exit(1);
|
||||
}
|
||||
_exit(0);
|
||||
break;
|
||||
case -1: /* error */
|
||||
slog(LG_ERROR, "fork() failed for check_registration(): %s",
|
||||
strerror(errno));
|
||||
command_fail(hdata->si, fault_toomany, "Sorry, too many registrations in progress. Try again later.");
|
||||
hdata->approved = 1;
|
||||
return;
|
||||
default: /* parent */
|
||||
pd = &procdata[proccount++];
|
||||
mowgli_strlcpy(pd->name, hdata->account, sizeof pd->name);
|
||||
mowgli_strlcpy(pd->email, hdata->email, sizeof pd->email);
|
||||
childproc_add(pid, "ns_mxcheck_async", childproc_cb, pd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int count_mx (const char *host)
|
||||
{
|
||||
u_char nsbuf[4096];
|
||||
ns_msg amsg;
|
||||
int l;
|
||||
|
||||
l = res_query (host, ns_c_any, ns_t_mx, nsbuf, sizeof (nsbuf));
|
||||
if (l < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ns_initparse (nsbuf, l, &amsg);
|
||||
l = ns_msg_count (amsg, ns_s_an);
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2010 William Pitcock <nenolod@atheme.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Sends a customized welcome message on nickname registration.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "conf.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_regnotice", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static mowgli_list_t regnotices = { NULL, NULL, 0 };
|
||||
|
||||
static void regnotice_hook(myuser_t *mu)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
return_if_fail(mu != NULL);
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, regnotices.head)
|
||||
{
|
||||
char *line = n->data;
|
||||
|
||||
myuser_notice(nicksvs.nick, mu, "%s", line);
|
||||
}
|
||||
}
|
||||
|
||||
static int regnotice_config_handler(mowgli_config_file_entry_t *ce)
|
||||
{
|
||||
mowgli_config_file_entry_t *cce;
|
||||
|
||||
MOWGLI_ITER_FOREACH(cce, ce->entries)
|
||||
{
|
||||
char *line = sstrdup(cce->varname);
|
||||
mowgli_node_add(line, mowgli_node_create(), ®notices);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void regnotice_config_purge(void *unused)
|
||||
{
|
||||
mowgli_node_t *n, *tn;
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, regnotices.head)
|
||||
{
|
||||
char *line = n->data;
|
||||
|
||||
free(line);
|
||||
mowgli_node_delete(n, ®notices);
|
||||
mowgli_node_free(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("config_purge");
|
||||
hook_add_config_purge(regnotice_config_purge);
|
||||
|
||||
hook_add_event("user_register");
|
||||
hook_add_user_register(regnotice_hook);
|
||||
|
||||
add_conf_item("REGNOTICE", &nicksvs.me->conf_table, regnotice_config_handler);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_register(regnotice_hook);
|
||||
hook_del_config_purge(regnotice_config_purge);
|
||||
|
||||
del_conf_item("REGNOTICE", &nicksvs.me->conf_table);
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2010 William Pitcock <nenolod@atheme.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains code for delaying user registration
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "conf.h"
|
||||
#include <limits.h>
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/ns_waitreg", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
unsigned int waitreg_time = 0;
|
||||
|
||||
static void waitreg_hook(hook_user_register_check_t *hdata)
|
||||
{
|
||||
return_if_fail(hdata != NULL);
|
||||
return_if_fail(hdata->si != NULL);
|
||||
return_if_fail(hdata->password != NULL);
|
||||
|
||||
if (hdata->si->su == NULL)
|
||||
return;
|
||||
|
||||
unsigned int nickage = CURRTIME - hdata->si->su->ts;
|
||||
|
||||
if (nickage < waitreg_time)
|
||||
{
|
||||
command_fail(hdata->si, fault_badparams, _("You can not register your nick so soon after connecting. Please wait a while and try again."));
|
||||
hdata->approved++;
|
||||
}
|
||||
}
|
||||
|
||||
static void info_hook(sourceinfo_t *si)
|
||||
{
|
||||
return_if_fail(si != NULL);
|
||||
|
||||
command_success_nodata(si, "Time (in seconds) before users may register an account: %u", waitreg_time);
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
|
||||
hook_add_event("user_can_register");
|
||||
hook_add_user_can_register(waitreg_hook);
|
||||
|
||||
hook_add_event("operserv_info");
|
||||
hook_add_operserv_info(info_hook);
|
||||
|
||||
add_uint_conf_item("WAITREG_TIME", &nicksvs.me->conf_table, 0, &waitreg_time, 0, INT_MAX, 0);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_can_register(waitreg_hook);
|
||||
hook_del_operserv_info(info_hook);
|
||||
|
||||
del_conf_item("WAITREG_TIME", &nicksvs.me->conf_table);
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
#include "atheme.h"
|
||||
#include "conf.h"
|
||||
#include "datastream.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/on_db_save", false, _modinit, _moddeinit,
|
||||
"",
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static char *command = NULL;
|
||||
|
||||
static void on_db_save(void *unused);
|
||||
|
||||
static struct update_command_state {
|
||||
connection_t *out, *err;
|
||||
pid_t pid;
|
||||
int running;
|
||||
} update_command_proc;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
hook_add_event("db_saved");
|
||||
hook_add_db_saved(on_db_save);
|
||||
|
||||
add_dupstr_conf_item("db_update_command", &conf_gi_table, 0, &command, NULL);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_db_saved(on_db_save);
|
||||
|
||||
del_conf_item("db_update_command", &conf_gi_table);
|
||||
}
|
||||
|
||||
static void update_command_finished(pid_t pid, int status, void *data)
|
||||
{
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
slog(LG_ERROR, "ERROR: Database update command failed with error %d", WEXITSTATUS(status));
|
||||
|
||||
update_command_proc.running = 0;
|
||||
}
|
||||
|
||||
static void update_command_recvq_handler(connection_t *cptr, int err)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
int count;
|
||||
|
||||
count = recvq_getline(cptr, buf, sizeof(buf) - 1);
|
||||
if (count <= 0)
|
||||
return;
|
||||
if (buf[count-1] == '\n')
|
||||
count--;
|
||||
if (count == 0)
|
||||
buf[count++] = ' ';
|
||||
buf[count] = '\0';
|
||||
|
||||
if (err)
|
||||
{
|
||||
slog(LG_ERROR, "ERROR: database update command said: %s", buf);
|
||||
}
|
||||
else
|
||||
slog(LG_DEBUG, "db update command stdout: %s", buf);
|
||||
}
|
||||
|
||||
static void update_command_stdout_handler(connection_t *cptr)
|
||||
{
|
||||
update_command_recvq_handler(cptr, 0);
|
||||
}
|
||||
|
||||
static void update_command_stderr_handler(connection_t *cptr)
|
||||
{
|
||||
update_command_recvq_handler(cptr, 1);
|
||||
}
|
||||
|
||||
static void on_db_save(void *unused)
|
||||
{
|
||||
int stdout_pipes[2], stderr_pipes[2];
|
||||
pid_t pid;
|
||||
int errno1;
|
||||
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
if (update_command_proc.running)
|
||||
{
|
||||
slog(LG_ERROR, "ERROR: database update command is still running");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe(stdout_pipes) == -1)
|
||||
{
|
||||
int err = errno;
|
||||
slog(LG_ERROR, "ERROR: Couldn't create pipe for database update command: %s", strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe(stderr_pipes) == -1)
|
||||
{
|
||||
int err = errno;
|
||||
slog(LG_ERROR, "ERROR: Couldn't create pipe for database update command: %s", strerror(err));
|
||||
close(stdout_pipes[0]);
|
||||
close(stdout_pipes[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
|
||||
switch (pid)
|
||||
{
|
||||
case -1:
|
||||
errno1 = errno;
|
||||
slog(LG_ERROR, "Failed to fork for database update command: %s", strerror(errno1));
|
||||
return;
|
||||
case 0:
|
||||
connection_close_all_fds();
|
||||
close(stdout_pipes[0]);
|
||||
close(stderr_pipes[0]);
|
||||
dup2(stdout_pipes[1], 1);
|
||||
dup2(stderr_pipes[1], 2);
|
||||
close(stdout_pipes[1]);
|
||||
close(stderr_pipes[1]);
|
||||
execl("/bin/sh", "sh", "-c", command, NULL);
|
||||
write(2, "Failed to exec /bin/sh\n", 23);
|
||||
_exit(255);
|
||||
return;
|
||||
default:
|
||||
close(stdout_pipes[1]);
|
||||
close(stderr_pipes[1]);
|
||||
update_command_proc.out = connection_add("update_command_stdout", stdout_pipes[0], 0, recvq_put, NULL);
|
||||
update_command_proc.err = connection_add("update_command_stderr", stderr_pipes[0], 0, recvq_put, NULL);
|
||||
update_command_proc.out->recvq_handler = update_command_stdout_handler;
|
||||
update_command_proc.err->recvq_handler = update_command_stderr_handler;
|
||||
update_command_proc.pid = pid;
|
||||
update_command_proc.running = 1;
|
||||
childproc_add(pid, "db_update", update_command_finished, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2010 William Pitcock, et al.
|
||||
* The rights to this code are as documented under doc/LICENSE.
|
||||
*
|
||||
* Automatically AKILL a list of clients, given their operating parameters.
|
||||
*
|
||||
* Basically this builds a keyword patricia. O(NICKLEN) lookups at the price
|
||||
* of a longer startup process.
|
||||
*
|
||||
* Configuration.
|
||||
* ==============
|
||||
*
|
||||
* This module adds a new block to the config file:
|
||||
*
|
||||
* nicklists {
|
||||
* all = "/home/nenolod/atheme-production.hg4576/etc/nicklists/azn.txt";
|
||||
* nick = "/home/nenolod/atheme-production.hg4576/etc/nicklists/bottler-nicks.txt";
|
||||
* user = "/home/nenolod/atheme-production.hg4576/etc/nicklists/bottler-users.txt";
|
||||
* real = "/home/nenolod/atheme-production.hg4576/etc/nicklists/bottler-gecos.txt";
|
||||
* };
|
||||
*
|
||||
* You can add multiple all, nick, user and real entries. The entries will be merged.
|
||||
* I would also like to say: fuck you GNAA, you guys need to go play in fucking traffic.
|
||||
* Thanks for reading my crappy docs, and have a nice day.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_akillnicklist", false, _modinit, _moddeinit,
|
||||
"0.1",
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static mowgli_patricia_t *akillalllist = NULL;
|
||||
static mowgli_patricia_t *akillnicklist = NULL;
|
||||
static mowgli_patricia_t *akilluserlist = NULL;
|
||||
static mowgli_patricia_t *akillreallist = NULL;
|
||||
|
||||
static mowgli_list_t conft = { NULL, NULL, 0 };
|
||||
|
||||
static void
|
||||
add_contents_of_file_to_list(const char *filename, mowgli_patricia_t *list)
|
||||
{
|
||||
char value[BUFSIZE];
|
||||
FILE *f;
|
||||
|
||||
f = fopen(filename, "r");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
while (fgets(value, BUFSIZE, f) != NULL)
|
||||
{
|
||||
strip(value);
|
||||
|
||||
if (!*value)
|
||||
continue;
|
||||
|
||||
mowgli_patricia_add(list, value, (void *) 0x1);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static int
|
||||
nicklist_config_handler_all(mowgli_config_file_entry_t *entry)
|
||||
{
|
||||
add_contents_of_file_to_list(entry->vardata, akillalllist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nicklist_config_handler_nick(mowgli_config_file_entry_t *entry)
|
||||
{
|
||||
add_contents_of_file_to_list(entry->vardata, akillnicklist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nicklist_config_handler_user(mowgli_config_file_entry_t *entry)
|
||||
{
|
||||
add_contents_of_file_to_list(entry->vardata, akilluserlist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
nicklist_config_handler_real(mowgli_config_file_entry_t *entry)
|
||||
{
|
||||
add_contents_of_file_to_list(entry->vardata, akillreallist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
aknl_nickhook(hook_user_nick_t *data)
|
||||
{
|
||||
user_t *u;
|
||||
bool doit = false;
|
||||
char *username;
|
||||
|
||||
return_if_fail(data != NULL);
|
||||
return_if_fail(data->u != NULL);
|
||||
|
||||
u = data->u;
|
||||
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
|
||||
if (is_autokline_exempt(u))
|
||||
return;
|
||||
|
||||
username = u->user;
|
||||
if (*username == '~')
|
||||
username++;
|
||||
|
||||
if (mowgli_patricia_retrieve(akillalllist, u->nick) != NULL &&
|
||||
mowgli_patricia_retrieve(akillalllist, username) != NULL &&
|
||||
mowgli_patricia_retrieve(akillalllist, u->gecos) != NULL)
|
||||
doit = true;
|
||||
|
||||
if (mowgli_patricia_retrieve(akillnicklist, u->nick) != NULL)
|
||||
doit = true;
|
||||
|
||||
if (mowgli_patricia_retrieve(akilluserlist, username) != NULL)
|
||||
doit = true;
|
||||
|
||||
if (mowgli_patricia_retrieve(akillreallist, u->gecos) != NULL)
|
||||
doit = true;
|
||||
|
||||
if (!doit)
|
||||
return;
|
||||
|
||||
slog(LG_INFO, "AKNL: k-lining \2%s\2!%s@%s [%s] due to appearing to be a possible spambot", u->nick, u->user, u->host, u->gecos);
|
||||
kline_sts("*", "*", u->host, 86400, "Possible spambot");
|
||||
}
|
||||
|
||||
void
|
||||
_modinit(module_t *m)
|
||||
{
|
||||
add_subblock_top_conf("NICKLISTS", &conft);
|
||||
add_conf_item("ALL", &conft, nicklist_config_handler_all);
|
||||
add_conf_item("NICK", &conft, nicklist_config_handler_nick);
|
||||
add_conf_item("USER", &conft, nicklist_config_handler_user);
|
||||
add_conf_item("REAL", &conft, nicklist_config_handler_real);
|
||||
|
||||
akillalllist = mowgli_patricia_create(strcasecanon);
|
||||
akillnicklist = mowgli_patricia_create(strcasecanon);
|
||||
akilluserlist = mowgli_patricia_create(strcasecanon);
|
||||
akillreallist = mowgli_patricia_create(strcasecanon);
|
||||
|
||||
hook_add_event("user_add");
|
||||
hook_add_user_add(aknl_nickhook);
|
||||
hook_add_event("user_nickchange");
|
||||
hook_add_user_nickchange(aknl_nickhook);
|
||||
}
|
||||
|
||||
void
|
||||
_moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_user_add(aknl_nickhook);
|
||||
hook_del_user_nickchange(aknl_nickhook);
|
||||
|
||||
del_conf_item("ALL", &conft);
|
||||
del_conf_item("NICK", &conft);
|
||||
del_conf_item("USER", &conft);
|
||||
del_conf_item("REAL", &conft);
|
||||
del_top_conf("NICKLISTS");
|
||||
}
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Copyright (c) 2010 JD Horelick <jdhore1@gmail.com>
|
||||
* Rights to this code are as defined in doc/LICENSE.
|
||||
*
|
||||
* DEFCON implementation.
|
||||
*
|
||||
* By default, any setting except 5 will expire after 15 minutes,
|
||||
* to change this, add a defcon_timeout = X; option to the operserv{}
|
||||
* block in your atheme.con. X = amount of time in minutes for a defcon
|
||||
* setting to time out/expire.
|
||||
*
|
||||
*/
|
||||
#include "atheme.h"
|
||||
#define DEFCON_CMODE "R"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_defcon", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void os_cmd_defcon(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void defcon_nouserreg(hook_user_register_check_t *hdata);
|
||||
static void defcon_nochanreg(hook_channel_register_check_t *hdatac);
|
||||
static void defcon_useradd(hook_user_nick_t *data);
|
||||
static void defcon_timeoutfunc(void *dummy);
|
||||
static int level = 5;
|
||||
static unsigned int defcon_timeout = 900;
|
||||
static mowgli_eventloop_timer_t *defcon_timer = NULL;
|
||||
|
||||
command_t os_defcon = { "DEFCON", N_("Implements Defense Condition lockdowns."), PRIV_ADMIN, 1, os_cmd_defcon, { .path = "contrib/defcon" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_defcon);
|
||||
TAINT_ON("Using os_defcon", "Use of os_defcon is unsupported and not recommend. Use only at your own risk.");
|
||||
|
||||
/* Hooks for all the stuff defcon disables */
|
||||
hook_add_event("user_can_register");
|
||||
hook_add_user_can_register(defcon_nouserreg);
|
||||
hook_add_event("channel_can_register");
|
||||
hook_add_channel_can_register(defcon_nochanreg);
|
||||
hook_add_event("user_add");
|
||||
hook_add_user_add(defcon_useradd);
|
||||
|
||||
service_t *svs;
|
||||
svs = service_find("operserv");
|
||||
add_duration_conf_item("DEFCON_TIMEOUT", &svs->conf_table, 0, &defcon_timeout, "m", 900);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_defcon);
|
||||
|
||||
hook_del_user_can_register(defcon_nouserreg);
|
||||
hook_del_channel_can_register(defcon_nochanreg);
|
||||
hook_del_user_add(defcon_useradd);
|
||||
|
||||
service_t *svs;
|
||||
svs = service_find("operserv");
|
||||
del_conf_item("DEFCON_TIMEOUT", &svs->conf_table);
|
||||
|
||||
if (defcon_timer != NULL)
|
||||
mowgli_timer_destroy(base_eventloop, defcon_timer);
|
||||
}
|
||||
|
||||
static void defcon_nouserreg(hook_user_register_check_t *hdata)
|
||||
{
|
||||
return_if_fail(hdata != NULL);
|
||||
return_if_fail(hdata->si != NULL);
|
||||
|
||||
if (level < 5)
|
||||
{
|
||||
command_fail(hdata->si, fault_badparams, _("Registrations are currently disabled on this network, please try again later."));
|
||||
hdata->approved++;
|
||||
}
|
||||
}
|
||||
|
||||
static void defcon_nochanreg(hook_channel_register_check_t *hdatac)
|
||||
{
|
||||
return_if_fail(hdatac != NULL);
|
||||
return_if_fail(hdatac->si != NULL);
|
||||
|
||||
if (level < 5)
|
||||
{
|
||||
command_fail(hdatac->si, fault_badparams, _("Registrations are currently disabled on this network, please try again later."));
|
||||
hdatac->approved++;
|
||||
}
|
||||
}
|
||||
|
||||
static void defcon_useradd(hook_user_nick_t *data)
|
||||
{
|
||||
user_t *u = data->u;
|
||||
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
|
||||
if (level == 1)
|
||||
{
|
||||
slog(LG_INFO, "DEFCON:KLINE: %s!%s@%s", u->nick, u->user, u->host);
|
||||
kline_sts("*", u->user, u->host, 900, "This network is currently not accepting connections, please try again later.");
|
||||
}
|
||||
}
|
||||
|
||||
static void defcon_svsignore(void)
|
||||
{
|
||||
svsignore_t *svsignore;
|
||||
mowgli_node_t *n, *tn;
|
||||
|
||||
if (level <= 2)
|
||||
{
|
||||
MOWGLI_ITER_FOREACH(n, svs_ignore_list.head)
|
||||
{
|
||||
svsignore = (svsignore_t *)n->data;
|
||||
|
||||
if (!strcasecmp(svsignore->mask, "*@*"))
|
||||
return;
|
||||
}
|
||||
|
||||
slog(LG_INFO, "DEFCON:IGNORE:ADD");
|
||||
svsignore = svsignore_add("*@*", "DEFCON Level 1 or 2 activated");
|
||||
svsignore->setby = "DEFCON";
|
||||
svsignore->settime = CURRTIME;
|
||||
}
|
||||
else if (level >= 3)
|
||||
{
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, svs_ignore_list.head)
|
||||
{
|
||||
svsignore = (svsignore_t *)n->data;
|
||||
|
||||
if (!strcasecmp(svsignore->mask,"*@*"))
|
||||
{
|
||||
slog(LG_INFO, "DEFCON:IGNORE:REMOVE");
|
||||
svsignore_delete(svsignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void defcon_forcechanmodes(void)
|
||||
{
|
||||
channel_t *chptr;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
service_t *svs;
|
||||
char modesetbuf[256];
|
||||
char modeunsetbuf[256];
|
||||
|
||||
svs = service_find("operserv");
|
||||
|
||||
if (level <= 3)
|
||||
{
|
||||
snprintf(modesetbuf, sizeof modesetbuf, "+%s", DEFCON_CMODE);
|
||||
slog(LG_INFO, "DEFCON:MODE: %s", modesetbuf);
|
||||
MOWGLI_PATRICIA_FOREACH(chptr, &state, chanlist)
|
||||
{
|
||||
channel_mode_va(svs->me, chptr, 1, modesetbuf);
|
||||
}
|
||||
}
|
||||
else if (level >= 4)
|
||||
{
|
||||
snprintf(modeunsetbuf, sizeof modeunsetbuf, "-%s", DEFCON_CMODE);
|
||||
slog(LG_INFO, "DEFCON:MODE: %s", modeunsetbuf);
|
||||
MOWGLI_PATRICIA_FOREACH(chptr, &state, chanlist)
|
||||
{
|
||||
channel_mode_va(svs->me, chptr, 1, modeunsetbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void defcon_timeoutfunc(void *dummy)
|
||||
{
|
||||
service_t *svs;
|
||||
char buf[BUFSIZE];
|
||||
|
||||
svs = service_find("operserv");
|
||||
|
||||
level = 5;
|
||||
defcon_svsignore();
|
||||
defcon_forcechanmodes();
|
||||
slog(LG_INFO, "DEFCON:TIMEOUT");
|
||||
|
||||
snprintf(buf, sizeof buf, "The DEFCON level is now back to normal (\2%d\2). Sorry for any inconvenience this caused.", level);
|
||||
notice_global_sts(svs->me, "*", buf);
|
||||
}
|
||||
|
||||
static void os_cmd_defcon(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *defcon = parv[0];
|
||||
char buf[BUFSIZE];
|
||||
|
||||
if (!defcon)
|
||||
{
|
||||
command_success_nodata(si, _("Defense condition is currently level \2%d\2."), level);
|
||||
return;
|
||||
}
|
||||
|
||||
level = atoi(defcon);
|
||||
|
||||
if ((level <= 0) || (level > 5))
|
||||
{
|
||||
command_fail(si, fault_badparams, _("Defcon level must be between 1 and 5"));
|
||||
level = 5;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Call the 2 functions that don't use hooks */
|
||||
defcon_svsignore();
|
||||
defcon_forcechanmodes();
|
||||
|
||||
if (level < 5)
|
||||
{
|
||||
snprintf(buf, sizeof buf, "The DEFCON level has been changed to \2%d\2. We apologize for any inconvenience.", level);
|
||||
|
||||
if (defcon_timer == NULL)
|
||||
defcon_timer = mowgli_timer_add_once(base_eventloop, "defcon_timeout", defcon_timeoutfunc, NULL, defcon_timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(buf, sizeof buf, "The DEFCON level is now back to normal (\2%d\2). Sorry for any inconvenience this caused.", level);
|
||||
|
||||
mowgli_timer_destroy(base_eventloop, defcon_timer);
|
||||
defcon_timer = NULL;
|
||||
}
|
||||
|
||||
notice_global_sts(si->service->me, "*", buf);
|
||||
command_success_nodata(si, _("Defense condition set to level \2%d\2."), level);
|
||||
wallops(_("\2%s\2 set Defense condition to level \2%d\2."), get_oper_name(si), level);
|
||||
logcommand(si, CMDLOG_ADMIN, "DEFCON: \2%d\2", level);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,39 @@
|
|||
/* os_helpme.c - set user mode +h
|
||||
* elly+atheme@leptoquark.net
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "uplink.h" /* sts() */
|
||||
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_helpme", false, _modinit, _moddeinit,
|
||||
"os_helpme.c",
|
||||
"elly+atheme@leptoquark.net"
|
||||
);
|
||||
|
||||
static void os_cmd_helpme(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_helpme = { "HELPME", N_("Makes you into a network helper."),
|
||||
PRIV_HELPER, 0, os_cmd_helpme, { .path = "contrib/helpme" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_helpme);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_helpme);
|
||||
}
|
||||
|
||||
static void os_cmd_helpme(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
service_t *svs;
|
||||
|
||||
svs = service_find("operserv");
|
||||
|
||||
sts(":%s MODE %s :+h", svs->nick, si->su->nick);
|
||||
command_success_nodata(si, _("You are now a network helper."));
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock <nenolod -at- nenolod.net>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Facilitates watching what channels a user joins.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_joinmon", true, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.net>"
|
||||
);
|
||||
|
||||
static void watch_user_joins(hook_channel_joinpart_t *hdata);
|
||||
static void os_cmd_joinmon(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
static void write_jmdb(database_handle_t *db);
|
||||
static void db_h_jm(database_handle_t *db, const char *type);
|
||||
|
||||
command_t os_joinmon = { "JOINMON", N_("Monitors what channels a user is joining."), PRIV_USER_ADMIN, 3, os_cmd_joinmon, { .path = "contrib/joinmon" } };
|
||||
|
||||
struct joinmon_ {
|
||||
char *user;
|
||||
/* This module is Jamaican...mon. */
|
||||
time_t mon_ts;
|
||||
char *creator;
|
||||
char *reason;
|
||||
};
|
||||
|
||||
typedef struct joinmon_ joinmon_t;
|
||||
|
||||
mowgli_list_t os_monlist;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
if (!module_find_published("backend/opensex"))
|
||||
{
|
||||
slog(LG_INFO, "Module %s requires use of the OpenSEX database backend, refusing to load.", m->name);
|
||||
m->mflags = MODTYPE_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
hook_add_event("channel_join");
|
||||
hook_add_channel_join(watch_user_joins);
|
||||
hook_add_db_write(write_jmdb);
|
||||
|
||||
db_register_type_handler("JM", db_h_jm);
|
||||
|
||||
service_named_bind_command("operserv", &os_joinmon);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
hook_del_channel_join(watch_user_joins);
|
||||
hook_del_db_write(write_jmdb);
|
||||
|
||||
db_unregister_type_handler("JM");
|
||||
|
||||
service_named_unbind_command("operserv", &os_joinmon);
|
||||
}
|
||||
|
||||
static void write_jmdb(database_handle_t *db)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, os_monlist.head)
|
||||
{
|
||||
joinmon_t *l = n->data;
|
||||
|
||||
db_start_row(db, "JM");
|
||||
db_write_word(db, l->user);
|
||||
db_write_time(db, l->mon_ts);
|
||||
db_write_word(db, l->creator);
|
||||
db_write_str(db, l->reason);
|
||||
db_commit_row(db);
|
||||
}
|
||||
}
|
||||
|
||||
static void db_h_jm(database_handle_t *db, const char *type)
|
||||
{
|
||||
const char *user = db_sread_word(db);
|
||||
time_t mon_ts = db_sread_time(db);
|
||||
const char *creator = db_sread_word(db);
|
||||
const char *reason = db_sread_str(db);
|
||||
|
||||
joinmon_t *l = smalloc(sizeof(joinmon_t));
|
||||
l->user = sstrdup(user);
|
||||
l->mon_ts = mon_ts;
|
||||
l->creator = sstrdup(creator);
|
||||
l->reason = sstrdup(reason);
|
||||
mowgli_node_add(l, mowgli_node_create(), &os_monlist);
|
||||
}
|
||||
|
||||
static void watch_user_joins(hook_channel_joinpart_t *hdata)
|
||||
{
|
||||
mowgli_node_t *n;
|
||||
chanuser_t *cu = hdata->cu;
|
||||
joinmon_t *l;
|
||||
|
||||
if (cu == NULL)
|
||||
return;
|
||||
|
||||
if (!(cu->user->server->flags & SF_EOB))
|
||||
return;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, os_monlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
/* Use match so you can monitor patterns like SomeBot* or
|
||||
* t???h?????1
|
||||
*/
|
||||
if (!match(l->user, cu->user->nick))
|
||||
{
|
||||
/* Use LG_INFO because there's really no better logtype and creating
|
||||
* one just for this module (ie: having to put stuff in core) is
|
||||
* kind of stupid. Give it it's own logtype if logtypes are ever
|
||||
* addable by modules.
|
||||
*/
|
||||
slog(LG_INFO, "JOINMON: \2%s\2 who matches \2%s\2 has joined \2%s\2",
|
||||
cu->user->nick, l->user, cu->chan->name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void os_cmd_joinmon(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *action = parv[0];
|
||||
char *pattern = parv[1];
|
||||
char *reason = parv[2];
|
||||
mowgli_node_t *n, *tn;
|
||||
joinmon_t *l;
|
||||
|
||||
if (!action)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "JOINMON");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: JOINMON ADD|DEL|LIST [parameters]"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp("ADD", action))
|
||||
{
|
||||
if (!pattern)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "JOINMON");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: JOINMON ADD <pattern> [reason]"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (si->smu == NULL)
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("You are not logged in."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* search for it */
|
||||
MOWGLI_ITER_FOREACH(n, os_monlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
if (!irccasecmp(l->user, pattern))
|
||||
{
|
||||
command_success_nodata(si, _("Pattern \2%s\2 is already being monitored."), pattern);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
l = smalloc(sizeof(joinmon_t));
|
||||
l->user = sstrdup(pattern);
|
||||
l->mon_ts = CURRTIME;;
|
||||
l->creator = sstrdup(get_source_name(si));
|
||||
|
||||
if (reason)
|
||||
{
|
||||
l->reason = sstrdup(reason);
|
||||
logcommand(si, CMDLOG_ADMIN, "JOINMON:ADD: \2%s\2 (Reason: \2%s\2)", pattern, reason);
|
||||
}
|
||||
else
|
||||
{
|
||||
l->reason = _("None");
|
||||
logcommand(si, CMDLOG_ADMIN, "JOINMON:ADD: \2%s\2", pattern);
|
||||
}
|
||||
|
||||
n = mowgli_node_create();
|
||||
mowgli_node_add(l, n, &os_monlist);
|
||||
|
||||
command_success_nodata(si, _("\2%s\2 is now being monitored."), pattern);
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("DEL", action))
|
||||
{
|
||||
if (!pattern)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "JOINMON");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: JOINMON DEL <pattern>"));
|
||||
return;
|
||||
}
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, os_monlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
if (!irccasecmp(l->user, pattern))
|
||||
{
|
||||
logcommand(si, CMDLOG_ADMIN, "JOINMON:DEL: \2%s\2", l->user);
|
||||
|
||||
mowgli_node_delete(n, &os_monlist);
|
||||
|
||||
free(l->user);
|
||||
free(l->creator);
|
||||
free(l->reason);
|
||||
free(l);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
command_success_nodata(si, _("Pattern \2%s\2 not found in joinmon database."), pattern);
|
||||
return;
|
||||
}
|
||||
else if (!strcasecmp("LIST", action))
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
struct tm tm;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, os_monlist.head)
|
||||
{
|
||||
l = n->data;
|
||||
|
||||
tm = *localtime(&l->mon_ts);
|
||||
strftime(buf, BUFSIZE, TIME_FORMAT, &tm);
|
||||
command_success_nodata(si, "Pattern: \2%s\2, Reason: \2%s\2 (%s - %s)",
|
||||
l->user, l->reason, l->creator, buf);
|
||||
}
|
||||
command_success_nodata(si, "End of list.");
|
||||
logcommand(si, CMDLOG_GET, "JOINMON:LIST");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "JOINMON");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Kill users through services, requested by christel@freenode.
|
||||
*
|
||||
* This differs from the ircd /kill command in that it does not show to
|
||||
* normal users who issued the kill, although the reason will usually be
|
||||
* shown. This is useful in cases where a kline would normally be used,
|
||||
* but would not remove the user, but the user cannot (fully) reconnect.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_kill", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void os_cmd_kill(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_kill = { "KILL", "Kill a user with Services.", PRIV_OMODE, 2, os_cmd_kill, { .path = "contrib/kill" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_kill);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_kill);
|
||||
}
|
||||
|
||||
static void os_cmd_kill(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
user_t *target;
|
||||
|
||||
if(!parv[0] || !parv[1])
|
||||
{
|
||||
command_fail(si, fault_badparams, "Usage: \2KILL\2 <target> <reason>");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(target = user_find_named(parv[0])))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 is not on the network", parv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_ADMIN, "KILL: \2%s\2 (reason: \2%s\2)", target->nick, parv[1]);
|
||||
command_success_nodata(si, "\2%s\2 has been killed.", target->nick);
|
||||
|
||||
kill_user(si->service->me, target, "Requested: %s", parv[1]);
|
||||
}
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2007 Atheme Development Group
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Autokline channels.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_klinechan", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Jilles Tjoelker <http://www.stack.nl/~jilles/irc/>"
|
||||
);
|
||||
|
||||
static void os_cmd_klinechan(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void os_cmd_listklinechans(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_klinechan = { "KLINECHAN", "Klines all users joining a channel.",
|
||||
PRIV_MASS_AKILL, 3, os_cmd_klinechan, { .path = "contrib/klinechan" } };
|
||||
command_t os_listklinechans = { "LISTKLINECHAN", "Lists active K:line channels.", PRIV_MASS_AKILL, 1, os_cmd_listklinechans, { .path = "contrib/listklinechans" } };
|
||||
|
||||
static void klinechan_check_join(hook_channel_joinpart_t *hdata);
|
||||
static void klinechan_show_info(hook_channel_req_t *hdata);
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_klinechan);
|
||||
service_named_bind_command("operserv", &os_listklinechans);
|
||||
hook_add_event("channel_join");
|
||||
hook_add_first_channel_join(klinechan_check_join);
|
||||
hook_add_event("channel_info");
|
||||
hook_add_channel_info(klinechan_show_info);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_klinechan);
|
||||
service_named_unbind_command("operserv", &os_listklinechans);
|
||||
hook_del_channel_join(klinechan_check_join);
|
||||
hook_del_channel_info(klinechan_show_info);
|
||||
}
|
||||
|
||||
static void klinechan_check_join(hook_channel_joinpart_t *hdata)
|
||||
{
|
||||
mychan_t *mc;
|
||||
chanuser_t *cu = hdata->cu;
|
||||
service_t *svs;
|
||||
char reason[256];
|
||||
|
||||
svs = service_find("operserv");
|
||||
if (svs == NULL)
|
||||
return;
|
||||
|
||||
if (cu == NULL || is_internal_client(cu->user))
|
||||
return;
|
||||
|
||||
if (!(mc = MYCHAN_FROM(cu->chan)))
|
||||
return;
|
||||
|
||||
if (metadata_find(mc, "private:klinechan:closer"))
|
||||
{
|
||||
if (has_priv_user(cu->user, PRIV_JOIN_STAFFONLY))
|
||||
notice(svs->me->nick, cu->user->nick,
|
||||
"Warning: %s klines normal users",
|
||||
cu->chan->name);
|
||||
else if (is_autokline_exempt(cu->user))
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
snprintf(buf, sizeof(buf), "Not klining *@%s due to klinechan %s (user %s!%s@%s is exempt)",
|
||||
cu->user->host, cu->chan->name,
|
||||
cu->user->nick, cu->user->user, cu->user->host);
|
||||
wallops_sts(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(reason, sizeof reason, "Joining %s",
|
||||
cu->chan->name);
|
||||
slog(LG_INFO, "klinechan_check_join(): klining \2*@%s\2 (user \2%s!%s@%s\2 joined \2%s\2)",
|
||||
cu->user->host, cu->user->nick,
|
||||
cu->user->user, cu->user->host,
|
||||
cu->chan->name);
|
||||
kline_sts("*", "*", cu->user->host, 86400, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void klinechan_show_info(hook_channel_req_t *hdata)
|
||||
{
|
||||
metadata_t *md;
|
||||
const char *setter, *reason;
|
||||
time_t ts;
|
||||
struct tm tm;
|
||||
char strfbuf[BUFSIZE];
|
||||
|
||||
if (!has_priv(hdata->si, PRIV_CHAN_AUSPEX))
|
||||
return;
|
||||
md = metadata_find(hdata->mc, "private:klinechan:closer");
|
||||
if (md == NULL)
|
||||
return;
|
||||
setter = md->value;
|
||||
md = metadata_find(hdata->mc, "private:klinechan:reason");
|
||||
reason = md != NULL ? md->value : "unknown";
|
||||
md = metadata_find(hdata->mc, "private:klinechan:timestamp");
|
||||
ts = md != NULL ? atoi(md->value) : 0;
|
||||
|
||||
tm = *localtime(&ts);
|
||||
strftime(strfbuf, sizeof strfbuf, TIME_FORMAT, &tm);
|
||||
|
||||
command_success_nodata(hdata->si, "%s had \2automatic klines\2 enabled on it by %s on %s (%s)", hdata->mc->name, setter, strfbuf, reason);
|
||||
}
|
||||
|
||||
static void os_cmd_klinechan(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
char *action = parv[1];
|
||||
char *reason = parv[2];
|
||||
mychan_t *mc;
|
||||
|
||||
if (!target || !action)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "KLINECHAN");
|
||||
command_fail(si, fault_needmoreparams, "Usage: KLINECHAN <#channel> <ON|OFF> [reason]");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(mc = mychan_find(target)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 is not registered.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(action, "ON"))
|
||||
{
|
||||
if (!reason)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "KLINECHAN");
|
||||
command_fail(si, fault_needmoreparams, "Usage: KLINECHAN <#channel> ON <reason>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mc->flags & CHAN_LOG)
|
||||
{
|
||||
command_fail(si, fault_noprivs, "\2%s\2 cannot be closed.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadata_find(mc, "private:klinechan:closer"))
|
||||
{
|
||||
command_fail(si, fault_nochange, "\2%s\2 is already on autokline.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_add(mc, "private:klinechan:closer", si->su->nick);
|
||||
metadata_add(mc, "private:klinechan:reason", reason);
|
||||
metadata_add(mc, "private:klinechan:timestamp", number_to_string(CURRTIME));
|
||||
|
||||
wallops("%s enabled automatic klines on the channel \2%s\2 (%s).", get_oper_name(si), target, reason);
|
||||
logcommand(si, CMDLOG_ADMIN, "KLINECHAN:ON: \2%s\2 (reason: \2%s\2)", target, reason);
|
||||
command_success_nodata(si, "Klining all users joining \2%s\2.", target);
|
||||
}
|
||||
else if (!strcasecmp(action, "OFF"))
|
||||
{
|
||||
if (!metadata_find(mc, "private:klinechan:closer"))
|
||||
{
|
||||
command_fail(si, fault_nochange, "\2%s\2 is not closed.", target);
|
||||
return;
|
||||
}
|
||||
|
||||
metadata_delete(mc, "private:klinechan:closer");
|
||||
metadata_delete(mc, "private:klinechan:reason");
|
||||
metadata_delete(mc, "private:klinechan:timestamp");
|
||||
|
||||
wallops("%s disabled automatic klines on the channel \2%s\2.", get_oper_name(si), target);
|
||||
logcommand(si, CMDLOG_ADMIN, "KLINECHAN:OFF: \2%s\2", target);
|
||||
command_success_nodata(si, "No longer klining users joining \2%s\2.", target);
|
||||
}
|
||||
else
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "KLINECHAN");
|
||||
command_fail(si, fault_badparams, "Usage: KLINECHAN <#channel> <ON|OFF> [reason]");
|
||||
}
|
||||
}
|
||||
|
||||
static void os_cmd_listklinechans(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
const char *pattern;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
mychan_t *mc;
|
||||
metadata_t *md;
|
||||
int matches = 0;
|
||||
|
||||
pattern = parc >= 1 ? parv[0] : "*";
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(mc, &state, mclist)
|
||||
{
|
||||
md = metadata_find(mc, "private:klinechan:closer");
|
||||
if (md == NULL)
|
||||
continue;
|
||||
if (!match(pattern, mc->name))
|
||||
{
|
||||
command_success_nodata(si, "- %-30s", mc->name);
|
||||
matches++;
|
||||
}
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_ADMIN, "LISTKLINECHANS: \2%s\2 (\2%d\2 matches)", pattern, matches);
|
||||
if (matches == 0)
|
||||
command_success_nodata(si, _("No K:line channels matched pattern \2%s\2"), pattern);
|
||||
else
|
||||
command_success_nodata(si, ngettext(N_("\2%d\2 match for pattern \2%s\2"),
|
||||
N_("\2%d\2 matches for pattern \2%s\2"), matches), matches, pattern);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2006 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* This file contains functionality which implements the OService MODEALL
|
||||
* command.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_modeall", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void os_cmd_modeall(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_modeall = { "MODEALL", N_("Changes modes on all channels."), PRIV_OMODE, 2, os_cmd_modeall, { .path = "contrib/os_modeall" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_modeall);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_modeall);
|
||||
}
|
||||
|
||||
static void set_channel_mode(service_t *s, channel_t *c, int modeparc, char *modeparv[])
|
||||
{
|
||||
channel_mode(s->me, c, modeparc, modeparv);
|
||||
}
|
||||
|
||||
static void os_cmd_modeall(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *mode = parv[0];
|
||||
channel_t *c;
|
||||
int modeparc;
|
||||
char *modeparv[256];
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
int count = 0;
|
||||
|
||||
if (!mode)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "MODEALL");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: MODEALL <parameters>"));
|
||||
return;
|
||||
}
|
||||
|
||||
modeparc = sjtoken(mode, ' ', modeparv);
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(c, &state, chanlist)
|
||||
{
|
||||
set_channel_mode(si->service, c, modeparc, modeparv);
|
||||
count++;
|
||||
}
|
||||
|
||||
command_success_nodata(si, _("Set modes \2%s\2 on \2%d\2 channels."), mode, count);
|
||||
wallops("\2%s\2 is using MODEALL (set: \2%s\2)",
|
||||
get_oper_name(si), mode);
|
||||
logcommand(si, CMDLOG_ADMIN, "MODEALL: \2%s\2", mode);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) 2005 William Pitcock, et al.
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* ping spammer thingy
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_pingspam", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
char *notices[] =
|
||||
{
|
||||
"Scanning for proxies.",
|
||||
"Killing off bottlers.",
|
||||
"LOL ok so like we are teh SKANZ0RZING j00 becuz well like OMG deze bots r h3r3 an liek they are FL00DING!!#@! ignore plz",
|
||||
"gaben",
|
||||
"Please ignore this notice.",
|
||||
"Scanning for warez.",
|
||||
"All your pr0n are belong to us!",
|
||||
"Move over! This is the police!",
|
||||
"This notice brought to you by Burma-Shave.",
|
||||
"They're coming...",
|
||||
":)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(::)(:",
|
||||
"lolz!",
|
||||
"<Hikaru> your a pagan",
|
||||
"* Ads needs to shower soon",
|
||||
"<Hik`Coding> Don't make me get Yakuza on you",
|
||||
"beu fails it",
|
||||
"BAN KAI~!$"
|
||||
};
|
||||
|
||||
char *phrases[] =
|
||||
{
|
||||
"",
|
||||
" please-ignore",
|
||||
" proxy scan",
|
||||
" ignore me",
|
||||
" <3 neostats",
|
||||
};
|
||||
|
||||
void pingspam(user_t *u);
|
||||
static void user_add_hook(hook_user_nick_t *data);
|
||||
static void os_cmd_pingspam(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void os_cmd_autopingspam(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_pingspam = { "PINGSPAM", "Spam a user with pings from every service, plus some bonus notices.", PRIV_OMODE, 1, os_cmd_pingspam, { .path = "contrib/pingspam" } };
|
||||
command_t os_autopingspam = { "AUTOPINGSPAM", "Spam connecting users with pings from every service, plus some bonus notices (setting).", PRIV_ADMIN, 1, os_cmd_autopingspam, { .path = "contrib/autopingspam" } };
|
||||
|
||||
int spamming;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
spamming = 0;
|
||||
|
||||
service_named_bind_command("operserv", &os_pingspam);
|
||||
service_named_bind_command("operserv", &os_autopingspam);
|
||||
|
||||
hook_add_event("user_add");
|
||||
hook_add_user_add(user_add_hook);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_pingspam);
|
||||
service_named_unbind_command("operserv", &os_autopingspam);
|
||||
hook_del_user_add(user_add_hook);
|
||||
}
|
||||
|
||||
static void user_add_hook(hook_user_nick_t *data)
|
||||
{
|
||||
user_t *u;
|
||||
|
||||
u = data->u;
|
||||
if (u == NULL)
|
||||
return;
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
if (spamming)
|
||||
pingspam(u);
|
||||
}
|
||||
|
||||
static void os_cmd_pingspam(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *target = parv[0];
|
||||
user_t *u;
|
||||
|
||||
if(!target)
|
||||
{
|
||||
command_fail(si, fault_badparams, "Usage: \2PINGSPAM\2 <target>");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(u = user_find_named(target)))
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "\2%s\2 is not on the network", target);
|
||||
return;
|
||||
}
|
||||
|
||||
pingspam(u);
|
||||
command_success_nodata(si, "\2%s\2 has been pwned.", target);
|
||||
logcommand(si, CMDLOG_ADMIN, "PINGSPAM: \2%s\2", target);
|
||||
}
|
||||
|
||||
static void os_cmd_autopingspam(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
char *mode = parv[0];
|
||||
|
||||
if(!mode)
|
||||
{
|
||||
command_success_nodata(si, "Auto-pingspam is currently \2%s\2", spamming ? "ON" : "OFF");
|
||||
return;
|
||||
}
|
||||
|
||||
if(strcasecmp(mode, "on") == 0 || atoi(mode))
|
||||
{
|
||||
spamming = 1;
|
||||
command_success_nodata(si, "Auto-pingspam is now \2ON\2");
|
||||
}else{
|
||||
spamming = 0;
|
||||
command_success_nodata(si, "Auto-pingspam is now \2OFF\2");
|
||||
}
|
||||
}
|
||||
|
||||
void pingspam(user_t *u)
|
||||
{
|
||||
user_t *sptr;
|
||||
mowgli_node_t *n;
|
||||
int i;
|
||||
service_t *svs;
|
||||
|
||||
if((svs = service_find("global")) != NULL)
|
||||
for(i = 0;i < 6;i++)
|
||||
notice(svs->me->nick, u->nick, "%s", notices[rand() % sizeof(notices) / sizeof(char*)]);
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, me.me->userlist.head)
|
||||
{
|
||||
sptr = n->data;
|
||||
msg(sptr->nick, u->nick, "\001PING %ld%s\001",
|
||||
time(NULL),
|
||||
phrases[rand() % sizeof(phrases) / sizeof(char*)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2009 Jilles Tjoelker, et al
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Monitors exit of given processes, using kqueue.
|
||||
* The kqueue is added to the main poll loop.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include <sys/event.h>
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_procwatch", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void procwatch_readhandler(connection_t *cptr);
|
||||
|
||||
static void os_cmd_procwatch(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_procwatch = { "PROCWATCH", "Notifies snoop channel on process exit.",
|
||||
PRIV_ADMIN, 1, os_cmd_procwatch, { .path = "contrib/procwatch" } };
|
||||
|
||||
static connection_t *kq_conn;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
int kq;
|
||||
|
||||
kq = kqueue();
|
||||
if (kq == -1)
|
||||
{
|
||||
m->mflags = MODTYPE_FAIL;
|
||||
return;
|
||||
}
|
||||
kq_conn = connection_add("procwatch kqueue", kq, 0, procwatch_readhandler, NULL);
|
||||
|
||||
service_named_bind_command("operserv", &os_procwatch);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
if (kq_conn != NULL)
|
||||
connection_close_soon(kq_conn);
|
||||
service_named_unbind_command("operserv", &os_procwatch);
|
||||
}
|
||||
|
||||
static void procwatch_readhandler(connection_t *cptr)
|
||||
{
|
||||
struct kevent ev;
|
||||
|
||||
if (cptr != kq_conn)
|
||||
{
|
||||
slog(LG_INFO, "procwatch_readhandler(): called with unexpected fd %d", cptr->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
while (kevent(cptr->fd, NULL, 0, &ev, 1, &(const struct timespec){ 0, 0 }) > 0)
|
||||
{
|
||||
slog(LG_INFO, "PROCWATCH: %ld exited with status %x",
|
||||
(long)ev.ident, (unsigned)ev.data);
|
||||
}
|
||||
}
|
||||
|
||||
static void os_cmd_procwatch(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
long v;
|
||||
char *end;
|
||||
struct kevent ev;
|
||||
|
||||
if (parc == 0)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "PROCWATCH");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: PROCWATCH <pid>"));
|
||||
return;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
v = strtol(parv[0], &end, 10);
|
||||
if (errno != 0 || *end != '\0' || v < 0 || (pid_t)v != v)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INVALID_PARAMS, "PROCWATCH");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: PROCWATCH <pid>"));
|
||||
return;
|
||||
}
|
||||
EV_SET(&ev, v, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_EXIT, 0, NULL);
|
||||
if (kevent(kq_conn->fd, &ev, 1, NULL, 0, NULL) == -1)
|
||||
{
|
||||
command_fail(si, fault_toomany, _("Failed to add pid %ld"), v);
|
||||
return;
|
||||
}
|
||||
command_success_nodata(si, "Added pid %ld to list.", v);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Does an A record lookup.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_resolve", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void os_cmd_resolve(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t cmd_resolve = { "RESOLVE", N_("Perform DNS lookup on hostname"), PRIV_ADMIN, 1, os_cmd_resolve, { .path = "contrib/os_resolve" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &cmd_resolve);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &cmd_resolve);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
dns_query_t dns_query;
|
||||
sourceinfo_t *si;
|
||||
} resolve_req_t;
|
||||
|
||||
mowgli_heap_t *request_heap = NULL;
|
||||
|
||||
static void resolve_cb(void *vptr, dns_reply_t *reply)
|
||||
{
|
||||
resolve_req_t *req = vptr;
|
||||
char buf[BUFSIZE];
|
||||
|
||||
return_if_fail(vptr != NULL);
|
||||
return_if_fail(reply != NULL);
|
||||
|
||||
if (reply->addr.saddr.sa.sa_family != AF_INET)
|
||||
return;
|
||||
|
||||
inet_ntop(reply->addr.saddr.sa.sa_family, &reply->addr.saddr.sin.sin_addr, buf, reply->addr.saddr_len);
|
||||
|
||||
command_success_nodata(req->si, "Result is %s", buf);
|
||||
|
||||
mowgli_heap_free(request_heap, req);
|
||||
object_unref(req->si);
|
||||
}
|
||||
|
||||
static void os_cmd_resolve(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
resolve_req_t *req;
|
||||
|
||||
if (request_heap == NULL)
|
||||
request_heap = mowgli_heap_create(sizeof(resolve_req_t), 32, BH_LAZY);
|
||||
|
||||
if (!parv[0])
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "RESOLVE");
|
||||
return;
|
||||
}
|
||||
|
||||
req = mowgli_heap_alloc(request_heap);
|
||||
|
||||
req->si = si;
|
||||
req->dns_query.ptr = req;
|
||||
req->dns_query.callback = resolve_cb;
|
||||
|
||||
gethost_byname_type(parv[0], &req->dns_query, T_A);
|
||||
|
||||
object_ref(req->si);
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Jilles Tjoelker
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Dump/restore channel modes
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_savechanmodes", false, _modinit, _moddeinit,
|
||||
"$Revision: 7785 $",
|
||||
"Jilles Tjoelker <jilles -at- stack.nl>"
|
||||
);
|
||||
|
||||
static void os_cmd_savechanmodes(sourceinfo_t *si, int parc, char *parv[]);
|
||||
static void os_cmd_loadchanmodes(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_savechanmodes = { "SAVECHANMODES", "Dumps channel modes to a file.",
|
||||
PRIV_ADMIN, 1, os_cmd_savechanmodes, { .path = "contrib/savechanmodes" } };
|
||||
command_t os_loadchanmodes = { "LOADCHANMODES", "Restores channel modes from a file.",
|
||||
PRIV_ADMIN, 1, os_cmd_loadchanmodes, { .path = "contrib/loadchanmodes" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_savechanmodes);
|
||||
service_named_bind_command("operserv", &os_loadchanmodes);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_savechanmodes);
|
||||
service_named_unbind_command("operserv", &os_loadchanmodes);
|
||||
}
|
||||
|
||||
static void os_cmd_savechanmodes(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
FILE *out;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
channel_t *c;
|
||||
mowgli_node_t *n;
|
||||
chanban_t *cb;
|
||||
|
||||
if (!(out = fopen(DATADIR "/chanmodes.txt", "w")))
|
||||
{
|
||||
command_fail(si, fault_nosuch_source, "Cannot open %s: %s",
|
||||
DATADIR "/chanmodes.txt", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_ADMIN, "SAVECHANMODES");
|
||||
wallops("\2%s\2 is dumping channel modes", get_oper_name(si));
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(c, &state, chanlist)
|
||||
{
|
||||
fprintf(out, "chan %s %s\n", c->name, channel_modes(c, true));
|
||||
if (c->topic)
|
||||
fprintf(out, "topic %s %lu %s\n", c->topic_setter,
|
||||
(unsigned long)c->topicts,
|
||||
c->topic);
|
||||
MOWGLI_ITER_FOREACH(n, c->bans.head)
|
||||
{
|
||||
cb = n->data;
|
||||
fprintf(out, "ban %c %s\n", cb->type, cb->mask);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
|
||||
command_success_nodata(si, "Channel modes saved to %s.",
|
||||
DATADIR "/chanmodes.txt");
|
||||
}
|
||||
|
||||
static channel_t *restore_channel(char *name, char *modes)
|
||||
{
|
||||
channel_t *c;
|
||||
int modeparc;
|
||||
char *modeparv[256];
|
||||
service_t *svs;
|
||||
|
||||
svs = service_find("operserv");
|
||||
if (svs == NULL)
|
||||
svs = chansvs.me;
|
||||
|
||||
join(name, chansvs.nick);
|
||||
c = channel_find(name);
|
||||
if (c != NULL)
|
||||
{
|
||||
modeparc = sjtoken(modes, ' ', modeparv);
|
||||
channel_mode(svs->me, c, modeparc, modeparv);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static void os_cmd_loadchanmodes(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
FILE *in;
|
||||
char *item, buf[2048];
|
||||
char *name, *modes, *setter, *tsstr, *topic, *type, *mask;
|
||||
time_t ts, prevtopicts;
|
||||
channel_t *c;
|
||||
int line;
|
||||
|
||||
if (!(in = fopen(DATADIR "/chanmodes.txt", "r")))
|
||||
{
|
||||
command_fail(si, fault_nosuch_source, "Cannot open %s: %s",
|
||||
DATADIR "/chanmodes.txt", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
logcommand(si, CMDLOG_ADMIN, "LOADCHANMODES");
|
||||
wallops("\2%s\2 is restoring channel modes", get_oper_name(si));
|
||||
|
||||
line = 0;
|
||||
c = NULL;
|
||||
while (fgets(buf, sizeof buf, in))
|
||||
{
|
||||
line++;
|
||||
item = strtok(buf, " ");
|
||||
strip(item);
|
||||
|
||||
if (item == NULL || *item == '#')
|
||||
continue;
|
||||
|
||||
if (!strcmp(item, "chan"))
|
||||
{
|
||||
name = strtok(NULL, " ");
|
||||
modes = strtok(NULL, "\n");
|
||||
|
||||
if (name == NULL || modes == NULL)
|
||||
continue;
|
||||
c = restore_channel(name, modes);
|
||||
}
|
||||
else if (!strcmp(item, "topic"))
|
||||
{
|
||||
if (c == NULL)
|
||||
continue;
|
||||
|
||||
setter = strtok(NULL, " ");
|
||||
tsstr = strtok(NULL, " ");
|
||||
topic = strtok(NULL, "\n");
|
||||
|
||||
if (setter == NULL || tsstr == NULL || topic == NULL)
|
||||
continue;
|
||||
if (c->topic != NULL)
|
||||
continue;
|
||||
prevtopicts = c->topicts;
|
||||
ts = strtoul(tsstr, NULL, 10);
|
||||
handle_topic(c, setter, ts, topic);
|
||||
topic_sts(c, chansvs.me->me, setter, ts, prevtopicts, topic);
|
||||
}
|
||||
else if (!strcmp(item, "ban"))
|
||||
{
|
||||
if (c == NULL)
|
||||
continue;
|
||||
|
||||
type = strtok(NULL, " ");
|
||||
mask = strtok(NULL, "\n");
|
||||
|
||||
if (type == NULL || mask == NULL)
|
||||
continue;
|
||||
modestack_mode_param(chansvs.nick, c, MTYPE_ADD, type[0], mask);
|
||||
chanban_add(c, mask, type[0]);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(in);
|
||||
|
||||
command_success_nodata(si, "Channel modes restored from %s.",
|
||||
DATADIR "/chanmodes.txt");
|
||||
command_success_nodata(si, "Remember to restart services to make %s leave channels it should not be in.",
|
||||
chansvs.nick);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,54 @@
|
|||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_tabletest", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static void os_cmd_tabletest(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_tabletest = { "TABLETEST", "Table test.", AC_NONE, 0, os_cmd_tabletest, { .path = "" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_tabletest);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_tabletest);
|
||||
}
|
||||
|
||||
static void os_cmd_tabletest(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
table_t *t = table_new("Table \2test\2");
|
||||
table_row_t *r = table_row_new(t);
|
||||
|
||||
table_cell_associate(r, "foo", "bar");
|
||||
table_cell_associate(r, "F", "-");
|
||||
table_cell_associate(r, "baz", "splork");
|
||||
|
||||
r = table_row_new(t);
|
||||
|
||||
table_cell_associate(r, "foo", "1");
|
||||
table_cell_associate(r, "F", "+");
|
||||
table_cell_associate(r, "baz", "2");
|
||||
|
||||
r = table_row_new(t);
|
||||
|
||||
table_cell_associate(r, "foo", "beagle4");
|
||||
table_cell_associate(r, "F", "+");
|
||||
table_cell_associate(r, "baz", "boo");
|
||||
|
||||
command_success_table(si, t);
|
||||
|
||||
object_unref(t);
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2006 Jilles Tjoelker, et al
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Calls a command without a user_t.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_testcmd", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
struct testcmddata
|
||||
{
|
||||
sourceinfo_t *prevsi;
|
||||
bool got_result;
|
||||
};
|
||||
|
||||
static void os_cmd_testcmd(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
static void testcmd_command_fail(sourceinfo_t *si, faultcode_t code, const char *message);
|
||||
static void testcmd_command_success_nodata(sourceinfo_t *si, const char *message);
|
||||
static void testcmd_command_success_string(sourceinfo_t *si, const char *result, const char *message);
|
||||
|
||||
command_t os_testcmd = { "TESTCMD", "Executes a command without a user_t.",
|
||||
AC_NONE, 3, os_cmd_testcmd, { .path = "contrib/testcmd" } };
|
||||
|
||||
struct sourceinfo_vtable testcmd_vtable = {
|
||||
.description = "testcmd",
|
||||
.cmd_fail = testcmd_command_fail,
|
||||
.cmd_success_nodata = testcmd_command_success_nodata,
|
||||
.cmd_success_string = testcmd_command_success_string
|
||||
};
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_testcmd);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
service_named_unbind_command("operserv", &os_testcmd);
|
||||
}
|
||||
|
||||
static void testcmd_command_fail(sourceinfo_t *si, faultcode_t code, const char *message)
|
||||
{
|
||||
struct testcmddata *udata = si->callerdata;
|
||||
|
||||
command_success_nodata(udata->prevsi, "Command failed with fault %d, \"%s\"", code, message);
|
||||
udata->got_result = true;
|
||||
}
|
||||
|
||||
static void testcmd_command_success_nodata(sourceinfo_t *si, const char *message)
|
||||
{
|
||||
struct testcmddata *udata = si->callerdata;
|
||||
|
||||
if (udata->got_result)
|
||||
command_success_nodata(udata->prevsi, "More comment \"%s\"", message);
|
||||
else
|
||||
command_success_nodata(udata->prevsi, "Command succeeded with no data, \"%s\"", message);
|
||||
udata->got_result = true;
|
||||
}
|
||||
|
||||
static void testcmd_command_success_string(sourceinfo_t *si, const char *result, const char *message)
|
||||
{
|
||||
struct testcmddata *udata = si->callerdata;
|
||||
|
||||
command_success_nodata(udata->prevsi, "Command succeeded with string \"%s\", \"%s\"", result, message);
|
||||
udata->got_result = true;
|
||||
}
|
||||
|
||||
static void os_cmd_testcmd(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
service_t *svs;
|
||||
command_t *cmd;
|
||||
sourceinfo_t newsi;
|
||||
struct testcmddata udata;
|
||||
int newparc;
|
||||
char *newparv[256];
|
||||
|
||||
if (parc < 2)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "TESTCMD");
|
||||
command_fail(si, fault_needmoreparams, "Syntax: TESTCMD <service> <command> [arguments]");
|
||||
return;
|
||||
}
|
||||
|
||||
svs = service_find_nick(parv[0]);
|
||||
if (svs == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, "No such service \2%s\2", parv[0]);
|
||||
return;
|
||||
}
|
||||
if (svs->commands == NULL)
|
||||
{
|
||||
command_fail(si, fault_noprivs, "Service \2%s\2 has no commands", svs->nick);
|
||||
return;
|
||||
}
|
||||
cmd = command_find(svs->commands, parv[1]);
|
||||
if (cmd == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_key, "No such command \2%s\2 in service \2%s\2", parv[1], svs->nick);
|
||||
return;
|
||||
}
|
||||
udata.prevsi = si;
|
||||
udata.got_result = false;
|
||||
memset(newparv, '\0', sizeof newparv);
|
||||
if (parc >= 3)
|
||||
newparc = sjtoken(parv[2], ';', newparv);
|
||||
else
|
||||
newparc = 0;
|
||||
memset(&newsi, '\0', sizeof newsi);
|
||||
newsi.smu = si->smu;
|
||||
if (si->su != NULL)
|
||||
newsi.sourcedesc = si->su->ip != NULL ? si->su->ip : si->su->host;
|
||||
else
|
||||
newsi.sourcedesc = si->sourcedesc;
|
||||
newsi.service = svs;
|
||||
newsi.v = &testcmd_vtable;
|
||||
newsi.callerdata = &udata;
|
||||
command_exec(svs, &newsi, cmd, newparc, newparv);
|
||||
if (!udata.got_result)
|
||||
command_success_nodata(si, "Command returned without giving a result");
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2009 Jilles Tjoelker, et al
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Reads data from a child process via a pipe.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include "datastream.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_testproc", false, _modinit, _moddeinit,
|
||||
PACKAGE_STRING,
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
struct testprocdata
|
||||
{
|
||||
char dest[NICKLEN];
|
||||
connection_t *pip;
|
||||
};
|
||||
|
||||
static struct testprocdata procdata;
|
||||
|
||||
static void os_cmd_testproc(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_testproc = { "TESTPROC", "Does something with child processes.",
|
||||
AC_NONE, 0, os_cmd_testproc, { .path = "contrib/testproc" } };
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_testproc);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
if (procdata.pip != NULL)
|
||||
connection_close_soon(procdata.pip);
|
||||
service_named_unbind_command("operserv", &os_testproc);
|
||||
}
|
||||
|
||||
static void testproc_recvqhandler(connection_t *cptr)
|
||||
{
|
||||
char buf[BUFSIZE];
|
||||
int count;
|
||||
user_t *u;
|
||||
|
||||
if (cptr != procdata.pip)
|
||||
{
|
||||
slog(LG_INFO, "testproc_recvqhandler(): called with unexpected fd %d", cptr->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
count = recvq_getline(cptr, buf, sizeof buf - 1);
|
||||
if (count <= 0)
|
||||
return;
|
||||
if (buf[count - 1] == '\n')
|
||||
count--;
|
||||
if (count > 0 && buf[count - 1] == '\r')
|
||||
count--;
|
||||
if (count == 0)
|
||||
buf[count++] = ' ';
|
||||
buf[count] = '\0';
|
||||
u = user_find(procdata.dest);
|
||||
if (u != NULL)
|
||||
notice(service_find("operserv")->me->nick, u->nick, "%s", buf);
|
||||
}
|
||||
|
||||
static void testproc_closehandler(connection_t *cptr)
|
||||
{
|
||||
if (cptr != procdata.pip)
|
||||
{
|
||||
slog(LG_INFO, "testproc_closehandler(): called with unexpected fd %d", cptr->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
slog(LG_DEBUG, "testproc_closehandler(): fd %d closed", cptr->fd);
|
||||
procdata.pip = NULL;
|
||||
}
|
||||
|
||||
static void os_cmd_testproc(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
int pipes[2];
|
||||
|
||||
if (si->su == NULL)
|
||||
{
|
||||
command_fail(si, fault_noprivs, _("\2%s\2 can only be executed via IRC."), "TESTPROC");
|
||||
return;
|
||||
}
|
||||
|
||||
if (procdata.pip != NULL)
|
||||
{
|
||||
command_fail(si, fault_toomany, "Another TESTPROC is still in progress");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pipe(pipes) == -1)
|
||||
{
|
||||
command_fail(si, fault_toomany, "Failed to create pipe");
|
||||
return;
|
||||
}
|
||||
switch (fork())
|
||||
{
|
||||
case -1:
|
||||
close(pipes[0]);
|
||||
close(pipes[1]);
|
||||
command_fail(si, fault_toomany, "Failed to fork");
|
||||
return;
|
||||
case 0:
|
||||
connection_close_all_fds();
|
||||
close(pipes[0]);
|
||||
dup2(pipes[1], 1);
|
||||
dup2(pipes[1], 2);
|
||||
close(pipes[1]);
|
||||
execl("/bin/sh", "sh", "-c", "echo hi; sleep 1; echo hi 2; sleep 0.5; echo hi 3; sleep 4; echo hi 4", (char *)NULL);
|
||||
(void)write(2, "Failed to exec /bin/sh\n", 23);
|
||||
_exit(255);
|
||||
break;
|
||||
default:
|
||||
close(pipes[1]);
|
||||
procdata.pip = connection_add("testproc pipe", pipes[0], 0, recvq_put, NULL);
|
||||
procdata.pip->recvq_handler = testproc_recvqhandler;
|
||||
procdata.pip->close_handler = testproc_closehandler;
|
||||
mowgli_strlcpy(procdata.dest, CLIENT_NAME(si->su), sizeof procdata.dest);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
|
@ -0,0 +1,928 @@
|
|||
/*
|
||||
* Copyright (c) 2010 William Pitcock <nenolod@atheme.org>
|
||||
* Rights to this code are as documented in doc/LICENSE.
|
||||
*
|
||||
* Looks for users and performs actions on them.
|
||||
*/
|
||||
|
||||
#include "atheme.h"
|
||||
#include <limits.h>
|
||||
|
||||
DECLARE_MODULE_V1
|
||||
(
|
||||
"contrib/os_trace", false, _modinit, _moddeinit,
|
||||
"Copyright (c) 2010 William Pitcock <nenolod@atheme.org>",
|
||||
"Atheme Development Group <http://www.atheme.org>"
|
||||
);
|
||||
|
||||
static char *reason_extract(char **args);
|
||||
static void os_cmd_trace(sourceinfo_t *si, int parc, char *parv[]);
|
||||
|
||||
command_t os_trace = { "TRACE", N_("Looks for users and performs actions on them."), PRIV_USER_AUSPEX, 2, os_cmd_trace, { .path = "contrib/trace" } };
|
||||
|
||||
typedef struct {
|
||||
void /* trace_query_domain_t */ *(*prepare)(char **args);
|
||||
bool (*exec)(user_t *u, void /* trace_query_domain_t */ *q);
|
||||
void (*cleanup)(void /* trace_query_domain_t */ *q);
|
||||
} trace_query_constructor_t;
|
||||
|
||||
typedef struct {
|
||||
trace_query_constructor_t *cons;
|
||||
mowgli_node_t node;
|
||||
} trace_query_domain_t;
|
||||
|
||||
static int read_comparison_operator(char** string, int default_comparison)
|
||||
{
|
||||
if (**string == '<')
|
||||
{
|
||||
if (*((*string)+1) == '=')
|
||||
{
|
||||
*string += 2;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*string += 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (**string == '>')
|
||||
{
|
||||
if (*((*string)+1) == '=')
|
||||
{
|
||||
*string += 2;
|
||||
return 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
*string += 1;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
else if (**string == '=')
|
||||
{
|
||||
*string += 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return default_comparison;
|
||||
}
|
||||
|
||||
char *reason_extract(char **args)
|
||||
{
|
||||
char *start = *args;
|
||||
bool quotes = false;
|
||||
|
||||
while (**args == ' ')
|
||||
{
|
||||
(*args)++;
|
||||
}
|
||||
if (**args == '"')
|
||||
{
|
||||
start = ++(*args);
|
||||
quotes = true;
|
||||
}
|
||||
else
|
||||
start = *args;
|
||||
|
||||
while (**args)
|
||||
{
|
||||
if (quotes && **args == '"')
|
||||
{
|
||||
quotes = false;
|
||||
**args = 0;
|
||||
(*args)++;
|
||||
break;
|
||||
}
|
||||
else if (!quotes && **args == ' ')
|
||||
{
|
||||
**args = 0;
|
||||
(*args)++;
|
||||
break;
|
||||
}
|
||||
|
||||
(*args)++;
|
||||
}
|
||||
|
||||
if (!(**args))
|
||||
*args = NULL;
|
||||
|
||||
if (start == *args)
|
||||
return NULL; /* No reason found. */
|
||||
if (quotes)
|
||||
return NULL; /* Unclosed quotes. */
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
atheme_regex_t *regex;
|
||||
char *pattern;
|
||||
int flags;
|
||||
} trace_query_regexp_domain_t;
|
||||
|
||||
static void *trace_regexp_prepare(char **args)
|
||||
{
|
||||
trace_query_regexp_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
domain = scalloc(sizeof(trace_query_regexp_domain_t), 1);
|
||||
domain->pattern = regex_extract(*args, &(*args), &domain->flags);
|
||||
domain->regex = regex_create(domain->pattern, domain->flags);
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_regexp_exec(user_t *u, void *q)
|
||||
{
|
||||
char usermask[512];
|
||||
trace_query_regexp_domain_t *domain = (trace_query_regexp_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
if (domain->regex == NULL)
|
||||
return false;
|
||||
|
||||
snprintf(usermask, 512, "%s!%s@%s %s", u->nick, u->user, u->host, u->gecos);
|
||||
|
||||
return regex_match(domain->regex, usermask);
|
||||
}
|
||||
|
||||
static void trace_regexp_cleanup(void *q)
|
||||
{
|
||||
trace_query_regexp_domain_t *domain = (trace_query_regexp_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
if (domain->regex != NULL)
|
||||
regex_destroy(domain->regex);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_regexp = { trace_regexp_prepare, trace_regexp_exec, trace_regexp_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
server_t *server;
|
||||
} trace_query_server_domain_t;
|
||||
|
||||
static void *trace_server_prepare(char **args)
|
||||
{
|
||||
char *server;
|
||||
trace_query_server_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
/* split out the next space */
|
||||
server = strtok(*args, " ");
|
||||
|
||||
domain = scalloc(sizeof(trace_query_server_domain_t), 1);
|
||||
domain->server = server_find(server);
|
||||
|
||||
/* advance *args to next token */
|
||||
*args = strtok(NULL, "");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_server_exec(user_t *u, void *q)
|
||||
{
|
||||
trace_query_server_domain_t *domain = (trace_query_server_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
return (domain->server == u->server);
|
||||
}
|
||||
|
||||
static void trace_server_cleanup(void *q)
|
||||
{
|
||||
trace_query_server_domain_t *domain = (trace_query_server_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_server = { trace_server_prepare, trace_server_exec, trace_server_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
char *pattern;
|
||||
} trace_query_glob_domain_t;
|
||||
|
||||
static void *trace_glob_prepare(char **args)
|
||||
{
|
||||
char *pattern;
|
||||
trace_query_glob_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
/* split out the next space */
|
||||
pattern = strtok(*args, " ");
|
||||
|
||||
domain = scalloc(sizeof(trace_query_glob_domain_t), 1);
|
||||
domain->pattern = sstrdup(pattern);
|
||||
|
||||
*args = strtok(NULL, "");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_glob_exec(user_t *u, void *q)
|
||||
{
|
||||
char usermask[512];
|
||||
trace_query_glob_domain_t *domain = (trace_query_glob_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
if (domain->pattern == NULL)
|
||||
return false;
|
||||
|
||||
snprintf(usermask, 512, "%s!%s@%s", u->nick, u->user, u->host);
|
||||
|
||||
return !match(domain->pattern, usermask);
|
||||
}
|
||||
|
||||
static void trace_glob_cleanup(void *q)
|
||||
{
|
||||
trace_query_glob_domain_t *domain = (trace_query_glob_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_glob = { trace_glob_prepare, trace_glob_exec, trace_glob_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
channel_t *channel;
|
||||
} trace_query_channel_domain_t;
|
||||
|
||||
static void *trace_channel_prepare(char **args)
|
||||
{
|
||||
char *channel;
|
||||
trace_query_channel_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
/* split out the next space */
|
||||
channel = strtok(*args, " ");
|
||||
|
||||
domain = scalloc(sizeof(trace_query_channel_domain_t), 1);
|
||||
domain->channel = channel_find(channel);
|
||||
|
||||
/* advance *args to next token */
|
||||
*args = strtok(NULL, "");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_channel_exec(user_t *u, void *q)
|
||||
{
|
||||
trace_query_channel_domain_t *domain = (trace_query_channel_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
return (chanuser_find(domain->channel, u) != NULL);
|
||||
}
|
||||
|
||||
static void trace_channel_cleanup(void *q)
|
||||
{
|
||||
trace_query_channel_domain_t *domain = (trace_query_channel_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_channel = { trace_channel_prepare, trace_channel_exec, trace_channel_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
int nickage;
|
||||
int comparison;
|
||||
} trace_query_nickage_domain_t;
|
||||
|
||||
static void *trace_nickage_prepare(char **args)
|
||||
{
|
||||
char *nickage_string;
|
||||
trace_query_nickage_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
/* split out the next space */
|
||||
nickage_string = strtok(*args, " ");
|
||||
|
||||
domain = scalloc(sizeof(trace_query_nickage_domain_t), 1);
|
||||
domain->comparison = read_comparison_operator(&nickage_string, 2);
|
||||
domain->nickage = atoi(nickage_string);
|
||||
|
||||
/* advance *args to next token */
|
||||
*args = strtok(NULL, "");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_nickage_exec(user_t *u, void *q)
|
||||
{
|
||||
trace_query_nickage_domain_t *domain = (trace_query_nickage_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
int nickage = CURRTIME - u->ts;
|
||||
if (domain->comparison == 1)
|
||||
return (nickage < domain->nickage);
|
||||
else if (domain->comparison == 2)
|
||||
return (nickage <= domain->nickage);
|
||||
else if (domain->comparison == 3)
|
||||
return (nickage > domain->nickage);
|
||||
else if (domain->comparison == 4)
|
||||
return (nickage >= domain->nickage);
|
||||
else
|
||||
return (nickage == domain->nickage);
|
||||
}
|
||||
|
||||
static void trace_nickage_cleanup(void *q)
|
||||
{
|
||||
trace_query_nickage_domain_t *domain = (trace_query_nickage_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_nickage = { trace_nickage_prepare, trace_nickage_exec, trace_nickage_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
int numchan;
|
||||
int comparison;
|
||||
} trace_query_numchan_domain_t;
|
||||
|
||||
static void *trace_numchan_prepare(char **args)
|
||||
{
|
||||
char *numchan_string;
|
||||
trace_query_numchan_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
/* split out the next space */
|
||||
numchan_string = strtok(*args, " ");
|
||||
|
||||
domain = scalloc(sizeof(trace_query_numchan_domain_t), 1);
|
||||
domain->comparison = read_comparison_operator(&numchan_string, 0);
|
||||
domain->numchan = atoi(numchan_string);
|
||||
|
||||
/* advance *args to next token */
|
||||
*args = strtok(NULL, "");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_numchan_exec(user_t *u, void *q)
|
||||
{
|
||||
trace_query_numchan_domain_t *domain = (trace_query_numchan_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
int numchan = u->channels.count;
|
||||
if (domain->comparison == 1)
|
||||
return (numchan < domain->numchan);
|
||||
else if (domain->comparison == 2)
|
||||
return (numchan <= domain->numchan);
|
||||
else if (domain->comparison == 3)
|
||||
return (numchan > domain->numchan);
|
||||
else if (domain->comparison == 4)
|
||||
return (numchan >= domain->numchan);
|
||||
else
|
||||
return (numchan == domain->numchan);
|
||||
}
|
||||
|
||||
static void trace_numchan_cleanup(void *q)
|
||||
{
|
||||
trace_query_numchan_domain_t *domain = (trace_query_numchan_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_numchan = { trace_numchan_prepare, trace_numchan_exec, trace_numchan_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_query_domain_t domain;
|
||||
bool identified;
|
||||
} trace_query_identified_domain_t;
|
||||
|
||||
static void *trace_identified_prepare(char **args)
|
||||
{
|
||||
char *yesno;
|
||||
bool identified;
|
||||
trace_query_identified_domain_t *domain;
|
||||
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
return_val_if_fail(*args != NULL, NULL);
|
||||
|
||||
yesno = strtok(*args, " ");
|
||||
|
||||
if (!strcasecmp(yesno, "yes"))
|
||||
identified = true;
|
||||
else if (!strcasecmp(yesno, "no"))
|
||||
identified = false;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
domain = scalloc(sizeof(trace_query_identified_domain_t), 1);
|
||||
domain->identified = identified;
|
||||
|
||||
/* advance *args to next token */
|
||||
*args = strtok(NULL, "");
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
static bool trace_identified_exec(user_t *u, void *q)
|
||||
{
|
||||
trace_query_identified_domain_t *domain = (trace_query_identified_domain_t *) q;
|
||||
|
||||
return_val_if_fail(domain != NULL, false);
|
||||
return_val_if_fail(u != NULL, false);
|
||||
|
||||
return (domain->identified == (u->myuser != NULL));
|
||||
}
|
||||
|
||||
static void trace_identified_cleanup(void *q)
|
||||
{
|
||||
trace_query_identified_domain_t *domain = (trace_query_identified_domain_t *) q;
|
||||
|
||||
return_if_fail(domain != NULL);
|
||||
|
||||
free(domain);
|
||||
}
|
||||
|
||||
trace_query_constructor_t trace_identified = { trace_identified_prepare, trace_identified_exec, trace_identified_cleanup };
|
||||
|
||||
/****************************************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
sourceinfo_t *si;
|
||||
bool matched;
|
||||
} trace_action_t;
|
||||
|
||||
typedef struct {
|
||||
trace_action_t *(*prepare)(sourceinfo_t *si, char **args);
|
||||
void (*exec)(user_t *u, trace_action_t *a);
|
||||
void (*cleanup)(trace_action_t *a, bool succeeded);
|
||||
} trace_action_constructor_t;
|
||||
|
||||
static void trace_action_init(trace_action_t *a, sourceinfo_t *si);
|
||||
|
||||
/* initializes common fields for trace action object. */
|
||||
void trace_action_init(trace_action_t *a, sourceinfo_t *si)
|
||||
{
|
||||
return_if_fail(a != NULL);
|
||||
return_if_fail(si != NULL);
|
||||
|
||||
a->si = si;
|
||||
a->matched = false;
|
||||
}
|
||||
|
||||
static trace_action_t *trace_print_prepare(sourceinfo_t *si, char **args)
|
||||
{
|
||||
trace_action_t *a;
|
||||
|
||||
return_val_if_fail(si != NULL, NULL);
|
||||
|
||||
a = scalloc(sizeof(trace_action_t), 1);
|
||||
trace_action_init(a, si);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
static void trace_print_exec(user_t *u, trace_action_t *a)
|
||||
{
|
||||
return_if_fail(u != NULL);
|
||||
return_if_fail(a != NULL);
|
||||
if(is_internal_client(u))
|
||||
return;
|
||||
|
||||
a->matched = true;
|
||||
command_success_nodata(a->si, _("\2Match:\2 %s!%s@%s %s {%s}"), u->nick, u->user, u->host, u->gecos, u->server->name);
|
||||
}
|
||||
|
||||
static void trace_print_cleanup(trace_action_t *a, bool succeeded)
|
||||
{
|
||||
return_if_fail(a != NULL);
|
||||
|
||||
if (!a->matched && succeeded)
|
||||
command_success_nodata(a->si, _("No matches."));
|
||||
free(a);
|
||||
}
|
||||
|
||||
trace_action_constructor_t trace_print = { trace_print_prepare, trace_print_exec, trace_print_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_action_t base;
|
||||
char *reason;
|
||||
} trace_action_kill_t;
|
||||
|
||||
static trace_action_t *trace_kill_prepare(sourceinfo_t *si, char **args)
|
||||
{
|
||||
trace_action_kill_t *a;
|
||||
char *reason;
|
||||
|
||||
return_val_if_fail(si != NULL, NULL);
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
if (*args == NULL)
|
||||
return NULL;
|
||||
|
||||
reason = reason_extract(args);
|
||||
if (reason == NULL)
|
||||
return NULL;
|
||||
|
||||
a = scalloc(sizeof(trace_action_kill_t), 1);
|
||||
trace_action_init(&a->base, si);
|
||||
a->reason = reason;
|
||||
|
||||
return (trace_action_t*) a;
|
||||
}
|
||||
|
||||
static void trace_kill_exec(user_t *u, trace_action_t *act)
|
||||
{
|
||||
service_t *svs;
|
||||
trace_action_kill_t *a = (trace_action_kill_t *) act;
|
||||
|
||||
return_if_fail(u != NULL);
|
||||
return_if_fail(a != NULL);
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
if (is_ircop(u))
|
||||
return;
|
||||
if (u->myuser && is_soper(u->myuser))
|
||||
return;
|
||||
if ((svs = service_find("operserv")) != NULL)
|
||||
return;
|
||||
|
||||
act->matched = true;
|
||||
kill_user(svs->me, u, "%s", a->reason);
|
||||
command_success_nodata(act->si, _("\2%s\2 has been killed."), u->nick);
|
||||
}
|
||||
|
||||
static void trace_kill_cleanup(trace_action_t *a, bool succeeded)
|
||||
{
|
||||
return_if_fail(a != NULL);
|
||||
|
||||
if (!a->matched && succeeded)
|
||||
command_success_nodata(a->si, _("No matches."));
|
||||
free(a);
|
||||
}
|
||||
|
||||
trace_action_constructor_t trace_kill = { trace_kill_prepare, trace_kill_exec, trace_kill_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_action_t base;
|
||||
long duration;
|
||||
char *reason;
|
||||
} trace_action_akill_t;
|
||||
|
||||
static trace_action_t *trace_akill_prepare(sourceinfo_t *si, char **args)
|
||||
{
|
||||
trace_action_akill_t *a;
|
||||
char *s, *reason;
|
||||
long duration = config_options.kline_time;
|
||||
char token;
|
||||
|
||||
return_val_if_fail(si != NULL, NULL);
|
||||
return_val_if_fail(args != NULL, NULL);
|
||||
if (*args == NULL)
|
||||
return NULL;
|
||||
|
||||
while (**args == ' ')
|
||||
(*args)++;
|
||||
|
||||
/* Extract a token, but only if there's one to remove.
|
||||
* Otherwise, this would clip a word off the reason. */
|
||||
token = 0;
|
||||
s = *args;
|
||||
if (!strncasecmp(s, "!T", 2) || !strncasecmp(s, "!P", 2))
|
||||
{
|
||||
if (s[2] == ' ')
|
||||
{
|
||||
token = tolower(s[1]);
|
||||
s[2] = '\0';
|
||||
*args += 3;
|
||||
}
|
||||
else if (s[2] == '\0')
|
||||
{
|
||||
token = tolower(s[1]);
|
||||
*args += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (token == 't')
|
||||
{
|
||||
s = strtok(*args, " ");
|
||||
*args = strtok(NULL, "");
|
||||
if (*args == NULL)
|
||||
return NULL;
|
||||
|
||||
duration = (atol(s) * 60);
|
||||
while (isdigit(*s))
|
||||
s++;
|
||||
if (*s == 'h' || *s == 'H')
|
||||
duration *= 60;
|
||||
else if (*s == 'd' || *s == 'D')
|
||||
duration *= 1440;
|
||||
else if (*s == 'w' || *s == 'W')
|
||||
duration *= 10080;
|
||||
else if (*s == '\0')
|
||||
;
|
||||
else
|
||||
duration = 0;
|
||||
|
||||
if (duration == 0)
|
||||
return NULL;
|
||||
}
|
||||
else if (token == 'p')
|
||||
duration = 0;
|
||||
|
||||
reason = reason_extract(args);
|
||||
if (reason == NULL)
|
||||
return NULL;
|
||||
|
||||
a = scalloc(sizeof(trace_action_akill_t), 1);
|
||||
trace_action_init(&a->base, si);
|
||||
a->duration = duration;
|
||||
a->reason = reason;
|
||||
|
||||
|
||||
return (trace_action_t*) a;
|
||||
}
|
||||
|
||||
static void trace_akill_exec(user_t *u, trace_action_t *act)
|
||||
{
|
||||
char *kuser, *khost;
|
||||
trace_action_akill_t *a = (trace_action_akill_t *) act;
|
||||
|
||||
return_if_fail(u != NULL);
|
||||
return_if_fail(a != NULL);
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
if (is_ircop(u))
|
||||
return;
|
||||
if (u->myuser && is_soper(u->myuser))
|
||||
return;
|
||||
|
||||
kuser = "*";
|
||||
khost = u->host;
|
||||
|
||||
if (!match(khost, "127.0.0.1") || !match_ips(khost, "127.0.0.1"))
|
||||
return;
|
||||
if (me.vhost != NULL && (!match(khost, me.vhost) || !match_ips(khost, me.vhost)))
|
||||
return;
|
||||
if (kline_find(kuser, khost))
|
||||
return;
|
||||
|
||||
act->matched = true;
|
||||
kline_add(kuser, khost, a->reason, a->duration, get_storage_oper_name(act->si));
|
||||
command_success_nodata(act->si, _("\2%s\2 has been akilled."), u->nick);
|
||||
}
|
||||
|
||||
static void trace_akill_cleanup(trace_action_t *a, bool succeeded)
|
||||
{
|
||||
return_if_fail(a != NULL);
|
||||
|
||||
if (!a->matched && succeeded)
|
||||
command_success_nodata(a->si, _("No matches."));
|
||||
free(a);
|
||||
}
|
||||
|
||||
trace_action_constructor_t trace_akill = { trace_akill_prepare, trace_akill_exec, trace_akill_cleanup };
|
||||
|
||||
typedef struct {
|
||||
trace_action_t base;
|
||||
int matches;
|
||||
} trace_action_count_t;
|
||||
|
||||
static trace_action_t *trace_count_prepare(sourceinfo_t *si, char **args)
|
||||
{
|
||||
trace_action_count_t *a;
|
||||
|
||||
return_val_if_fail(si != NULL, NULL);
|
||||
|
||||
a = scalloc(sizeof(trace_action_count_t), 1);
|
||||
trace_action_init(&a->base, si);
|
||||
|
||||
return (trace_action_t *) a;
|
||||
}
|
||||
|
||||
static void trace_count_exec(user_t *u, trace_action_t *act)
|
||||
{
|
||||
trace_action_count_t *a = (trace_action_count_t *) act;
|
||||
|
||||
return_if_fail(u != NULL);
|
||||
return_if_fail(a != NULL);
|
||||
if (is_internal_client(u))
|
||||
return;
|
||||
|
||||
act->matched = true;
|
||||
a->matches++;
|
||||
}
|
||||
|
||||
static void trace_count_cleanup(trace_action_t *act, bool succeeded)
|
||||
{
|
||||
trace_action_count_t *a = (trace_action_count_t *) act;
|
||||
|
||||
return_if_fail(a != NULL);
|
||||
|
||||
if (succeeded)
|
||||
command_success_nodata(act->si, _("\2%d\2 matches"), a->matches);
|
||||
|
||||
free(a);
|
||||
}
|
||||
|
||||
trace_action_constructor_t trace_count = { trace_count_prepare, trace_count_exec, trace_count_cleanup };
|
||||
|
||||
/*
|
||||
* Add-on interface.
|
||||
*
|
||||
* This allows third-party module writers to extend the trace API.
|
||||
* Just copy the prototypes out of trace.c, and add the trace_cmdtree
|
||||
* symbol to your module with MODULE_USE_SYMBOL().
|
||||
*
|
||||
* Then add your criteria to the tree with mowgli_patricia_add().
|
||||
*/
|
||||
mowgli_patricia_t *trace_cmdtree = NULL;
|
||||
mowgli_patricia_t *trace_acttree = NULL;
|
||||
|
||||
void _modinit(module_t *m)
|
||||
{
|
||||
service_named_bind_command("operserv", &os_trace);
|
||||
|
||||
trace_cmdtree = mowgli_patricia_create(strcasecanon);
|
||||
mowgli_patricia_add(trace_cmdtree, "REGEXP", &trace_regexp);
|
||||
mowgli_patricia_add(trace_cmdtree, "SERVER", &trace_server);
|
||||
mowgli_patricia_add(trace_cmdtree, "GLOB", &trace_glob);
|
||||
mowgli_patricia_add(trace_cmdtree, "CHANNEL", &trace_channel);
|
||||
mowgli_patricia_add(trace_cmdtree, "NICKAGE", &trace_nickage);
|
||||
mowgli_patricia_add(trace_cmdtree, "NUMCHAN", &trace_numchan);
|
||||
mowgli_patricia_add(trace_cmdtree, "IDENTIFIED", &trace_identified);
|
||||
|
||||
trace_acttree = mowgli_patricia_create(strcasecanon);
|
||||
mowgli_patricia_add(trace_acttree, "PRINT", &trace_print);
|
||||
mowgli_patricia_add(trace_acttree, "KILL", &trace_kill);
|
||||
mowgli_patricia_add(trace_acttree, "AKILL", &trace_akill);
|
||||
mowgli_patricia_add(trace_acttree, "COUNT", &trace_count);
|
||||
}
|
||||
|
||||
void _moddeinit(module_unload_intent_t intent)
|
||||
{
|
||||
mowgli_patricia_destroy(trace_cmdtree, NULL, NULL);
|
||||
|
||||
service_named_unbind_command("operserv", &os_trace);
|
||||
}
|
||||
|
||||
#define MAXMATCHES_DEF 1000
|
||||
|
||||
static bool os_cmd_trace_run(sourceinfo_t *si, trace_action_constructor_t *actcons, trace_action_t* act, mowgli_list_t *crit, char *args);
|
||||
|
||||
static void os_cmd_trace(sourceinfo_t *si, int parc, char *parv[])
|
||||
{
|
||||
mowgli_list_t crit = { NULL, NULL, 0 };
|
||||
trace_action_constructor_t *actcons;
|
||||
trace_action_t* act;
|
||||
char *args = parv[1];
|
||||
mowgli_node_t *n, *tn;
|
||||
char *params;
|
||||
bool succeeded;
|
||||
|
||||
if (!parv[0])
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "TRACE");
|
||||
command_fail(si, fault_badparams, _("Syntax: TRACE <action> <params>"));
|
||||
return;
|
||||
}
|
||||
|
||||
actcons = mowgli_patricia_retrieve(trace_acttree, parv[0]);
|
||||
if (actcons == NULL)
|
||||
{
|
||||
command_fail(si, fault_badparams, STR_INVALID_PARAMS, "TRACE");
|
||||
command_fail(si, fault_badparams, _("Syntax: TRACE <action> <params>"));
|
||||
return;
|
||||
}
|
||||
|
||||
act = actcons->prepare(si, &args);
|
||||
if (act == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Action compilation failed."));
|
||||
return;
|
||||
}
|
||||
|
||||
params = sstrdup(args);
|
||||
succeeded = os_cmd_trace_run(si, actcons, act, &crit, args);
|
||||
|
||||
MOWGLI_ITER_FOREACH_SAFE(n, tn, crit.head)
|
||||
{
|
||||
trace_query_domain_t *q = (trace_query_domain_t *) n->data;
|
||||
q->cons->cleanup(q);
|
||||
}
|
||||
actcons->cleanup(act, succeeded);
|
||||
|
||||
if (succeeded)
|
||||
logcommand(si, CMDLOG_ADMIN, "TRACE: \2%s\2 \2%s\2", parv[0], params);
|
||||
|
||||
free(params);
|
||||
}
|
||||
|
||||
static bool os_cmd_trace_run(sourceinfo_t *si, trace_action_constructor_t *actcons, trace_action_t* act, mowgli_list_t *crit, char *args)
|
||||
{
|
||||
user_t *u;
|
||||
mowgli_patricia_iteration_state_t state;
|
||||
mowgli_node_t *n;
|
||||
|
||||
if (args == NULL)
|
||||
{
|
||||
command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "TRACE");
|
||||
command_fail(si, fault_needmoreparams, _("Syntax: TRACE <action> <params>"));
|
||||
return false;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
trace_query_constructor_t *cons;
|
||||
trace_query_domain_t *q;
|
||||
char *cmd = strtok(args, " ");
|
||||
|
||||
if (cmd == NULL)
|
||||
break;
|
||||
|
||||
cons = mowgli_patricia_retrieve(trace_cmdtree, cmd);
|
||||
if (cons == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Invalid criteria specified."));
|
||||
return false;
|
||||
}
|
||||
|
||||
args = strtok(NULL, "");
|
||||
if (args == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Invalid criteria specified."));
|
||||
return false;
|
||||
}
|
||||
|
||||
q = cons->prepare(&args);
|
||||
slog(LG_DEBUG, "operserv/trace: adding criteria %p(%s) to list [remain: %s]", q, cmd, args);
|
||||
if (q == NULL)
|
||||
{
|
||||
command_fail(si, fault_nosuch_target, _("Invalid criteria specified."));
|
||||
return false;
|
||||
}
|
||||
slog(LG_DEBUG, "operserv/trace: new args position [%s]", args);
|
||||
|
||||
q->cons = cons;
|
||||
mowgli_node_add(q, &q->node, crit);
|
||||
}
|
||||
|
||||
MOWGLI_PATRICIA_FOREACH(u, &state, userlist)
|
||||
{
|
||||
bool doit = true;
|
||||
|
||||
MOWGLI_ITER_FOREACH(n, crit->head)
|
||||
{
|
||||
trace_query_domain_t *q = (trace_query_domain_t *) n->data;
|
||||
|
||||
if (!q->cons->exec(u, q))
|
||||
{
|
||||
doit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (doit)
|
||||
actcons->exec(u, act);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
|
||||
* vim:ts=8
|
||||
* vim:sw=8
|
||||
* vim:noexpandtab
|
||||
*/
|
Loading…
Reference in New Issue