energymech/src/ons.c

1233 lines
24 KiB
C
Raw Normal View History

2014-03-08 19:56:21 -05:00
/*
EnergyMech, IRC bot software
Parts Copyright (c) 1997-2009 proton
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 2 of the License, 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.
*/
#define COM_ONS_C
#include "config.h"
#include "defines.h"
#include "structs.h"
#include "global.h"
#include "h.h"
#include "text.h"
#include "mcmd.h"
2018-04-14 05:24:20 +02:00
#ifdef SUPPRESS
uint32_t makecrc(const char *args)
{
uint32_t crc = 0;
int n = 0;
while(args[n])
crc += ((((crc * 0xc960ebb3) ^ 0x14d0bd4d) + 0x9ff77d71) * args[n++]) - 0xb07daba7;
return(crc);
}
void send_suppress(const char *command, const char *args)
{
Mech *backup;
int crc;
crc = makecrc(args);
for(backup=botlist;backup;backup=backup->next)
{
if (backup != current)
{
backup->supres_cmd = command;
backup->supres_crc = crc;
}
}
botnet_relay(NULL,"CS%s %i\n",command,crc);
}
#endif /* SUPPRESS */
2014-03-08 19:56:21 -05:00
/*
* :nick!user@host KICK #channel kicknick :message
*/
void on_kick(char *from, char *rest)
{
Chan *chan;
ChanUser *doer,*victim;
char *channel,*nick;
channel = chop(&rest);
if ((CurrentChan = chan = find_channel_ac(channel)) == NULL)
return;
nick = chop(&rest);
if (rest && *rest == ':')
rest++;
nickcpy(CurrentNick,from);
if (current->spy & SPYF_CHANNEL)
send_spy(chan->name,"*** %s was kicked by %s (%s)",nick,CurrentNick,rest);
if (!nickcmp(current->nick,nick))
{
#ifdef DEBUG
debug("(on_kick) I was kicked from %s\n",chan->name);
#endif /* DEBUG */
Free(&chan->kickedby);
set_mallocdoer(on_kick);
2018-04-04 06:04:58 +02:00
chan->kickedby = stringdup(from);
2014-03-08 19:56:21 -05:00
chan->active = FALSE;
chan->sync = TRUE;
chan->bot_is_op = FALSE;
join_channel(chan->name,chan->key);
/*
* if we're kicked from the active channel, we need to find a new
* channel to set as the active one.
*/
if (chan == current->activechan)
{
for(chan=current->chanlist;chan;chan=chan->next)
{
if (chan->active)
break;
}
current->activechan = chan;
/*
* Might be set to NULL now, but its supposed to be checked whenever used.
* If not, we get a SEGV; and fix it.
*/
}
#ifdef STATS
if (chan && chan->stats)
chan->stats->flags |= CSTAT_PARTIAL;
#endif /* STATS */
/*
* this is the only return we can do: its the bot itself!
* channel userlist will be reconstructed on rejoin
*/
return;
}
#ifdef STATS
if (chan->setting[STR_STATS].str_var)
stats_plusminususer(chan,-1);
if (chan->stats)
chan->stats->kicks++;
#endif /* STATS */
/*
* making life easy for ourselves
*/
victim = find_chanuser(chan,nick);
doer = NULL;
if (chan->bot_is_op)
{
/*
* are we supposed to check for channel mass kicks?
*/
if (chan->setting[INT_MPL].int_var)
{
doer = find_chanuser(chan,from);
if (check_mass(chan,doer,INT_MKL))
mass_action(chan,doer);
}
/*
* are we supposed to protect users?
*/
if (chan->setting[INT_PROT].int_var)
{
if (victim->user && victim->user->x.x.prot)
{
/*
* doer might be NULL, prot_action() handles it
*/
prot_action(chan,from,doer,NULL,victim);
to_server("INVITE %s %s\n",nick,channel);
}
}
}
/*
* cant delete users who arent there
*/
if (victim)
{
#ifdef SEEN
make_seen(nick,victim->userhost,from,rest,now,SEEN_KICKED);
#endif /* SEEN */
/*
* Dont delete the poor sod before all has been processed
*/
remove_chanuser(chan,nick);
}
}
void on_join(Chan *chan, char *from)
{
Ban *ban;
ChanUser *cu;
int vpri;
/*
* Satisfy spies before we continue...
*/
if (current->spy & SPYF_CHANNEL)
send_spy(chan->name,"*** Joins: %s (%s)",CurrentNick,getuh(from));
/*
*
*/
#ifdef GREET
if (!CurrentShit && CurrentUser && CurrentUser->greet)
greet();
#endif /* GREET */
/*
* No further actions to be taken if the bot isnt opped
*/
if (!chan->bot_is_op)
return;
cu = chan->users;
/*
* Some stuff only applies to non-users
*/
if (!CurrentUser)
{
/*
* Kick banned (desynched) users if ABK is set
*/
if (chan->setting[TOG_ABK].int_var)
{
for(ban=chan->banlist;ban;ban=ban->next)
{
if (!matches(ban->banstring,from))
break;
}
if (ban)
{
send_kick(chan,CurrentNick,KICK_BANNED);
return;
}
}
/*
* Kickban users with control chars in their ident
* (which doesnt violate RFC1413 but is bloody annoying)
*/
if (chan->setting[TOG_CTL].int_var)
{
if (STRCHR(from,'\031') || STRCHR(from,'\002') || STRCHR(from,'\022') || STRCHR(from,'\026'))
{
deop_siteban(chan,cu);
send_kick(chan,CurrentNick,KICK_BAD_IDENT);
return;
}
}
}
/*
* If they're shitted, they're not allowed to be opped or voiced
*/
if (CurrentShit)
{
shit_action(chan,cu);
return;
}
/*
* Check for +ao users if AOP is toggled on
*/
if (chan->setting[TOG_AOP].int_var)
{
if (cu->user && cu->user->x.x.aop)
{
send_mode(chan,140,QM_CHANUSER,'+','o',(void*)cu);
return;
}
}
/*
* If AVOICE eq 0 we have nothing more to do
*/
vpri = 200;
switch(chan->setting[INT_AVOICE].int_var)
{
case 1:
vpri = 150;
if (cu->user && cu->user->x.x.avoice)
break;
/* fall through */
case 0:
return;
}
send_mode(chan,vpri,QM_CHANUSER,'+','v',(void*)cu);
}
void on_nick(char *from, char *newnick)
{
ChanUser *cu;
Chan *chan;
char newnuh[NUHLEN];
int maxcount;
int isbot;
nickcpy(CurrentNick,from);
#ifdef FASTNICK
/*
* grab the nick *RIGHT NOW*
* this is a setting because this is risky, you might get collided as a result
*/
if (!nickcmp(CurrentNick,current->wantnick))
to_server("NICK %s\n",current->wantnick);
#endif /* FASTNICK */
/*
* make the new From string
*/
sprintf(newnuh,"%s!%s",newnick,getuh(from));
#ifdef SEEN
make_seen(CurrentNick,from,newnick,NULL,now,SEEN_NEWNICK);
#endif /* SEEN */
/*
* snooping buggers
*/
if (current->spy & SPYF_CHANNEL)
send_spy(MATCH_ALL,"*** %s is now known as %s",CurrentNick,newnick);
change_authnick(from,newnuh);
if ((isbot = !nickcmp(current->nick,CurrentNick)))
{
setbotnick(current,newnick);
}
for(chan=current->chanlist;chan;chan=chan->next)
{
if ((cu = find_chanuser(chan,from)) == NULL)
continue;
/*
* only need to realloc the buffer if its too small
*/
if (strlen(cu->nick) >= strlen(newnick))
{
2018-04-04 06:04:58 +02:00
stringcpy(cu->nick,newnick);
2014-03-08 19:56:21 -05:00
}
else
{
Free((char**)&cu->nick);
set_mallocdoer(on_nick);
2018-04-04 06:04:58 +02:00
cu->nick = stringdup(newnick);
2014-03-08 19:56:21 -05:00
}
/*
* if the bot isnt opped, there's nothing more to do
*/
if (!chan->bot_is_op)
continue;
/*
* if its the current bot, we dont do diddly squat
*/
if (isbot)
continue;
shit_action(chan,cu);
/*
* check for nick-change-flood
*/
if ((maxcount = chan->setting[INT_NCL].int_var) < 2)
continue;
2018-03-16 02:45:13 +01:00
if ((now - cu->action_time[INDEX_NICK]) > NICKFLOODTIME)
2014-03-08 19:56:21 -05:00
{
2018-03-16 02:45:13 +01:00
cu->action_time[INDEX_NICK] = now + (NICKFLOODTIME / (maxcount - 1));
cu->action_num[INDEX_NICK] = 1;
2014-03-08 19:56:21 -05:00
}
else
{
2018-03-16 02:45:13 +01:00
cu->action_time[INDEX_NICK] += (NICKFLOODTIME / (maxcount - 1));
if (++cu->action_num[INDEX_NICK] >= maxcount)
2014-03-08 19:56:21 -05:00
{
deop_ban(chan,cu,NULL);
send_kick(chan,newnick,KICK_NICKFLOOD);
}
}
}
}
2018-03-16 02:45:13 +01:00
void on_msg(char *from, char *to, char *rest)
2014-03-08 19:56:21 -05:00
{
#ifdef SCRIPTING
Hook *hook;
#endif /* SCRIPTING */
#ifdef ALIAS
char amem[MSGLEN]; /* big buffers at the top */
Alias *alias;
int arec;
#endif /* ALIAS */
#ifdef REDIRECT
char *orig_to;
#endif /* REDIRECT */
char *pt,*origstart,*command;
uchar *p1,*p2;
int has_cc,has_bang;
int uaccess;
int i,j;
/*
* No line sent to this routine should be longer than MSGLEN
* Callers responsibility to check that from, to and msg is
* non-NULL and non-zerolength
*/
#ifdef NOTE
2018-03-16 02:45:13 +01:00
if (notelist && catch_note(from,to,rest))
2014-03-08 19:56:21 -05:00
return;
#endif /* NOTE */
/*
* If the message is for a channel and we dont accept
* public commands, we can go directly to common_public()
*/
if (CurrentChan && !CurrentChan->setting[TOG_PUB].int_var)
{
2018-03-16 02:45:13 +01:00
common_public(CurrentChan,from,"<%s> %s",rest);
2014-03-08 19:56:21 -05:00
return;
}
if (CurrentDCC)
{
uaccess = CurrentUser->x.x.access;
}
else
if ((uaccess = get_authaccess(from,NULL)) > OWNERLEVEL)
{
/*
* If its a bot we want nothing to do with it
*/
return;
}
/*
* remember where the string started
*/
2018-03-16 02:45:13 +01:00
origstart = rest;
2014-03-08 19:56:21 -05:00
if (from == CoreUser.name)
{
has_cc = TRUE;
}
else
{
has_cc = (current->setting[TOG_CC].int_var) ? FALSE : TRUE;
}
/*
* check for command bots nick replacing command char
*/
2018-03-16 02:45:13 +01:00
if ((p2 = (uchar*)(command = chop(&rest))) == NULL)
2014-03-08 19:56:21 -05:00
return;
p1 = (uchar*)current->nick;
while(!(i = tolowertab[*(p1++)] - tolowertab[*p2]) && *(p2++))
;
if (!i || ((p2 > (uchar*)command) && (*p2 == ':' || *p2 == ';' || *p2 == ',') && p2[1] == 0))
{
2018-03-16 02:45:13 +01:00
if ((command = chop(&rest)) == NULL)
2014-03-08 19:56:21 -05:00
return;
has_cc = TRUE;
}
has_bang = FALSE;
if (*command == current->setting[CHR_CMDCHAR].char_var)
{
has_cc = TRUE;
command++;
}
else
if (!has_cc && *command == '!')
{
has_bang = TRUE;
command++;
}
#ifdef ALIAS
arec = 0;
recheck_alias:
#endif /* ALIAS */
#ifdef ALIAS
for(alias=aliaslist;alias;alias=alias->next)
{
2018-04-04 06:04:58 +02:00
if (!stringcasecmp(alias->alias,command))
2014-03-08 19:56:21 -05:00
{
2018-03-16 02:45:13 +01:00
unchop(command,rest);
2018-03-13 02:39:29 +01:00
afmt(amem,alias->format,command);
2014-03-08 19:56:21 -05:00
#ifdef DEBUG
2018-03-13 02:39:29 +01:00
debug("(on_msg) [ALIAS] %s --> %s\n",command,amem);
2014-03-08 19:56:21 -05:00
#endif /* DEBUG */
2018-03-16 02:45:13 +01:00
rest = amem;
pt = chop(&rest);
2018-04-04 06:04:58 +02:00
i = stringcasecmp(pt,command);
2014-03-08 19:56:21 -05:00
command = pt;
arec++;
if ((arec < MAXALIASRECURSE) && (i != 0))
goto recheck_alias;
}
}
#endif /* ALIAS */
#ifdef REDIRECT
orig_to = to;
#endif /* REDIRECT */
i = 0;
#ifdef SCRIPTING
for(hook=hooklist;hook;hook=hook->next)
{
/*
* check if the hook applies to this particular bot
*/
if (hook->guid && hook->guid != current->guid)
continue;
/*
* does the hook match?
*/
2018-04-04 06:04:58 +02:00
if (hook->flags == HOOK_COMMAND && !stringcasecmp(command,hook->type.command))
2014-03-08 19:56:21 -05:00
{
2018-03-16 02:45:13 +01:00
if (hook->func(from,rest,hook))
2014-03-08 19:56:21 -05:00
/* if the hook returns non-zero, the input should not be parsed internally */
i = 1;
}
}
if (i) return;
#endif /* SCRIPTING */
/*
* match "command" against internal command list
*/
for(;mcmd[i].name;i++)
{
if (!has_cc && mcmd[i].cc && !(has_bang && mcmd[i].cbang))
continue;
if (uaccess < acmd[i])
continue;
2018-04-04 06:04:58 +02:00
j = stringcasecmp(mcmd[i].name,command);
2014-03-08 19:56:21 -05:00
if (j < 0)
continue;
if (j > 0)
break;
#if defined(BOTNET) && defined(REDIRECT)
if (mcmd[i].nocmd && redirect.to)
return;
#endif /* BOTNET && REDIRECT */
if (mcmd[i].nopub && CurrentChan)
{
#ifdef DEBUG
debug("(on_msg) Public command (%s) ignored\n",command);
#endif /* DEBUG */
return;
}
2018-03-16 02:45:13 +01:00
2014-03-08 19:56:21 -05:00
CurrentCmd = &mcmd[i];
2018-03-27 01:48:21 +02:00
#ifdef SUPPRESS
2018-03-16 02:45:13 +01:00
#ifdef BOTNET
// experimental command supression
if (CurrentCmd->name == current->supres_cmd)
{
int crc;
crc = makecrc(rest);
if (current->supres_crc == crc)
{
// another bot has already executed this command and is trying to supress its execution on other bots
current->supres_cmd = NULL;
current->supres_crc = 0;
#ifdef DEBUG
debug("(on_msg) command \"%s\" from %s was supressed\n",CurrentCmd->name,CurrentNick);
#endif
return;
}
}
//if command should be supressed ...
2018-03-27 01:48:21 +02:00
if (mcmd[i].supres && CurrentChan)
2018-03-16 02:45:13 +01:00
{
2018-03-27 01:48:21 +02:00
send_suppress(CurrentCmd->name,rest);
2018-03-16 02:45:13 +01:00
}
#endif
2018-03-27 01:48:21 +02:00
#endif /* SUPPRESS */
2014-03-08 19:56:21 -05:00
/*
* convert the command to uppercase
*/
2018-04-04 06:04:58 +02:00
stringcpy(command,mcmd[i].name);
2014-03-08 19:56:21 -05:00
/*
* send statmsg with info on the command executed
*/
if (current->setting[TOG_SPY].int_var)
{
send_spy(SPYSTR_STATUS,":%s[%i]: Executing %s[%i]",
CurrentNick,uaccess,command,(int)acmd[i]);
}
/*
* list of last LASTCMDSIZE commands
*/
if (from != CoreUser.name)
{
Free(&current->lastcmds[LASTCMDSIZE-1]);
for(j=LASTCMDSIZE-2;j>=0;j--)
current->lastcmds[j+1] = current->lastcmds[j];
if ((pt = STRCHR(from,'@')) == NULL)
pt = from;
set_mallocdoer(on_msg);
current->lastcmds[0] = (char*)Calloc(strlen(pt) + 45);
if (CurrentUser)
{
sprintf(current->lastcmds[0],"[%s] %s\r%s[%-3i]\t(*%s)",
time2medium(now),command,CurrentUser->name,
(CurrentUser->x.x.access),pt);
}
else
{
sprintf(current->lastcmds[0],"[%s] %s\r%s[---]\t(*%s)",
time2medium(now),command,CurrentNick,pt);
}
}
/*
* CAXS check: first argument might be a channel
* check user access on target channel
*/
if (mcmd[i].caxs)
{
/* get channel name; 1: msg, 2: to, 3: active channel */
2018-04-04 06:04:58 +02:00
to = (char*)get_channel(to,&rest);
2014-03-08 19:56:21 -05:00
if (!ischannel(to))
return;
uaccess = get_authaccess(from,to);
if (uaccess < acmd[i])
return;
CurrentChan = find_channel_ac(to);
if (mcmd[i].acchan && !CurrentChan)
{
to_user(from,ERR_CHAN,to);
return;
}
}
else
/*
* GAXS check: user needs global access
*/
if (mcmd[i].gaxs)
{
uaccess = get_authaccess(from,MATCH_ALL);
if (uaccess < acmd[i])
return;
}
/*
* CARGS check: at least one argument is required
*/
2018-03-16 02:45:13 +01:00
if (mcmd[i].args && !*rest)
2014-03-08 19:56:21 -05:00
{
if (uaccess) usage_command(from,command);
return;
}
#ifdef REDIRECT
/*
* can this command be redirected?
*/
if (!redirect.to && mcmd[i].redir)
{
if (mcmd[i].lbuf && ischannel(orig_to))
{
2018-04-04 06:04:58 +02:00
redirect.to = stringdup(to);
2014-03-08 19:56:21 -05:00
redirect.method = R_PRIVMSG;
}
else
2018-03-16 02:45:13 +01:00
if (begin_redirect(from,rest) < 0)
2014-03-08 19:56:21 -05:00
return;
}
#endif /* REDIRECT */
2018-04-04 06:04:58 +02:00
if (mcmd[i].dcc && partyline_only_command(from))
2014-03-08 19:56:21 -05:00
return;
2018-03-16 02:45:13 +01:00
mcmd[i].func(from,to,rest,acmd[i]);
2014-03-08 19:56:21 -05:00
#ifdef DEBUG
CurrentCmd = NULL;
#endif /* DEBUG */
#ifdef REDIRECT
end_redirect();
#endif /* REDIRECT */
/*
* be quick to exit afterwards, there are "dangerous" commands like DIE and DEL (user)
*/
return;
}
/*
* un-chop() the message string
*/
2018-03-16 02:45:13 +01:00
unchop(origstart,rest);
2014-03-08 19:56:21 -05:00
if (CurrentChan)
{
common_public(CurrentChan,from,"<%s> %s",origstart);
}
else
if (has_cc && *command && uaccess)
{
to_user(from,ERR_UNKNOWN_COMMAND);
}
else
if (CurrentDCC)
{
partyline_broadcast(CurrentDCC,"<%s> %s\n",origstart);
#ifdef BOTNET
botnet_relay(NULL,"PM* * %s@%s %s\n",CurrentNick,current->nick,origstart);
#endif /* BOTNET */
}
else
{
send_spy(SPYSTR_MESSAGE,"<%s> %s",CurrentNick,origstart);
}
}
void on_mode(char *from, char *channel, char *rest)
{
Chan *chan;
ChanUser *doer;
ChanUser *victim;
Shit *shit;
char templimit[20];
char *nick;
char *parm,*nickuh,*mode;
int i,sign,enfm,maxprot;
if ((chan = find_channel_ac(channel)) == NULL)
return;
channel = chan->name;
if (current->spy & SPYF_CHANNEL)
send_spy(channel,"*** %s sets mode: %s",CurrentNick,rest);
maxprot = chan->setting[INT_PROT].int_var;
sign = '+';
mode = chop(&rest);
/*
* might be NULL but we have to handle that due to server modes
*/
doer = find_chanuser(chan,from);
modeloop:
if (*mode == 'o' || *mode == 'v')
{
nick = chop(&rest);
if ((victim = find_chanuser(chan,nick)) == NULL)
{
mode++;
goto modeloop;
}
}
switch(*mode)
{
case '+':
case '-':
sign = *mode;
break;
/*
*
* MODE <channel> +/-o <nick>
*
*/
case 'o':
i = (victim->user) ? victim->user->x.x.access : 0;
/* +o */ if (sign == '+')
{
victim->flags |= CU_CHANOP;
victim->flags &= ~CU_DEOPPED;
if (!i)
{
if (victim->shit || (chan->setting[TOG_SD].int_var && !doer) ||
chan->setting[TOG_SO].int_var)
{
send_mode(chan,60,QM_CHANUSER,'-','o',victim);
}
}
else
if (!nickcmp(current->nick,nick))
{
/*
* wooohoooo! they gave me ops!!!
*/
chan->bot_is_op = TRUE;
if (chan->kickedby)
{
if (chan->setting[TOG_RK].int_var)
send_kick(chan,nickcpy(NULL,chan->kickedby),KICK_REVENGE);
Free(&chan->kickedby);
}
check_shit();
update_modes(chan);
}
#ifdef DEBUG
debug("(on_mode) %s!%s --> %i\n",victim->nick,victim->userhost,i);
#endif /* DEBUG */
}
/* -o */ else
{
victim->flags &= ~(CU_CHANOP|CU_DEOPPED);
if (i == BOTLEVEL)
{
if (!nickcmp(current->nick,nick))
{
/*
* they dont love me!!! :~(
*/
chan->bot_is_op = FALSE;
}
}
/*
* idiots deopping themselves
*/
if (!nickcmp(from,nick))
break;
/*
* 1. Use enfm var to temporarily store users access
* 2. get_userlevel also checks is_localbot()...
*/
enfm = (doer && doer->user) ? doer->user->x.x.access : 0;
if (enfm == BOTLEVEL)
break;
if (check_mass(chan,doer,INT_MDL))
mass_action(chan,doer);
if (maxprot && (victim->user && victim->user->x.x.prot) && !victim->shit)
{
/*
* FIXME: does it matter if the user is logged in or not?
*/
nickuh = get_nuh(victim);
if (get_authaccess(nickuh,channel))
{
send_mode(chan,60,QM_CHANUSER,'+','o',victim);
prot_action(chan,from,doer,NULL,victim);
}
}
}
break;
/*
*
* MODE <channel> +/-v <nick>
*
*/
case 'v':
if (sign == '+')
victim->flags |= CU_VOICE;
else
victim->flags &= ~CU_VOICE;
break;
#ifdef IRCD_EXTENSIONS
/*
:joonicks!*@* MODE #emech +I *king*!*@*
:joonicks!*@* MODE #emech +e *kong*!*@*
*/
#endif /* IRCD_EXTENSIONS */
/*
*
* MODE <channel> +/-b <parm>
*
*/
#ifdef IRCD_EXTENSIONS
/*
* ircnet braindamage modes
*/
case 'I':
case 'e':
#endif /* IRCD_EXTENSIONS */
case 'b':
parm = chop(&rest);
/* +b */ if (sign == '+')
{
#ifdef IRCD_EXTENSIONS
Ban *newban;
newban = make_ban(&chan->banlist,from,parm,now);
if (*mode == 'I') newban->imode = TRUE;
if (*mode == 'e') newban->emode = TRUE;
/*
* I/e modes are low privilige and not checked for protection (yet?)
*/
break;
#else /* IRCD_EXTENSIONS */
make_ban(&chan->banlist,from,parm,now);
#endif /* IRCD_EXTENSIONS */
/*
* skip protection checks if the doer is myself or another known bot
*/
if (doer && doer->user && doer->user->x.x.access == BOTLEVEL)
break;
if (check_mass(chan,doer,INT_MBL))
mass_action(chan,doer);
if (maxprot && get_protaction(chan,parm))
{
shit = get_shituser(parm,channel);
if (!shit || !shit->action)
{
/*
* FIXME: do we have a CU for the `from' user? -- yes: doer
* bot_is_op checked: no
*/
send_mode(chan,160,QM_RAWMODE,'-','b',parm);
prot_action(chan,from,doer,parm,NULL);
}
}
}
/* -b */ else
{
#ifdef IRCD_EXTENSIONS
if (*mode == 'I' || *mode == 'e')
{
delete_modemask(chan,parm,*mode);
break;
}
#endif /* IRCD_EXTENSIONS */
delete_ban(chan,parm);
if (!chan->setting[TOG_SHIT].int_var)
break;
/* whats this??? */
shit = get_shituser(parm,channel); // calls find_shit? clobbers get_nuh buffer
i = (shit) ? shit->action : 0;
if (i < SHIT_PERMABAN)
{
shit = find_shit(parm,channel);
i = (shit) ? shit->action : 0;
}
if (i == SHIT_PERMABAN)
{
send_mode(chan,160,QM_RAWMODE,'+','b',shit->mask);
}
}
break;
case 'p':
case 's':
case 'm':
case 't':
case 'i':
case 'n':
if (reverse_mode(from,chan,*mode,sign))
{
send_mode(chan,160,QM_RAWMODE,(sign == '+') ? '-' : '+',*mode,NULL);
}
i = (sign == '+');
switch(*mode)
{
case 'p':
chan->private = i;
break;
case 's':
chan->secret = i;
break;
case 'm':
chan->moderated = i;
break;
case 't':
chan->topprot = i;
break;
case 'i':
chan->invite = i;
break;
case 'n':
chan->nomsg = i;
break;
}
break;
/* k */
case 'k':
parm = chop(&rest);
enfm = reverse_mode(from,chan,'k',sign);
if (sign == '+')
{
chan->keymode = TRUE;
/*
* Undernet clueless-coder-kludge
*/
chan->hiddenkey = (parm) ? FALSE : TRUE;
if (enfm && parm)
{
send_mode(chan,160,QM_RAWMODE,'-','k',parm);
}
Free(&chan->key);
set_mallocdoer(on_mode);
2018-04-04 06:04:58 +02:00
chan->key = stringdup((parm) ? parm : "???");
2014-03-08 19:56:21 -05:00
}
else
{
if (enfm && parm)
{
send_mode(chan,160,QM_RAWMODE,'+','k',parm);
}
chan->keymode = FALSE;
}
break;
/* l */
case 'l':
if (sign == '+')
{
parm = chop(&rest);
2018-04-04 06:04:58 +02:00
chan->limit = asc2int(parm);
2014-03-08 19:56:21 -05:00
if (errno)
chan->limit = 0;
chan->limitmode = TRUE;
}
else
{
chan->limitmode = FALSE;
}
if (reverse_mode(from,chan,'l',sign))
{
if (sign == '+')
{
send_mode(chan,160,QM_RAWMODE,'-','l',NULL);
}
else
{
sprintf(templimit,"%i",chan->limit);
send_mode(chan,160,QM_RAWMODE,'+','l',templimit);
}
}
break;
case 0:
return;
}
mode++;
goto modeloop;
}
void common_public(Chan *chan, char *from, char *spyformat, char *rest)
{
ChanUser *doer;
2018-04-04 06:04:58 +02:00
int n,upper;
2014-03-08 19:56:21 -05:00
if (current->spy & SPYF_CHANNEL)
send_spy(chan->name,spyformat,CurrentNick,rest);
if (!chan->bot_is_op)
return;
doer = find_chanuser(chan,from);
2018-04-04 06:04:58 +02:00
// check if more than half of rest is caps
n = upper = 0;
while(rest[n])
{
if ((rest[n] >= 'A' && rest[n] <= 'Z') || (rest[n] == '!'))
upper += 2;
n++;
}
// trigger caps flood action
if (upper >= n)
2014-03-08 19:56:21 -05:00
{
if (check_mass(chan,doer,INT_CKL))
send_kick(chan,CurrentNick,KICK_CAPS);
}
if (chan->setting[TOG_KS].int_var)
{
if (!CurrentUser || !CurrentUser->x.x.access)
check_kicksay(chan,doer,rest);
}
if (check_mass(chan,doer,INT_FL))
{
if (chan->setting[INT_FPL].int_var > 1)
deop_ban(chan,doer,NULL);
send_kick(chan,CurrentNick,KICK_TEXTFLOOD);
send_spy(SPYSTR_STATUS,"%s kicked from %s for flooding",from,chan->name);
}
}
void on_action(char *from, char *to, char *rest)
{
if (CurrentChan)
{
common_public(CurrentChan,from,"* %s %s",rest);
return;
}
if (CurrentDCC)
{
partyline_broadcast(CurrentDCC,"* %s %s\n",rest);
#ifdef BOTNET
botnet_relay(NULL,"PM* * %s@%s \001%s\n",CurrentNick,current->nick,rest);
#endif /* BOTNET */
return;
}
if (current->spy & SPYF_MESSAGE)
send_spy(SPYSTR_MESSAGE,"* %s %s",CurrentNick,rest);
}
#ifdef DYNCMD
/*
*
*
*
*/
void do_chaccess(COMMAND_ARGS)
{
/*
* on_msg checks: GAXS + CARGS
*/
int i,oldaccess,newaccess,uaccess,dis;
char *name,*axs;
name = chop(&rest);
axs = chop(&rest);
if (!axs && !name)
{
usage(from); /* usage for CurrentCmd->name */
return;
}
dis = FALSE;
2018-04-04 06:04:58 +02:00
newaccess = asc2int(axs);
2014-03-08 19:56:21 -05:00
if (axs)
{
2018-04-04 06:04:58 +02:00
if (!stringcasecmp(axs,"disable"))
2014-03-08 19:56:21 -05:00
{
dis = TRUE;
newaccess = 100;
}
else
{
if (errno || (newaccess < 0) || (newaccess > OWNERLEVEL))
{
to_user(from,"Command access level must be between 0 and %i",OWNERLEVEL);
return;
}
}
}
uaccess = get_useraccess(from,ANY_CHANNEL);
if (newaccess > uaccess)
{
to_user(from,"Can't change access level to one higher than yours");
return;
}
if (dis && uaccess < OWNERLEVEL)
{
to_user(from,"Insufficient access to disable commands");
return;
}
for(i=0;mcmd[i].name;i++)
{
2018-04-04 06:04:58 +02:00
if (!stringcasecmp(mcmd[i].name,name))
2014-03-08 19:56:21 -05:00
{
oldaccess = acmd[i];
if (dis || oldaccess > 200)
{
to_user(from,"The command \"%s\" has been permanently disabled",name);
acmd[i] = 250; /* unsigned char, max 255 */
return;
}
if (newaccess == -1)
{
to_user(from,"The access level needed for that command is %i",oldaccess);
to_user(from,"To change it, specify new access level");
return;
}
if (oldaccess > uaccess)
{
to_user(from,"Can't change an access level that is higher than yours");
return;
}
if (oldaccess == newaccess)
to_user(from,"The access level was not changed");
else
to_user(from,"Command access level changed from %i to %i",oldaccess,newaccess);
acmd[i] = newaccess;
return;
}
}
to_user(from,"Unknown command: %s",name);
}
#endif /* DYNCMD */
int access_needed(char *name)
{
int i;
for(i=0;mcmd[i].name;i++)
{
2018-04-04 06:04:58 +02:00
if (!stringcasecmp(mcmd[i].name,name))
2014-03-08 19:56:21 -05:00
{
return(acmd[i]);
}
}
return(-1);
}
void do_last(COMMAND_ARGS)
{
char *pt,*thenum;
int i,num;
if (!rest || !*rest)
num = 5;
else
{
thenum = chop(&rest);
2018-04-04 06:04:58 +02:00
num = asc2int(thenum);
2014-03-08 19:56:21 -05:00
}
if ((num < 1) || (num > LASTCMDSIZE))
usage(from); /* usage for CurrentCmd->name */
else
{
pt = (char*)1;
table_buffer(TEXT_LASTHDR,num);
for(i=0;i<num;i++)
{
if (!pt)
break;
pt = current->lastcmds[i];
table_buffer(FMT_PLAIN,(pt) ? pt : TEXT_NONE);
}
table_send(from,1);
}
}