222 lines
5.3 KiB
C
222 lines
5.3 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(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, ",");
|
|
}
|
|
}
|