Code: Select all
/*
* m_joinmute.c adds a new channel mode: +J <seconds> which stops
* users which are not on channel for <seconds> from speaking.
* (C) 2009 Dvlpr
*
* It is my first public module =P
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef _WIN32
#include "version.h"
#endif
#define DelHook(x) if (x) HookDel(x); x = NULL
Hook *HookJoin = NULL;
Hook *HookPart = NULL;
Hook *HookMessage = NULL;
Hook *HookQuit = NULL;
Hook *HookKick = NULL;
static ModuleInfo *thismodinfo = NULL;
int cb_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[]);
int cb_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[]);
int cb_quit(aClient *sptr, char *comment);
int cb_kick(aClient *cptr, aClient *sptr, aClient *who, aChannel *chptr, char *comment);
DLLFUNC char *cb_msg(aClient *, aClient *, aChannel *, char *, int);
#ifdef HOOKTYPE_REHASH_COMPLETE
static int cb_rehash_complete();
Hook *HookRehashDone;
#endif
void add_user_to_memory(aClient *sptr, aChannel *chptr);
typedef struct _channels_users_
{
struct _channel_users *prev, *next;
aClient *source;
aChannel *chptr;
int joined_since;
} UsersM;
UsersM *muted_users; /* List of data */
UsersM *FindUserInMemory(aClient *sptr, aChannel *chptr);
void del_user_from_memory(UsersM *u);
Cmode_t EXTCMODE_JOINMUTE = 0L;
typedef struct {
EXTCM_PAR_HEADER
int seconds;
} JoinMute;
int modeJ_is_ok(aClient *sptr, aChannel *chptr, char *para, int checkt, int what);
CmodeParam * modeJ_put_param(CmodeParam *lst, char *para);
char *modeJ_get_param(CmodeParam *lst);
char *modeJ_conv_param(char *param);
void modeJ_free_param(CmodeParam *lst);
CmodeParam *modeJ_dup_struct(CmodeParam *src);
int modeJ_sjoin_check(aChannel *chptr, CmodeParam *ourx, CmodeParam *theirx);
ModuleHeader MOD_HEADER(m_joinmute)
= {
"m_joinmute",
"$Id: m_joinmute.c,v 0.1 2009/04/16 14:14 $",
"Adds +J chmode: Join Mute for X seconds",
"3.2-b8-1",
NULL
};
DLLFUNC int MOD_TEST(m_joinmute)(ModuleInfo *modinfo)
{
return MOD_SUCCESS;
}
DLLFUNC int MOD_INIT(m_joinmute)(ModuleInfo *modinfo)
{
CmodeInfo req;
thismodinfo = modinfo;
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM);
memset(&req, 0, sizeof(req));
req.paracount = 1;
req.flag = 'J';
req.is_ok = modeJ_is_ok;
req.put_param = modeJ_put_param;
req.get_param = modeJ_get_param;
req.conv_param = modeJ_conv_param;
req.free_param = modeJ_free_param;
req.dup_struct = modeJ_dup_struct;
req.sjoin_check = modeJ_sjoin_check;
CmodeAdd(thismodinfo->handle, req, &EXTCMODE_JOINMUTE);
return MOD_SUCCESS;
}
DLLFUNC int MOD_LOAD(m_joinmute)(int module_load)
{
HookJoin = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_JOIN, cb_join);
HookPart = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_PART, cb_part);
HookMessage = HookAddPCharEx(thismodinfo->handle, HOOKTYPE_CHANMSG, cb_msg);
HookQuit = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_QUIT, cb_quit);
HookKick = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_KICK, cb_kick);
#ifdef HOOKTYPE_REHASH_COMPLETE
HookRehashDone = HookAddEx(thismodinfo->handle, HOOKTYPE_REHASH_COMPLETE, cb_rehash_complete);
#endif
return MOD_SUCCESS;
}
DLLFUNC int MOD_UNLOAD(m_joinmute)(int module_unload)
{
DelHook(HookJoin);
DelHook(HookPart);
DelHook(HookMessage);
DelHook(HookQuit);
#ifdef HOOKTYPE_REHASH_COMPLETE
DelHook(HookRehashDone);
#endif
return MOD_SUCCESS;
}
int modeJ_is_ok(aClient *sptr, aChannel *chptr, char *para, int checkt, int what)
{
int seconds;
if(what == MODE_ADD)
seconds = atoi(para);
if ((checkt == EXCHK_ACCESS) || (checkt == EXCHK_ACCESS_ERR))
{
if (IsPerson(sptr) && is_chan_op(sptr, chptr))
return EX_ALLOW;
if (checkt == EXCHK_ACCESS_ERR) /* can only be due to being halfop */
sendto_one(sptr, err_str(ERR_NOTFORHALFOPS), me.name, sptr->name, 'J');
return EX_DENY;
}
else if (checkt == EXCHK_PARAM)
{
if(seconds < 0 || seconds > 65536)
{
sendnotice(sptr, "*** [ERROR] Seconds value is out of range!");
return EX_DENY;
}
return EX_ALLOW;
}
return 0;
}
CmodeParam * modeJ_put_param(CmodeParam *r_in, char *param)
{
JoinMute *r = (JoinMute *)r_in;
int seconds = atoi(param);
if (!r)
{
/* Need to create one */
r = (JoinMute *)malloc(sizeof(JoinMute));
memset(r, 0, sizeof(JoinMute));
r->flag = 'J';
}
if(seconds < 0 || seconds > 65536)
seconds = 0;
r->seconds = seconds;
return (CmodeParam *)r;
}
char *modeJ_get_param(CmodeParam *r_in)
{
JoinMute *r = (JoinMute *)r_in;
static char retbuf[16];
if (!r)
return NULL;
snprintf(retbuf, sizeof(retbuf), "%d", r->seconds);
return retbuf;
}
char *modeJ_conv_param(char *param_in)
{
static char retbuf[32];
int num = atoi(param_in);
if(num < 0)
num = 0;
else if(num > 65536)
num = 255;
else if(!num)
num = 0;
snprintf(retbuf, sizeof(retbuf), "%d", num);
return retbuf;
}
void modeJ_free_param(CmodeParam *r)
{
JoinMute *n = (JoinMute *)r;
free(n);
return;
}
CmodeParam *modeJ_dup_struct(CmodeParam *r_in)
{
JoinMute *n = (JoinMute *)malloc(sizeof(JoinMute));
memcpy(n, r_in, sizeof(JoinMute));
return (CmodeParam *)n;
}
int modeJ_sjoin_check(aChannel *chptr, CmodeParam *ourx, CmodeParam *theirx)
{
JoinMute *our = (JoinMute *)ourx;
JoinMute *their = (JoinMute *)theirx;
if (our->seconds == their->seconds)
return EXSJ_SAME;
if (our->seconds > their->seconds) /* Server with more seconds winning */
return EXSJ_WEWON;
else
return EXSJ_THEYWON;
}
/** add_user_to_memory
* Adds user to currently muted users list
* Allocates the memory for data
*/
void add_user_to_memory(aClient *sptr, aChannel *chptr)
{
UsersM *u = (UsersM *) MyMallocEx(sizeof(UsersM));
if(!u)
return;
u->chptr = chptr;
u->source = sptr;
u->joined_since = TStime();
AddListItem(u, muted_users);
return;
}
/** del_user_from_memory
* Removes user from currently muted users list
* Frees the memory allocated for data
*/
void del_user_from_memory(UsersM *u)
{
if(!u)
return;
DelListItem(u, muted_users);
MyFree(u);
return;
}
/** FindUserInMemory
* Scans through currently muted users
* to find matching one, if the user is found
* its pointer will be returned instantly
*/
UsersM *FindUserInMemory(aClient *sptr, aChannel *chptr)
{
UsersM *uz;
for(uz = muted_users; uz; uz = (UsersM *)uz->next)
{
if(!find_client(uz->source->name, NULL))
{
del_user_from_memory(uz);
continue;
}
if(!IsMember(uz->source, uz->chptr))
{
del_user_from_memory(uz);
continue;
}
if(!(uz->chptr->mode.extmode & EXTCMODE_JOINMUTE))
{
del_user_from_memory(uz);
continue;
}
if((uz->source == sptr) && (uz->chptr == chptr))
return uz;
}
return NULL;
}
/* Used on quit - just remove all entries with sptr as a user */
void clear_matching_entries(aClient *sptr)
{
UsersM *userz;
for(userz = muted_users; userz; userz = (UsersM *)userz->next)
{
if(userz->source == sptr)
del_user_from_memory(userz);
}
}
DLLFUNC char *cb_msg(aClient *cptr, aClient *sptr, aChannel *chptr, char *text, int notice)
{
JoinMute *para = (JoinMute *)extcmode_get_struct(chptr->mode.extmodeparam, 'J');
UsersM *u;
if(!MyClient(sptr))
return text;
u = FindUserInMemory(sptr, chptr); /* Let's find entry in muted users list :) */
/* hops/vops/ops are allowed to send it... */
if(is_chan_op(sptr, chptr) || is_half_op(sptr, chptr) || has_voice(sptr, chptr) || IsAnOper(sptr))
return text;
if(!(chptr->mode.extmode & EXTCMODE_JOINMUTE))
return text;
if(!u)
return text; /* Not found - let it be sent! -- Dvlpr */
if((TStime() - u->joined_since) > para->seconds) /* How we know if user allowed? we just check if current time - time when user
* joined the channel is more then seconds and if yes, we allow sending text + deleting
* user's data from muted users list */
{
del_user_from_memory(u);
return text;
}
/* 404! :] -- Dvlpr */
sendto_one(sptr, ":%s 404 %s %s :Cannot send to channel: you must wait %d seconds after joining"
" to speak", me.name, sptr->name, chptr->chname, para->seconds);
return NULL;
}
int cb_join(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[])
{
add_user_to_memory(sptr, chptr);
return HOOK_CONTINUE;
}
int cb_part(aClient *cptr, aClient *sptr, aChannel *chptr, char *parv[])
{
UsersM *u = FindUserInMemory(sptr, chptr);
if(!u)
return HOOK_CONTINUE;
del_user_from_memory(u);
return HOOK_CONTINUE;
}
int cb_quit(aClient *sptr, char *comment)
{
clear_matching_entries(sptr);
return HOOK_CONTINUE;
}
int cb_kick(aClient *cptr, aClient *sptr, aClient *who, aChannel *chptr, char *comment)
{
UsersM *u = FindUserInMemory(who, chptr);
if(!u)
return HOOK_CONTINUE;
del_user_from_memory(u);
return HOOK_CONTINUE;
}
#ifdef HOOKTYPE_REHASH_COMPLETE
static int cb_rehash_complete()
{
HookJoin = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_JOIN, cb_join);
HookPart = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_PART, cb_part);
HookMessage = HookAddPCharEx(thismodinfo->handle, HOOKTYPE_CHANMSG, cb_msg);
HookQuit = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_QUIT, cb_quit);
HookKick = HookAddEx(thismodinfo->handle, HOOKTYPE_LOCAL_KICK, cb_kick);
return HOOK_CONTINUE;
}
#endif