emehta-contrib/ns_ajoin.c

216 lines
5.1 KiB
C

/*
* 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-compat.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_syntaxerr(sourceinfo_t *si)
{
command_fail(si, fault_badparams, STR_INSUFFICIENT_PARAMS, "AJOIN");
command_fail(si, fault_badparams, "Syntax: AJOIN <list|add|del|clear> [#channel]");
}
static void ns_cmd_ajoin(sourceinfo_t *si, int parc, char *parv[])
{
char buf[512];
char *chan;
metadata_t *md;
if (!parv[0])
return ns_cmd_ajoin_syntaxerr(si);
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])
return ns_cmd_ajoin_syntaxerr(si);
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])
return ns_cmd_ajoin_syntaxerr(si);
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, ",");
}
}