diff --git a/extensions/Makefile.am b/extensions/Makefile.am index e4460d1cd..76be3ccb9 100644 --- a/extensions/Makefile.am +++ b/extensions/Makefile.am @@ -35,6 +35,7 @@ extension_LTLIBRARIES = \ force_user_invis.la \ helpops.la \ hurt.la \ + identify_msg.la \ invite_notify.la \ ip_cloaking.la \ ip_cloaking_old.la \ @@ -50,6 +51,7 @@ extension_LTLIBRARIES = \ sno_globaloper.la \ sno_whois.la \ umode_noctcp.la \ + umode_regnick.la \ m_adminwall.la \ m_echotags.la \ m_extendchans.la \ diff --git a/extensions/identify_msg.c b/extensions/identify_msg.c new file mode 100644 index 000000000..999564e8b --- /dev/null +++ b/extensions/identify_msg.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +static const char identify_msg_desc[] = "Provides the freenode.net/identify-msg client capability"; + +static void identmsg_outbound(void *); +unsigned int CLICAP_IDENTIFY_MSG = 0; + +mapi_cap_list_av2 identmsg_cap_list[] = { + { MAPI_CAP_CLIENT, "freenode.net/identify-msg", NULL, &CLICAP_IDENTIFY_MSG }, + { 0, NULL, NULL, NULL } +}; + +static mapi_hfn_list_av1 identmsg_hfnlist[] = { + { "outbound_msgbuf", identmsg_outbound }, + { NULL, NULL } +}; + +static void identmsg_outbound(void *data_) +{ + hook_data *data = data_; + struct MsgBuf *msgbuf = data->arg1; + + if (data->client->umodes & user_modes['r']) + msgbuf_append_tag(msgbuf, "freenode.net/identified", NULL, CLICAP_IDENTIFY_MSG); +} + +DECLARE_MODULE_AV2(identify_msg, NULL, NULL, NULL, NULL, identmsg_hfnlist, identmsg_cap_list, NULL, identify_msg_desc); diff --git a/extensions/umode_regnick.c b/extensions/umode_regnick.c new file mode 100644 index 000000000..aa84429a9 --- /dev/null +++ b/extensions/umode_regnick.c @@ -0,0 +1,112 @@ +/* + * modules/umode_regnick.c + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +#include "stdinc.h" +#include "modules.h" +#include "hook.h" +#include "client.h" +#include "ircd.h" +#include "send.h" +#include "s_user.h" +#include "numeric.h" +#include "inline/stringops.h" +#include "logger.h" + +static const char umode_regnick_desc[] = + "Adds user mode +r which indicates a user is identified to a registered nickname."; + +static void umode_regnick_validate_umode_change(hook_data_umode_changed *data); +static void umode_regnick_nick_change(hook_cdata *data); + +mapi_hfn_list_av1 umode_regnick_hfnlist[] = { + { "umode_changed", (hookfn) umode_regnick_validate_umode_change }, + { "local_nick_change", (hookfn) umode_regnick_nick_change }, + { "remote_nick_change", (hookfn) umode_regnick_nick_change }, + { NULL, NULL } +}; + +static int +umode_regnick_modinit(void) +{ + user_modes['r'] = find_umode_slot(); + + if (!user_modes['r']) + { + ierror("umode_regnick: could not find a usermode slot for +r"); + return -1; + } + + construct_umodebuf(); + return 0; +} + +static void +umode_regnick_moddeinit(void) +{ + user_modes['r'] = 0; + construct_umodebuf(); +} + +static void +umode_regnick_validate_umode_change(hook_data_umode_changed *data) +{ + bool changed = ((data->oldumodes ^ data->client->umodes) & user_modes['r']); + + if (!MyClient(data->client)) + return; + + /* users cannot change usermode +r themselves, so undo whatever they did */ + if (!changed) + return; + else + { + if (data->oldumodes & user_modes['r']) + data->client->umodes |= user_modes['r']; + else + data->client->umodes &= ~user_modes['r']; + } +} + +static void +umode_regnick_nick_change(hook_cdata *data) +{ + char buf[BUFSIZE]; + int old = data->client->umodes; + const char *oldnick = data->arg1, *newnick = data->arg2; + + if (!irccmp(oldnick, newnick)) + return; + + data->client->umodes &= ~user_modes['r']; + + if (MyClient(data->client)) + send_umode(data->client, data->client, old, buf); +} + +DECLARE_MODULE_AV2(umode_regnick, umode_regnick_modinit, umode_regnick_moddeinit, NULL, NULL, umode_regnick_hfnlist, NULL, NULL, umode_regnick_desc); diff --git a/modules/Makefile.am b/modules/Makefile.am index d70055775..602881631 100644 --- a/modules/Makefile.am +++ b/modules/Makefile.am @@ -64,6 +64,7 @@ auto_load_mod_LTLIBRARIES = \ m_starttls.la \ m_stats.la \ m_svinfo.la \ + m_svsumode.la \ m_tb.la \ m_testline.la \ m_testmask.la \ diff --git a/modules/m_svsumode.c b/modules/m_svsumode.c new file mode 100644 index 000000000..29a44df42 --- /dev/null +++ b/modules/m_svsumode.c @@ -0,0 +1,116 @@ +/* + * modules/m_svsumode.c + * Copyright (c) 2020 Ariadne Conill + * + * 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. + */ + +#include "stdinc.h" +#include "modules.h" +#include "hook.h" +#include "client.h" +#include "ircd.h" +#include "send.h" +#include "s_user.h" +#include "numeric.h" +#include "inline/stringops.h" +#include "logger.h" +#include "hash.h" + +static const char svsumode_desc[] = "Provides SVSUMODE command."; + +/* :NickServ ENCAP * SVSUMODE uid umode_changes */ +static void me_svsumode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]); + +struct Message svsumode_msgtab = { + "SVSUMODE", 0, 0, 0, 0, + {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_svsumode, 2}, mg_ignore} +}; + +mapi_clist_av1 svsumode_clist[] = { &svsumode_msgtab, NULL }; + +DECLARE_MODULE_AV2(svsumode, NULL, NULL, svsumode_clist, NULL, NULL, NULL, NULL, svsumode_desc); + +/* + * SVSUMODE + * + * parv[0] = service + * parv[1] = target + * parv[2] = umode changes + */ +static void +me_svsumode(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[]) +{ + bool add = true; + const char *p = parv[2]; + struct Client *target_p = find_client(parv[1]); + int oldumodes; + + if (target_p == NULL) + return; + + if (!IsService(source_p)) + return; + + oldumodes = target_p->umodes; + + while (*p) + { + const char mode = *p; + + switch (mode) + { + case '+': + add = true; + break; + + case '-': + add = false; + break; + + /* don't allow usermode +p to be set via SVSUMODE */ + case 'p': + break; + + default: + if (add) + target_p->umodes |= user_modes[(unsigned int) *p]; + else + target_p->umodes &= ~user_modes[(unsigned int) *p]; + + break; + } + + p++; + } + + /* inform the local client of their usermode change */ + if (MyClient(target_p)) + { + char chgbuf[BUFSIZE]; + + send_umode(target_p, target_p, oldumodes, chgbuf); + } +}