1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-30 00:16:38 +02:00
Files
unrealircd/src/modules/chanmodes/delayjoin.c
T

347 lines
9.0 KiB
C

/*
* Channel mode +D/+d: delayed join
* except from opers, U-lines and servers.
* Copyright 2014 Travis Mcarthur <Heero> and UnrealIRCd Team
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER(delayjoin)
= {
"delayjoin", /* Name of module */
"v0.0.1", /* Version */
"delayed join (+D,+d)", /* Short description of module */
"3.2-b8-1",
NULL
};
#define MOD_DATA_STR "delayjoin"
#define MOD_DATA_INVISIBLE "1"
static long UMODE_PRIVDEAF = 0;
static Cmode *CmodeDelayed = NULL;
static Cmode *CmodePostDelayed = NULL;
static Cmode_t EXTMODE_DELAYED;
static Cmode_t EXTMODE_POST_DELAYED;
DLLFUNC int moded_check_join( aClient *cptr, aChannel *chptr);
DLLFUNC int moded_check_part( aClient *cptr, aChannel *chptr);
DLLFUNC int moded_join(aClient *cptr, aChannel *chptr);
DLLFUNC int moded_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[]);
DLLFUNC int deny_all(aClient *cptr, aChannel *chptr, char mode, char *para, int checkt, int what);
DLLFUNC int moded_quit(aClient *acptr, char *comment);
DLLFUNC int moded_kick(aClient *cptr, aClient *sptr, aClient *acptr, aChannel *chptr, char *comment);
DLLFUNC int moded_chanmode(aClient *cptr, aClient *sptr, aChannel *chptr,
char *modebuf, char *parabuf, int sendts, int samode);
DLLFUNC int moded_chanmsg(aClient *sptr, aChannel *chptr, char *text, int notice);
char *moded_serialize(ModData *m);
void moded_unserialize(char *str, ModData *m);
DLLFUNC int MOD_INIT(delayjoin)(ModuleInfo *modinfo)
{
CmodeInfo req;
ModDataInfo mreq;
memset(&req, 0, sizeof(req));
req.paracount = 0;
req.is_ok = extcmode_default_requirechop;
req.flag = 'D';
CmodeDelayed = CmodeAdd(modinfo->handle, req, &EXTMODE_DELAYED);
req.flag = 'd';
req.is_ok = deny_all;
CmodePostDelayed = CmodeAdd(modinfo->handle, req, &EXTMODE_POST_DELAYED);
memset(&mreq, 0, sizeof(mreq));
mreq.name = MOD_DATA_STR;
mreq.serialize = moded_serialize;
mreq.unserialize = moded_unserialize;
mreq.sync = 0;
mreq.type = MODDATATYPE_MEMBER;
if (!ModDataAdd(modinfo->handle, mreq))
abort();
if (!CmodeDelayed || !CmodePostDelayed)
{
/* I use config_error() here because it's printed to stderr in case of a load
* on cmd line, and to all opers in case of a /rehash.
*/
config_error("delayjoin: Could not add usermode '+D' or '+d': %s", ModuleGetErrorStr(modinfo->handle));
return MOD_FAILED;
}
HookAddEx(modinfo->handle, HOOKTYPE_VISIBLE_IN_CHANNEL, moded_check_join);
HookAddEx(modinfo->handle, HOOKTYPE_JOIN_DATA, moded_join);
HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_PART, moded_part);
HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_PART, moded_part);
HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_QUIT, moded_quit);
HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_QUIT, moded_quit);
HookAddEx(modinfo->handle, HOOKTYPE_LOCAL_KICK, moded_kick);
HookAddEx(modinfo->handle, HOOKTYPE_REMOTE_KICK, moded_kick);
HookAddEx(modinfo->handle, HOOKTYPE_PRE_LOCAL_CHANMODE, moded_chanmode);
HookAddEx(modinfo->handle, HOOKTYPE_PRE_REMOTE_CHANMODE, moded_chanmode);
HookAddEx(modinfo->handle, HOOKTYPE_CHANMSG, moded_chanmsg);
MARK_AS_OFFICIAL_MODULE(modinfo);
return MOD_SUCCESS;
}
DLLFUNC int MOD_LOAD(delayjoin)(int module_load)
{
return MOD_SUCCESS;
}
DLLFUNC int MOD_UNLOAD(delayjoin)(int module_unload)
{
return MOD_SUCCESS;
}
DLLFUNC void set_post_delayed(aChannel *chptr)
{
chptr->mode.extmode |= EXTMODE_POST_DELAYED;
sendto_channel_butserv(chptr, &me, ":%s MODE %s +d", me.name, chptr->chname);
}
DLLFUNC void clear_post_delayed(aChannel *chptr)
{
chptr->mode.extmode &= ~EXTMODE_POST_DELAYED;
sendto_channel_butserv(chptr, &me, ":%s MODE %s -d", me.name, chptr->chname);
}
bool moded_member_invisible(Member* m, aChannel *chptr)
{
ModDataInfo *md;
if (!m)
return false;
md = findmoddata_byname(MOD_DATA_STR, MODDATATYPE_MEMBER);
if (!md)
return false;
if (!moddata_member(m,md).str)
return false;
return true;
}
bool moded_user_invisible(aClient *cptr, aChannel *chptr)
{
return moded_member_invisible(find_member_link(chptr->members, cptr),chptr);
}
DLLFUNC bool channel_has_invisible_users(aChannel *chptr)
{
Member* i;
for (i = chptr->members; i; i = i->next)
{
if (moded_member_invisible(i,chptr))
{
return true;
}
}
return false;
}
DLLFUNC bool channel_is_post_delayed(aChannel *chptr)
{
if (chptr->mode.extmode & EXTMODE_POST_DELAYED)
return true;
return false;
}
DLLFUNC bool channel_is_delayed(aChannel *chptr)
{
if (chptr->mode.extmode & EXTMODE_DELAYED)
return true;
return false;
}
DLLFUNC void clear_user_invisible(aChannel *chptr, aClient *sptr)
{
Member *i;
ModDataInfo *md;
bool should_clear = true, found_member = false;
md = findmoddata_byname(MOD_DATA_STR, MODDATATYPE_MEMBER);
if (!md)
return;
for (i = chptr->members; i; i = i->next)
{
if (i->cptr == sptr)
{
if (md)
memset(&moddata_member(i, md), 0, sizeof(ModData));
found_member = true;
if (!should_clear)
break;
}
else if (moddata_member(i,md).str)
{
should_clear = false;
if (found_member)
break;
}
}
if (should_clear && (chptr->mode.extmode & EXTMODE_POST_DELAYED))
{
clear_post_delayed(chptr);
}
}
DLLFUNC void clear_user_invisible_announce(aChannel *chptr, aClient *sptr)
{
Member *i;
clear_user_invisible(chptr,sptr);
for (i = chptr->members; i; i = i->next)
{
if (!is_skochanop(i->cptr,chptr) && i->cptr != sptr)
sendto_one(i->cptr,
":%s!%s@%s JOIN :%s", sptr->name, sptr->user->username, GetHost(sptr), chptr->chname);
}
}
DLLFUNC void set_user_invisible(aChannel *chptr, aClient *sptr)
{
Member *m = find_member_link(chptr->members,sptr);
ModDataInfo *md;
if (!m)
return;
md = findmoddata_byname(MOD_DATA_STR, MODDATATYPE_MEMBER);
if (!md || !md->unserialize)
return;
md->unserialize(MOD_DATA_INVISIBLE, &moddata_member(m, md));
}
DLLFUNC int deny_all(aClient *cptr, aChannel *chptr, char mode, char *para, int checkt, int what)
{
return EX_ALWAYS_DENY;
}
DLLFUNC int moded_check_join(aClient *cptr, aChannel *chptr)
{
return channel_is_delayed(chptr) && moded_user_invisible(cptr,chptr);
}
DLLFUNC int moded_join(aClient *cptr, aChannel *chptr)
{
if (channel_is_delayed(chptr))
set_user_invisible(chptr,cptr);
return 0;
}
DLLFUNC int moded_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[])
{
if (channel_is_delayed(chptr) || channel_is_post_delayed(chptr))
clear_user_invisible(chptr,cptr);
return 0;
}
DLLFUNC int moded_quit(aClient *acptr, char *comment)
{
Membership *membership;
aChannel *chptr;
for (membership = acptr->user->channel; membership; membership=membership->next)
{
chptr = membership->chptr;
if (channel_is_delayed(chptr) || channel_is_post_delayed(chptr))
clear_user_invisible(chptr,acptr);
}
return 0;
}
DLLFUNC int moded_kick(aClient *cptr, aClient *sptr, aClient *acptr, aChannel *chptr, char *comment)
{
if (channel_is_delayed(chptr) || channel_is_post_delayed(chptr))
clear_user_invisible(chptr,acptr);
return 0;
}
DLLFUNC int moded_chanmode(aClient *cptr, aClient *sptr, aChannel *chptr,
char *modebuf, char *parabuf, int sendts, int samode)
{
// Handle case where we just unset +D but have invisible users
if (!channel_is_delayed(chptr) && !channel_is_post_delayed(chptr) && channel_has_invisible_users(chptr))
set_post_delayed(chptr);
else if (channel_is_delayed(chptr) && channel_is_post_delayed(chptr))
clear_post_delayed(chptr);
if ((channel_is_delayed(chptr) || channel_is_post_delayed(chptr)))
{
ParseMode pm;
int ret;
for (ret = parse_chanmode(&pm, modebuf, parabuf); ret; ret = parse_chanmode(&pm, NULL, NULL))
{
if (pm.what == MODE_ADD && (pm.modechar == 'o' || pm.modechar == 'h' || pm.modechar == 'a' || pm.modechar == 'q' || pm.modechar == 'v'))
{
Member* i;
aClient* user = find_client(pm.param,NULL);
if (!user)
continue;
if (moded_user_invisible(user,chptr))
clear_user_invisible_announce(chptr,user);
if (pm.modechar == 'v')
continue;
for (i = chptr->members; i; i = i->next)
{
if (i->cptr == user)
continue;
if (moded_user_invisible(i->cptr,chptr))
sendto_one(user,":%s!%s@%s JOIN :%s", i->cptr->name, i->cptr->user->username, GetHost(i->cptr), chptr->chname);
}
}
}
}
return 0;
}
DLLFUNC int moded_chanmsg(aClient *sptr, aChannel *chptr, char *text, int notice)
{
if ((channel_is_delayed(chptr) || channel_is_post_delayed(chptr)) && (moded_user_invisible(sptr,chptr)))
clear_user_invisible_announce(chptr,sptr);
return 0;
}
char *moded_serialize(ModData *m)
{
return m->i ? "1" : "0";
}
void moded_unserialize(char *str, ModData *m)
{
m->i = atoi(str);
}