Protection scripts make up a major part of any full script. They also make up a large part of questions - how exactly do you make one? This document provides worked protection scripts for a variety of different things...
Swear Word Kicker
Excessive Caps Kicker
Excessive Punctuation Kicker
Excessive Colour Kicker
Excessively Long Text Kicker
Channel Advert Kicker
Bad IdentD Kicker
Revolving Door Kicker
Guest Kicker
Offensive Nickname Kicker
Repeat Kicker
Flood Kicker
Nick Flood Kicker
CTCP Flood Kicker
Clone Kicker
Bad Channel Kicker
Reaction Levels
And also on how to change how the script reacts to an offence due to the number of times the person has previously offended (Reaction Level)
Please be aware that all of these scripts were written for mIRC 5.9 so earlier or later versions may not be compatiable (e.g. changes in identifiers, the way mIRC evaluates using []'s etc...). You should be also aware that you may need to COMBINE events if you wish to use multiple kickers... e.g. if you wanted to use the swear kicker and the excessive caps kicker and the channel advert kicker then I strongly recommend you COMBINE these events. This is because many of the kickers use the same event, e.g. on TEXT with a matchtext wildcard of *, now the problem with this is only the first event would react, none of the other kickers would be called. So, For instance, if you wanted to combine the caps kicker and the punctuation kicker you would have to combine the two into:
on @*:TEXT:*:#: {
; Caps kicker code goes here
if ($len($1-) < 9) || ($nick isop #) return
var %text = $strip($remove($1-,$chr(32)))
var %non.caps = $len($removecs(%text,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z))
; %non.caps counts number of non-caps - note how it uses $removeCS (Case SenSiTiVE)
var %full.line = $len(%text)
; %full.line counts total length of line (with spaces removed)
var %percent = $calc(1 - (%non.caps / %full.line))
;This %percent is set to how much of the text is actually caps. This used to be a lot harder to do,
;but Khaled then added $removeCS which allowed you to remove letters by their case. So if you compare
;the length of text with the length of text with the uppercase words removed, you can calculate how
;much of the text as a percentage was caps
if (%percent >= 0.8) {
;This if statement checks the percent of text that is caps,
; and if its greater or equal to 0.8 then it will kick the person
;percent can range from 0.0 to 1.0
ban -u60 # $nick 11
kick # $nick Your text contains $calc(%percent * 100) percent caps. This is not acceptable
}
; Punctuation kicker code goes here
if ($calc($count($1-,?) + $count($1-,!)) >= 10) {
;The above if statement is all you really need for a punctuation kicker
;It just counts the number of times ! and ? was said, and if that number is greater or equal to
;10 then it kicks the user
ban -u6o # $nick 11
kick # $nick You used too many !?'s ( $+ $count($1-,?) $+ ?'s and $count($1-,!) $+ !'s)
}
; If you wanted to combine another kicker its code would go here
}
One of the simplest versions of a Swear Kicker is:
on @*:TEXT:*:#:{
if ($nick !isop #) {
if (shit isin $1-) || (dick isin $1-) || (fuck isin $1-) {
;The above if statement is what actually checks for the swear words
ban -u60 # $nick 11
kick # $nick Do not swear!
}
}
}
However if you are out to impress you could make the swear word list dynamic. You could have a variable: /set %swear.words shit dick fuck pussy ass
then get the script to check each word in the variable. This means you need to use tokens.
on @*:TEXT:*:#: {
if ($nick !isop #) {
var %i = 0
while (%i < $numtok(%swear.words,32)) {
; this while loops keeps going until its checked every word in %swear.words
inc %i
var %current.word = $gettok(%swear.words,%i,32)
if ($istok($strip($1-),%current.word,32) == $true) {
;$istok returns $true if %current.word is in the text
ban -u60 # $nick 11
kick # $nick Do not swear (You said %current.word $+ )
}
}
}
}
The Excessive Caps Kicker can also be done in two ways. However the below method is generally the best:
on @*:TEXT:*:#: {
if ($len($1-) < 9) || ($nick isop #) return
var %text = $strip($remove($1-,$chr(32)))
var %non.caps = $len($removecs(%text,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z))
; %non.caps counts number of non-caps - note how it uses $removeCS (Case SenSiTiVE)
var %full.line = $len($strip($remove(%text,$chr(32))))
; %full.line counts total length of line (with spaces removed)
var %percent = $calc(1 - (%non.caps / %full.line))
;This %percent is set to how much of the text is actually caps. This used to be a lot harder to do,
;but Khaled then added $removeCS which allowed you to remove letters by their case. So if you compare
;the length of text with the length of text with the uppercase words removed, you can calculate how
;much of the text as a percentage was caps
if (%percent >= 0.8) {
;This if statement checks the percent of text that is caps,
; and if its greater or equal to 0.8 then it will kick the person
;percent can range from 0.0 to 1.0
ban -u60 # $nick 11
kick # $nick Your text contains $calc(%percent * 100) percent caps. This is not acceptable
}
}
The Excessive Punctuation Kicker is probably one of the easiest kickers. All you really need is an IF statement, $calc and $count:
on @*:TEXT:*:#:{
if ($nick isop #) return
if ($calc($count($1-,?) + $count($1-,!)) >= 10) {
;The above if statement is all you really need for a punctuation kicker
;It just counts the number of times ! and ? was said, and if that number is greater or equal to
;10 then it kicks the user
ban -u60 # $nick 11
kick # $nick You used too many !?'s ( $+ $count($1-,?) $+ ?'s and $count($1-,!) $+ !'s)
}
}
If you felt like a challenge, you could rewrite this code to use a similar format to the advanced swear kicker so that you define what characters are considered to be punctuation.
The Excessive Colour Kicker is very similar to the punctuation kicker, it also uses $count. In general there are about 5 control codes used for colour(3), bold(2), underline(31), reverse(22), and normal(15).
on @*:TEXT:*:#:{
if ($nick isop #) return
var %count = $count($1-,$chr(3))
inc %count $count($1-,$chr(2))
inc %count $count($1-,$chr(22))
inc %count $count($1-,$chr(31))
inc %count $count($1-,$chr(15))
;The above 5 lines count the number of control codes
if (%count >= 10) {
ban -u60 # $nick 11
kick # $nick Please don't use soo much colour ( $+ %count $+ )
}
}
The Excessively Long Text Kicker is also an easy script. All it needs is an if statement and $len
on @*:TEXT:*:#:{
if ($nick isop #) return
if ($len($strip($1-)) >= 180) {
;Note that I $strip the text before I use $len, so it won't count any
; control codes like colour or bold etc...
ban -u60 # $nick 11
kick # $nick You talk too much! Keep it below 180 letters
}
}
The Channel Advert Kicker can get quite complex or it can get quite simple - it all depends on how accurate your want its detection to be. Here is a simple on TEXT detection:
on @*:TEXT:*:#:{
if ($nick isop #) return
var %s = $strip($1-)
if (*www* iswm %s) || (*http:* iswm %s) || (*ftp:* iswm %s) || ($chr(35) isin $1-) {
ban -u60 # $nick 11
kick # $nick Please do not advertise ( $+ $ifmatch detected)
}
}
However the main problem with the above code concerns the $chr(35) (which is a #). If someone says your channelname in your channel then they will still be kicked. How to avoid this? You could use tokens ($wildtok) and loops to go through every word and see if it an advert... It should go somewhere along the lines of:
on @*:TEXT:*:#:{
if ($nick isop #) return
var %i = 0
while (%i < $0) {
inc %i
var %word = $strip($gettok($1-,%i,32))
if (*www* iswm %word) || (*http:* iswm %word) || (*ftp:* iswm %word) || ($chr(35) isin %word) {
if (%word != $chan) {
;This if-statement makes sure the word isn't actually your channel name
;If you wanted to you could add specific URL's and other chanenl names
;to ignore as well. Help Channels would likely use this sort of thing
ban -u60 # $nick 11
kick # $nick Please do not advertise ( $+ $ifmatch detected)
}
}
}
}
Also just because I've used the on TEXT event dosen't mean that you can't use other events, like detect an advertisement in a part or quit message by using the on PART and on QUIT events.
The Bad IdentD Kicker is another fairly easy piece of code... all you really need is an on JOIN event that has an IF statment checking if a bad identd is in the persons $address:
on @*:JOIN:#:{
if (*!*FUCK*@* iswm $fulladdress) || (*!*SHIT*@* iswm $fulladdress) || (*!*DICK*@* iswm $fulladdress) {
ban -u60 # $nick 11
kick # $nick Bad Identd!
}
}
The Revolving Door Kicker (Banner actually) is a medium difficulty kicker. You need use the on PART event. The logic behind this kicker is that you keep a count of how many times the person parts in x seconds. It's very similar to a flood protection script. If the person exceeds x parts in x seconds then we ban him:
on @*:PART:#:{
if ($nick isop #) return
set -u60 %rd. [ $+ [ $chan ] $+ . $+ [ $nick ] ] $calc( %rd. [ $+ [ $chan ] $+ . $+ [ $nick ] ] + 1 )
; This just sets a variable: %rd.#channel.nick to keep track of the nbr of joins in 60secs
if ( %rd. [ $+ [ $chan ] $+ . $+ [ $nick ] ] >= 4) {
; This if statement checks to see if the variable is >= 4, the
; then the person is doing a revolving door
ban -u60 # $nick 11
}
}
The Guest Nickname Kicker requires two events to be effective. One is the on JOIN event to kick when a guest joins the channel, the other is the on NICK event to kick when the person changes to a guest nick.
on @*:JOIN:#:{
if (guest????? iswm $nick) {
ban -u60 # $nick 11
kick # $nick Guest nicks are not allowed, /nick <New Nickname>
}
}
on *:NICK:{
if (guest????? iswm $newnick) {
var %i = 0
while (%i < $comchan($newnick,0)) {
;This while loop goes through every channel both you and the nick are on
inc %i
if ($me isop $comchan($newnick,%i)) {
;You can only kick if you are an op =)
ban -u60 $comchan($newnick,%i) $newnick 11
kick $comchan($newnick,%i) $newnick Guest nicks are not allowed, /nick <New Nickname>
}
}
}
}
The Offensive Nickname Kicker works in a VERY similar fashion. Instead of if (guest????? iswm $nick)
use:
if (shit isin $nick) || (fuck isin $nick) || (dick isin $nick) etc...
And for the on NICK event just use the line above except change $nick
to $newnick
. It is that simple.
The Repeat Kicker can be done in several ways. The general idea is to somehow store what a person last said and then the next time they speak see if what they said was what they said last time. I like to use variables to record this information however some people may not like to do that because it _could_ take up a lot of space. Anyway, here is some code:
on @*:TEXT:*:#:{
if ($nick isop #) return
var %text = $hash($strip($1-),32)
; %text is what the person said, however it is stripped of colour, and $hash()'d to save filesize
var %old.text = %rp. [ $+ [ $chan ] $+ . $+ [ $nick ] ]
var %old.text = $deltok(%old.text,1,46)
if (%rp. [ $+ [ $chan ] $+ . $+ [ $nick ] ] == $null) || (%old.text != %text) {
; If the person didn't repeat or the person spoke for the
; first time then we need to create this variable:
set -u60 %rp. [ $+ [ $chan ] $+ . $+ [ $nick ] ] 1. $+ %text
; Note how its set to unset in 60 seconds - so the person has to repeat within 60seconds
; The variables format is: %rp.#channel.nickname N.%text
; N being the number of times the %text was said
return
}
var %temp = %rp. [ $+ [ $chan ] $+ . $+ [ $nick ] ]
var %count = $gettok(%temp,1,46)
; %count is set to how many times the person had previously repeated (N)
inc %count
;Then it is increased by one because the person repeated again
set -u60 %rp. [ $+ [ $chan ] $+ . $+ [ $nick ] ] %count $+ . $+ %text
if (%count >= 3) {
;If the number of repeats exceeds 2 then the person is kicked
ban -u60 # $nick 11
kick # $nick You repeated %count times!
}
}
Note: There is another repeat kicker in the FAQ that uses slightly different code. In particular, it uses $hash() inside the variable name to cut down on the amount of [ ] brackets required.
The Flood Kicker can be difficult, however it can be done in only one line if you pushed it. Like I said before, the Flood Kicker is very similar to the Revoling Door kicker...
on @*:TEXT:*:#: {
if ($nick isop #) return
set -u3 %fld. [ $+ [ $chan ] $+ . $+ [ $nick ] ] $calc( %fld. [ $+ [ $chan ] $+ . $+ [ $nick ] ] + 1)
; The variable, %fld.#chan.nick counts the number of lines the person speaks
; It is automatically unset 3 seconds after the last time the person talked
; So I guess in _theory_ if you managed to do 1 line per 3 secs for 3 lines you could be kicked
if (%fld. [ $+ [ $chan ] $+ . $+ [ $nick ] ] >= 5) {
;The above if statement checks if that variable is greater to or equals 5
ban -u60 # $nick 11
kick # $nick Please do not flood
}
}
This code is fairly generic and can be used for a variety of events... you could use it to kick mass mode changers, mass kickers, mass banners, mass topic changes, etc... Just remember that in different events $chan & $nick may not always be the correct identifiers to use! You can also use it to kick Nick Flooders, however that becomes slightly more difficult as you don't have a $chan so I'll write some code to show you how it can be done. The main idea is to not use $nick $newnick in your counting variable, instead use an $address
on *:NICK: {
set -u60 %fld. [ $+ [ $address ] ] $calc( %fld. [ $+ [ $address ] ] + 1)
if (%fld. [ $+ [ $address ] ] >= 5) {
var %i = 0
while (%i < $comchan($newnick,0)) {
inc %i
ban -u60 $comchan($newnick,%i) $newnick 2
kick $comchan($newnick,%i) $newnick Stop the nick flooding mate!
}
}
}
CTCP Floods can be detected by using a similar piece of code. It's useful to remember that most CTCP attacks are not channel CTCPs but private CTCP's, so when kicking we will need to use $comchan().
ctcp *:*:*: {
set -u60 %ctcp. [ $+ [ $site ] ] $calc( %ctcp. [ $+ [ $site ] ] + 1)
if (%ctcp. [ $+ [ $address ] ] >= 5) {
.ignore -tu60 $site
var %i = 0
while (%i < $comchan($nick,0)) {
inc %i
if ($nick !isop $comchan($nick,%i) {
ban -u60 $comchan($nick,%i) 2
kick $comchan($newnick,%i) $nick Stop the CTCP flooding please!
}
}
}
}
The Clone Kicker script probably requires the most scripting out of the main protection type scripts. The basic concepts to a clone kicker is that when someone joins a channel, they have a host (Which we can get using $wildsite or $gettok($wildsite,2,64)) which is unique every computer (Unless the person is connecting through a Proxy, BNC or some other service sharing device). mIRC has the $ialchan identifier. What this lets us do is count the number of people in a chanenl with the same host:
on @*:JOIN:#:{
if ($ial == $false) .ial on
if ($chan(#).ial == $false) { who # | return }
var %total = $ialchan($wildsite,#,0)
; %total is set to the number of people on the channel using $wildsite
if (%total > 1) {
;If there is MORE than one person using $wildsite then we start kicking...
ban -u60 # $nick 2
;Notice how I put the ban command here and used bantype 2 ($wildsite).
;Why? So I only have to place one ban yet it bans every clone.
var %i = 0
while (%i < %total) {
;This while loop loops through all the nicks using $wildsite
inc %i
var %nick = $ialchan($wildsite,#,%i).nick
; %nick is set to the current nickname
var %all.nicks = $addtok(%all.nicks,%nick,32)
; %all.nicks is set to every nick from $wildsite
if (%nick !isop #) {
kick # %nick Clone flood detected from $wildsite ( $+ %total users)
}
}
echo 4 -a *** Clone flood detected from $wildsite $+ : %all.nicks
}
}
For this script to work properly you need your IAL (Internal Address List) on /ial on
and you need to /who #channel
to every channel you join. You can automate the /who part:
on me:*:JOIN:#: .timer 1 3 check.ial $chan
alias -l check.ial if ($chan($1).ial == $false) who $1
This sets a timer that wil in 3 seconds check to see if the IAL for the channel is full. Why 3 seconds? Well there could be chance that another script also tried to update the IAL when you joined - there is no reason to do it twice.
If you wanted to improve the performance of the clone kicker and you are only going to use the script on a DALnet server, DALnet supports kicking upto 4 nicks in one kick line /kick # nick1,nick2,nick3,nick4 message
. So if you knew how to use tokens you could still create %all.nicks but at the end use tokens to get the first 4 nicks, then the next 4 nicks etc... The end result is that you send less commands to the IRC server which reduces the load and the chance you will be disconnected for flooding.
You may also want to put in an exception if there are too many clones (Because you know you will be disconnected), e.g. if (%total > 30) set %total 30
that way you will only kick 30 of the clones even if there is more. Hey - its better than kicking no clones and its better than being disconnected for flooding the server!
The Bad Channel script requires some knowledge of RAW as well as $comchan and loops, and some swear word checking skills as well. The basics behind this kicker is as follows:
- When user joins your channel, whois them (on JOIN)
- check the whois reply to see what channels they are in (raw event, numeric 319)
- kick the user (loops and $comchan)
The raw numeric 319 contains the list of channels a person is in (it is returned when you /whois the person
on !*:JOIN:#your_channel: whois $nick
raw 319:*: {
; $3- contains the channels the person is in (that are not +s or +p)
; $2 is the persons nickname, $nick is NOT the persons nickname in a RAW event
; this is where many people much up, thinking you can use $nick and $chan in a RAW event
if (xxx isin $3-) || (porn isin $3-) || (warez isin $3-) || (sex isin $3-) {
; The above if statements check if xxx,porn,warez or sex is in ANY of the channels the person is in
var %t = $comchan($2,0)
; The above variable sets how many channels the user is in that you are also in
while (%t) {
; The above while statement will loop through every channel you and the person ($2) are in
; and kick him from each of those channels. If you want you can remove the while statement
; and INSTEAD of $comchan($2,%t) use an actual channel, e.g. #HelpDesk
if ($me isop $comchan($2,%t)) {
; It would be a bit foolish if we tried to kick without ops, wouldn't it? *Grins*
ban -u60 $comchan($2,%t) $2 11
kick $comchan($2,%t) $2 I don't like your channels!
}
dec %t
}
}
}
Reaction Levels are used when you, say, want to warn someone when they first break a rule, then ban them for a minute for the second offence, then finally kick ban them - or something similar. How can you do this? There are a few methods however the easiest (for this www page anyway) is to use variables to count the number of offences...
So how would we use variables?
- We would create a unique variable for each user
- Each time the person offends, we increase the value of the variable by one
- We use an if statement to tell how many offences the user has done, and thus warn, ban or kick etc...
For the below examples we will use variables formatted in the following way:
%rl.HOST-ADDRESS
The HOST-ADDRESS value that we will use is masktype 2 (*!*@host). This is done so that if they change nicknames, we can still keep track of them. So thats why we use %rl. [ $+ [ $address($nick,2) ] ] in the below examples.
To increase the variable and keep its expire time at an hour, we need to use a set line as follows:
set -u3600 %rl. [ $+ [ $address($nick,2) ] ] $calc( %rl. [ $+ [ $address($nick,2) ] ] + 1)
I gues you could also use /inc instead of /set if you really wanted to.
So in general, our code that uses reaction levels would look like:
set -u3600 %rl. [ $+ [ $address($nick,2) ] ] $calc( %rl. [ $+ [ $address($nick,2) ] ] + 1)
if (%rl. [ $+ [ $address($nick,2) ] ] == 1) {
; insert code to use when user offends for the first (1st) time
}
if (%rl. [ $+ [ $address($nick,2) ] ] == 2) {
; insert code to use when user offends for the second (2nd) time
}
if (%rl. [ $+ [ $address($nick,2) ] ] == 3) {
; insert code to use when user offends for the third (3rd) time
}
if (%rl. [ $+ [ $address($nick,2) ] ] >= 4) {
; insert code to use when user offends for the fourth (4th) time and over
}
So where you would normally put the ban & kick lines, you could instead use:
set -u3600 %rl. [ $+ [ $address($nick,2) ] ] $calc( %rl. [ $+ [ $address($nick,2) ] ] + 1)
;the -u3600 makes the variable unset after 1hr without being used
if (%rl. [ $+ [ $address($nick,2) ] ] == 1) .notice $nick Please don't! - this is your first warning!
if (%rl. [ $+ [ $address($nick,2) ] ] == 2) ban -u60 # $nick 11
if (%rl. [ $+ [ $address($nick,2) ] ] >= 3) {
ban # $nick 11
kick # $nick You were warned. You are not allowed to do whatever you just did!
}
You would also need to clear your %rl.* variable list every time you connect to a server or start up mIRC:
on *:START: unset %rl.*
on *:CONNECT: unset %rl.*
So lets say I wanted to use this method on a channel advert kicker, I could do the following:
on @*:TEXT:*:#:{
if ($nick isop #) return
var %s = $strip($1-)
if (*www* iswm %s) || (*http:* iswm %s) || (*ftp:* iswm %s) || ($chr(35) isin $1-) {
set -u3600 %rl. [ $+ [ $address($nick,2) ] ] $calc( %rl. [ $+ [ $address($nick,2) ] ] + 1)
;the -u3600 makes the variable unset after 1hr without being used
if (%rl. [ $+ [ $address($nick,2) ] ] == 1) .notice $nick No Ads! - this is your first warning!
if (%rl. [ $+ [ $address($nick,2) ] ] == 2) ban -u60 # $nick 11
if (%rl. [ $+ [ $address($nick,2) ] ] >= 3) {
ban # $nick 11
kick # $nick You were warned. You are not allowed advertise in here ( $+ $ifmatch detected)
}
}
}
Of course if you did this to every single protection event it would take up a fair bit of disk space. You could instead create an alias:
alias rl {
;btw rl stands for Reaction Level not Rocket Launcher =)
;format: /rl <channel> <nickname>
set -u3600 %rl. [ $+ [ $address($2,2) ] ] $calc( %rl. [ $+ [ $address($2,2) ] ] + 1)
;the -u3600 makes the variable unset after 1hr without being used
if (%rl. [ $+ [ $address($2,2) ] ] == 1) .notice $2 Please don't! - this is your first warning!
if (%rl. [ $+ [ $address($2,2) ] ] == 2) ban -u60 $1 $2 11
if (%rl. [ $+ [ $address($2,2) ] ] >= 3) {
ban $1 $2 11
kick $1 $2 You were warned. You have broken the rules one too many times!
}
}
on @*:TEXT:*:#:{
if ($nick isop #) return
var %s = $strip($1-)
if (*www* iswm %s) || (*http:* iswm %s) || (*ftp:* iswm %s) || ($chr(35) isin $1-) {
rl # $nick
}
}
If you wanted to you could make this alias really complex: /rl <channel> <fulladdress> <offence type>. The alias could keep a seperate count for each different type of offence (e.g. flood, repeat, colour, etc...). So for instance you could make it kick flooders on the first offence, however only warn people with too much colour on their first offence.
viruskiller