Top

Channel Checker 1.07


mIRC Code
+ 1 likes
Please Register to submit score.
Bookmark and Share
Average Score  8.0 (of 1 scores)
Date Added  Aug 08, 2009
Last Updated  Aug 16, 2009
Tags  bad  channels  filtering  protection  queue  track  whois 

Introduction

Gives detailed info about the people on your channels. Keeps users showing bad channels or bad words anywhere in their /whois results from your channels.
Provides dialogs and custom windows, everything is configurable, is multinetwork, will not make mIRC hang and will not cause flood disconnects. Has a versatile Rule sets-system (named TrackUsers) that are matched towards the whois results, exclude/include/wildcard/regex. BadChans is used to store considered-bad channels, BadStrings is for words inside channelnames, GoodChans serves as exclude for BadStrings.

//edits 2009/08/08
- fixed TrackUsers syntax error missing )
- replaced 'CHANNEL' with the correct 'PCHANNEL' on 2 places (alias cck.TrackUsers.Check)
- whois output now says which TrackUsers RuleSet was matched.

//version 1.07 (2009/08/10)
- TrackUsers has now an extra available action (a member of a RuleSet) named 'DO/LIST'. When added to a RuleSet, it will make the script doing /list #channel for every channel the nick is on, so you can see the amount users on the channel and the topic.
This has an unsolvable issue though, since mIRC creates/activates a 'channels list' window for every /list, it looks like a flashlight. To lower the annoyancy-level abit, I close the window upon every /list raw, you're able to type fairly well in another window then.

//edit 2009/08/16: a manual /names #channel doesn't trigger a channel scan anymore, only after you join.

Grab the Code

;===================================================================================================
; STARTUP / SHUTDOWN
;===================================================================================================

on *:START: {
  var %dir = $scriptdir
  var %h = cck.HDisk | hmake %h 30
  hadd %h Config $+(%dir,cck.Config.txt)
  hadd %h CheckChans $+(%dir,cck.CheckChans.txt)
  hadd %h BadChans $+(%dir,cck.BadChans.txt)
  hadd %h BadStrings $+(%dir,cck.BadStrings.txt)
  hadd %h GoodChans $+(%dir,cck.GoodChans.txt)
  hadd %h TrackUsers $+(%dir,cck.TrackUsers.txt)
  var %p = %dir $+ TrackData\ | hadd %h TrackPath %p | if (!$isdir(%p)) { mkdir $qt(%p) }

  hmake cck.H 30
  cck.Config.Load
  cck.CheckChans.Load
  cck.BadChans.Load
  cck.BadStrings.Load
  cck.GoodChans.Load
  cck.TrackUsers.Load

  var %i = 1 | while (%i < 10) { hmake cck.HQ $+ %i 30 | inc %i }
  hmake cck.HRaw 30
  window -h @cck.raw
  cck.CheckChans.Sweep CONTINUE
  cck.CheckChans.Timer
  .disable #cck.*
  .raw on
  cck.queue.process ON SILENT
  echo -bflmrst Loaded $hget(cck.HConfig,VersionShort)
}

on *:UNLOAD: {
  var %s = $hget(cck.HConfig,VersionShort)
  hfree -w cck.H*
  .timercck.* OFF
  close -@ @ChanCheck.*
  close -@ @cck.*
  if ($dialog(CCK.ASK)) { dialog -k CCK.ASK }
  if ($dialog(CCK.MAIN)) { dialog -k CCK.MAIN }
  echo -bflmrst Unloaded %s
}

;===================================================================================================
; GENERAL FUNCTION BASE
;===================================================================================================

; +++ UI OUTPUT FUNCTIONS
alias cck.echo+ {
  var %w = @ChanCheck.Control | if (!$window(%w)) { window -den %w -1 -1 $hget(cck.HConfig,WinXY) }
  echo -t %w (3CCK) $1-
}
alias cck.echo/ {
  var %w = @ChanCheck.Control | if (!$window(%w)) { window -den %w -1 -1 $hget(cck.HConfig,WinXY) }
  echo -t %w (7CCK) $1-
}
alias cck.echo- {
  var %w = @ChanCheck.Control | if (!$window(%w)) { window -den %w -1 -1 $hget(cck.HConfig,WinXY) }
  echo -t %w (4CCK) $1-
}
alias cck.echoLog {
  var %w = @ChanCheck.Log | if (!$window(%w)) { window -den %w -1 -1 $hget(cck.HConfig,WinXY) }
  echo -ti4 %w $1-
}

; +++ FUNCTION / TIMESTAMP IN CONFIGURED FORMAT (!spaces not allowed!)
alias cck.time { return $asctime($hget(cck.HConfig,TimeFormat)) }

; +++ FUNCTION / UPDATE TIMER INTERVAL
; IN32 $1 = timer name (wildcards allowed) $2 = new interval
alias cck.timerupd {
  var %label = $1, %new = $2, %total = $timer(0), %i = 1
  while (%i <= %total) {
    var %n = $timer(%i) | if (%label !iswm %n) { inc %i | continue }
    if ($timer(%n).reps == 1) && (%new > $timer(%n).delay) { var %passed = $calc($timer(%n).delay - $timer(%n).secs) | dec %new %passed }
    var %sw = -c
    if ($timer(%n).type == offline) { var %sw = %sw $+ o }
    if ($timer(%n).anysc) { var %sw = %sw $+ i }
    if ($timer(%n).mmt) { var %sw = %sw $+ h }
    if ($timer(%n).pause) { var %sw = %sw $+ p }
    .timer $+ %n %sw $timer(%n).reps %new $timer(%n).com
    inc %i 
  }
}

; +++ FUNCTION / CHECK IF NICK SHOULD BE EXCLUDED FROM CHECKS
; IN32 $1 = network $2 = nick
; $3 = channel that should be skipped in the onchan checks (reason: IAL update after script finishes)
; OUT32: $result = 1 (exclude) or 0 (no exclude)
alias cck.exclude {
  var %cid = $cck.net2cid($1) | if (!%cid) { return 0 } | if ($cid != %cid) { scid %cid }
  if ($istok($replace($hget(cck.HConfig,ExcludeNicks),<ME>,$me),$2,32)) { return 1 }
  var %s
  if ($hget(cck.HConfig,Exclude@) == ON) { %s = %s $+ @ }
  if ($hget(cck.HConfig,Exclude%) == ON) { %s = %s $+ % }
  if ($hget(cck.HConfig,Exclude+) == ON) { %s = %s $+ + }
  if (%s) && (!$cck.onchan(%s,$1,$2,$3)) { return 1 }
  return 0
}

; +++ FUNCTION KEYS / ACT
; IN $1 = WARN or KICK or BAN
alias cck.key.act {
  cck.diaASK.getlatest $network | if (!$result) { cck.echo- SYSTEM: Unable to act - no data for $network found in ASK dialog. | return }
  var %act = $1 | tokenize 32 $result
  cck.netwarnkickban %act $3 $4 $5 $iif($2 == T,$5-,$cck.actmsg(%act,$3,$4,$6-))
}

; +++ FUNCTION KEYS / RETURN UI MESSAGE
alias cck.key.info {
  var %h = cck.HConfig
  return $+([,$hget(%h,keySweep),) Sweep] $+([,$hget(%h,keyWarn),) Warn] $+([,$hget(%h,keyKick),) Kick] $+([,$hget(%h,keyBan),) Ban]
}

; +++ FUNCTION KEYS / SET THROUGH POPUP MENU
alias cck.key.config {
  var %i = 0
  :nkey
  inc %i | if (%i > 4) { return }
  var %act = $gettok(Sweep@Warn@Kick@Ban,%i,64)
  if ($?="Enter a Function key combination for: %act " == $null) goto nkey
  cck.Config Key $+ %act $upper($!) | if ($result == REFUSED) { dec %count }
  goto nkey
}

; +++ FUNCTION / PLAY OR SET BAD USER - SOUND AT ASK-MOMENT
; <SET (optional)>
alias cck.BadSound {
  if ($1 != SET) {
    var %f = $hget(cck.HConfig,BadSound)
    if ($isfile(%f)) { splay $qt(%f) }
    ; | elseif (%f) { cck.echo- SYSTEM: Cannot play bad sound. File %f is missing. }
    return 
  }
  cck.Config BadSound $sfile($+($scriptdir,*.wav),Select the sound file to play upon detection/ask or cancel to clear.)
}

; +++ FUNCTION / POPUP DIALOG TO CONFIRM IMPORTANT ACTION
alias cck.confirm { if ($input($1-,yvw) == $yes) { return 1 } | return 0 }

; +++ FUNCTION / CONVERT A WINDOW TOKEN POSITION COLUMN TO A TOKEN STRING
; convert list column to token string
; $1 = @win $2 = ascii token separator input window $3 = token position of wanted column
; $4 = ascii token separator output string $5 = max chars output string (optional)
alias cck.col2tok {
  var %i = 1, %t = $line($1,0), %out
  while (%i <= %t) {
    var %out1 = $+(%out,$chr($4),$gettok($line($1,%i),$3,$2))
    if ($5) && ($len(%out1) > $5) { return %out $+ </cck> }
    var %out = %out1 | inc %i
  }
  return %out
}

; +++ FUNCTION / LIMIT A TOKEN STRING TO X CHARS BY DELETING FROM END.
; Input: $1 = separator ascii code $2 = bytes limit $3- = token string
alias cck.limittokenstring { var %s = $3- | while ($len(%s) > $2) { var %s = $deltok(%s,-1,$1) } | return %s }

; +++ FUNCTION / CREATE DATA STRUCTURES WITH RANDOM NAME
alias -l rhash { var %i = 1, %h = cck.Htmp | while ($hget(%h $+ %i)) { inc %i } | hmake %h $+ %i | return %h $+ %i }
alias -l rwin { var %i = 1, %w = @cck.tmp | while ($window(%w $+ %i)) { inc %i } | window -h %w $+ %i | return %w $+ %i }

; +++ FUNCTION / CONVERT SCRIPTS FUNCTION RETURN VALUES TO BOOLEAN
alias -l ok { if ($istok(1 DONE,$1,32)) { return 1 } | return 0 }

; +++ FUNCTION / VARIOUS
alias -l box { return $+([,$1-,],) }
alias -l rs { return $eval($str($ $+ rand(a,z) $ $+ + $ $+ + $chr(32),$1),2) }
alias -l s2c { return $replace($1-,$chr(32),$chr(44)) }

;===================================================================================================
; CONFIG MAIN
;===================================================================================================

; +++ CONFIG / LOAD
alias cck.Config.Load {
  var %h = cck.HConfig | if ($hget(%h)) { hfree %h } | hmake %h 30
  var %f = $hget(cck.HDisk,Config) | if ($isfile(%f)) { hload %h $qt(%f) }
  var %c = cck.config.load1 $1

  hadd %h VersionShort CQChanCheck 1.07
  hadd %h VersionLong CQChanCheck 1.07 by CatQuasar

  %c SweepInterval 600
  %c DeadGap 500
  %c UsePing ON
  %c NoPINGGap 3000
  %c Timeout 15
  %c MonitorQueue ON
  %c NoAbort@PART-KICK OFF
  %c DetailedWhois OFF
  %c TimeFormat yyyymmdd-HHnnss
  %c BadSound $+($scriptdir,pervert.wav)

  %c ActBadChans ASK
  %c ActBadStrings ASK
  %c WarnMsg Your presence on <BADCHANS> is not allowed in <MYCHANS>. 
  %c KickMsg Illegal channels.
  %c TrackUsers.DefaultAct ASK
  %c TrackUsers.DefaultKickMsg Bad user.
  %c TrackUsers.DefaultDo/List OFF

  %c WarnMsg.MaxDataLength 200
  %c KickMsg.MaxDataLength 200
  %c AskMsg.MaxDataLength 200

  %c KeySweep SF12 | alias / $+ SF12 cck.whoischan 1 $!network $!chan KEY
  %c KeyWarn SF9 | alias / $+ SF9 cck.key.act WARN
  %c KeyKick SF10 | alias / $+ SF10 cck.key.act KICK
  %c KeyBan SF11 | alias / $+ SF11 cck.key.act BAN
  %c Exclude@ ON
  %c Exclude% ON
  %c Exclude+ ON
  %c ExcludeNicks X W <ME>

  %c DiaASK.CloseWhenEmpty OFF
  %c DiaASK.MaxDataLength 200
  %c WinLog.ShowNonMatches ON
  %c WinLog.MaxDataLength 800
  %c WinXY 600 300

  hsave %h $qt(%f)
}
alias -l cck.config.load1 { if ($hfind(cck.HConfig,$1,1) == $null) { hadd cck.HConfig $1 $2- } }
alias cck.Config.Default {
  if ($cck.confirm(This is undoable - Sure?)) { .remove $qt($hget(cck.HDisk,Config)) | cck.Config.Load | cck.diaMAIN.load Config }
}

; +++ CONFIG / CHANGE
; IN32 $1 = parameter $2 = value
; OUT32 $result = NOCHANGE or INVALID or DONE
alias cck.Config {
  var %par = $1, %val = $2-
  var %h = cck.HConfig, %val0 = $hget(%h,%par)
  if (%val0 === %val) { cck.echo/ CONFIG:12 %par already " $+ %val $+ ". | return NOCHANGE }

  ; refuse when invalid
  if (Key* iswm %par) {
    if (!$findtok(S F C,$left(%val,1),32)) {
      cck.echo- CONFIG:12 %par Invalid value %val $+ . Valid Function Keys are for ex. SF5 SF6 SF7 SF8
      return INVALID
    }
  }
  elseif ($istok(SweepInterval DeadGap NoPINGGAP,%par,32)) {
    if (%val !isnum 1-) || (. isin %val) {
      cck.echo- CONFIG:12 %par Invalid value %val $+ . Should be an integer type-number > 0
      return INVALID
    }
  }
  elseif (%par == TimeFormat) {
    if ($chr(32) isin $asctime(%val)) {
      cck.echo- CONFIG:12 %par Invalid value %val $+ . Spaces are not allowed in the generated time value.
      return INVALID
    }
  }

  hadd %h %par %val | hsave %h $qt($hget(cck.HDisk,Config))

  ; update systems
  goto %par

  :KeySweep | alias / $+ %val cck.whoischan 1 $!network $chr(35) KEY | goto done
  :KeyWarn | alias / $+ %val cck.key.act WARN | goto done
  :KeyKick | alias / $+ %val cck.key.act KICK | goto done
  :KeyBan | alias / $+ %val cck.key.act BAN | goto done
  :SweepInterval | cck.timerupd cck.Sweep %val | goto done
  :DeadGap | :NoPINGGap | if ($timer(cck.DeadGap).delay == %val0) { cck.timerupd cck.DeadGap %val } | goto done
  :Timeout | cck.timerupd cck.Timeout %val | goto done

  :%par
  :done
  cck.diaMAIN.upd Config %par %val
  cck.diaASK.upd %par %val
  cck.echo+ CONFIG:12 %par changed from $qt(%val0) to $qt(%val) $+ . | return DONE
}

;===================================================================================================
; CONFIG / CHECK CHANNELS
;===================================================================================================

; +++ CHECK CHANNELS / LOAD
; These are the channels to protect against users on bad channels.
; <network,channel> = <F.USERJOIN> <F.OWNJOIN> <F.TIMER> <F.CONTINUE>
alias cck.CheckChans.Load {
  var %h = cck.HCheckChans | if ($hget(%h)) { hfree %h } | hmake %h 30
  var %f = $hget(cck.HDisk,CheckChans) | if ($isfile(%f)) { hload %h $qt(%f) }
  var %c = cck.checkchans.load1
  ; *****

  ; %c UnderNet,#mp3passion ON OFF OFF OFF
  ; %c UnderNet,#mp3download ON OFF OFF OFF
  ; %c UnderNet,#mp3_collective ON OFF OFF OFF

  ; *****
  hsave %h $qt(%f)
}
alias -l cck.checkchans.load1 { if ($hfind(cck.HCheckChans,$1,1) == $null) { hadd cck.HCheckChans $1 $2- } }

; +++ CHECK CHANNELS / ADD
; IN32 $1 = network or * (= any) $2 = channel $3 = USERJOIN $4 = OWNJOIN $5 = TIMER $6 = CONTINUE
; OUT32 $1 = EXIST or DONE
alias cck.CheckChans.Add {
  var %nc = $1 $+ , $+ $2
  if ($hfind(cck.HCheckChans,%nc,1)) { cck.echo/ CHECKCHANS:12 %nc Already exists. | return EXIST }
  hadd cck.HCheckChans %nc $3 $4 $5 $6 | hsave cck.HCheckChans $qt($hget(cck.HDisk,CheckChans))
  cck.CheckChans.Timer | cck.echo+ CHECKCHANS:12 %nc Added. $&
    $box(USERJOIN $3) $box(OWNJOIN $4) $box(TIMER $5) $box(CONTINUE $6)
  cck.diaMAIN.upd CheckChans ADD %nc | return DONE
}

; +++ CHECK CHANNELS / REMOVE
; IN32 $1 = network or * $2 = channel
; OUT32 $1 = NOTFOUND or DONE
alias cck.CheckChans.Rem {
  var %nc = $1 $+ , $+ $2
  if (!$hfind(cck.HCheckChans,%nc,1)) { cck.echo- CHECKCHANS:12 %nc Not found. | return NOTFOUND }
  hdel cck.HCheckChans %nc | hsave cck.HCheckChans $qt($hget(cck.HDisk,CheckChans))
  cck.CheckChans.Timer | cck.echo+ CHECKCHANS: 12 %nc Removed.
  cck.diaMAIN.upd CheckChans REM %nc | return DONE
}

; +++ CHECK CHANNELS / CHANGE PARAMETER
; IN32 $1 = network $2 = channel $3 = parameter (USERJOIN or OWNJOIN or TIMER or CONTINUE) $4 = ON or OFF or command spy
; OUT32 $1 = NOTFOUND or NOCHANGE or DONE
alias cck.CheckChans.Change {
  var %nc = $1 $+ , $+ $2, %rec = $hget(cck.HCheckChans,%nc), %p
  if (%rec == $null) { cck.echo- CHECKCHANS:12 %nc Not found. | return NOTFOUND }
  goto $3
  :USERJOIN | %p = 1 | goto check
  :OWNJOIN | %p = 2 | goto check
  :TIMER | %p = 3 | goto check
  :CONTINUE | %p = 4 | goto check
  :check
  var %val0 = $gettok(%rec,%p,32)
  if ($4 === %val0) { cck.echo/ CHECKCHANS:12 %nc $+  $3 already $4 $+ . | return NOCHANGE }
  hadd cck.HCheckChans %nc $puttok(%rec,$4,%p,32) | hsave cck.HCheckChans $qt($hget(cck.HDisk,CheckChans))
  if ($3 == TIMER) { cck.CheckChans.Timer }
  elseif ($3 == CONTINUE) { cck.CheckChans.Sweep CONTINUE }
  cck.echo+ CHECKCHANS:12 %nc $+  $3 now $4 $+ .
  cck.diaMAIN.upd CheckChans REP %nc | return DONE
}

; +++ CHECK CHANNELS / CHECK IF GIVEN CHANNEL IS IN THE LIST 
; IN32 $1 = network $2 = channel $3 = optional parameter (USERJOIN or OWNJOIN or TIMER or CONTINUE or ANY)
; OUT32 case no parameter: 1 = channel present 0 = not present
; OUT32 case parameter: 1 = parameter ON 0 = OFF
alias cck.CheckChans.Check {
  var %nc = $1 $+ , $+ $2, %rec = $hget(cck.HCheckChans,%nc) | if (%rec == $null) { return 0 } | if (!$3) { return 1 }
  var %event = $3 | tokenize 32 %rec
  goto %event
  :USERJOIN | if ($1 == ON) { return 1 } | return 0
  :OWNJOIN | if ($2 == ON) { return 1 } | return 0
  :TIMER | if ($3 == ON) { return 1 } | return 0
  :CONTINUE | if ($4 == ON) { return 1 } | return 0
  :ANY | if ($1 == ON) || ($2 == ON) || ($3 == ON) || ($4 == ON) { return 1 } | return 0
}

; +++ CHECK CHANNELS / SET DEFAULT
alias cck.CheckChans.Default {
  if ($cck.confirm(This is undoable - Sure?)) {
    .remove $qt($hget(cck.HDisk,CheckChans)) | cck.CheckChans.Load | cck.diaMAIN.load CheckChans
  }
}

; +++ CHECK CHANNELS / GET PARAMETER
; IN32 $1 = network  $2 = channel  $3 = parameter
; OUT32 $1 = NOTFOUND or value of parameter
alias cck.CheckChans.Get {
  var %nc = $1 $+ , $+ $2, %rec = $hget(cck.HCheckChans,%nc) | if (%rec == $null) { return NOTFOUND }
  var %par = $3 | tokenize 32 %rec | goto %par
  :USERJOIN | return $1
  :OWNJOIN | return $2
  :TIMER | return $3
  :CONTINUE | return $4
}

; +++ CHECK CHANNELS / START-STOP TIMER ACCORDING TO CONFIGURATION
alias cck.CheckChans.Timer {
  var %i = 1
  while ($hget(cck.HCheckChans,%i).data) {
    if ($gettok($v1,3,32) == ON) {
      if (!$timer(cck.Sweep)) { .timercck.Sweep -oi 0 $hget(cck.HConfig,SweepInterval) cck.CheckChans.Sweep TIMER }
      return
    }
    inc %i
  }
  .timercck.Sweep OFF
}

; +++ CHECK CHANNELS / PERFORM GLOBAL SWEEP
; IN $1 = CONTINUE or TIMER (optional - if not specified, all channels) 
alias cck.CheckChans.Sweep {
  if ($1 == CONTINUE) && (!$cck.queue.empty(WHOIS,-)) { return }
  var %p1 = $1, %i = 1
  while ($hget(cck.HCheckChans,%i).item) {
    var %nc = $v1 | tokenize 32 $hget(cck.HCheckChans,%nc)
    if (%p1 == TIMER) { if ($3 != ON) { inc %i | continue } }
    elseif (%p1 == CONTINUE) { if ($4 != ON) { inc %i | continue } }
    tokenize 44 %nc | if ($cck.net2cid($1)) { scid $v1 | if ($me ison $2) { cck.whoischan 1 $1 $2 %p1 } }
    inc %i
  }
}

;===================================================================================================
; CONFIG / BAD CHANNELS
;===================================================================================================

; +++ BAD CHANNELS / LOAD
alias cck.BadChans.Load {
  var %h = cck.HBadChans | if ($hget(%h)) { hfree %h } | hmake %h 30
  var %f = $hget(cck.HDisk,BadChans) | if ($isfile(%f)) { hload %h $qt(%f) }
  var %c = cck.badchans.load1
  ; *****

  ; %c *,#nazi
  ; %c *,#100%highschoolsexpics
  ; %c *,#11-19flirts
  ; %c *,#familysex
  ; %c *,#horsesex
  ; %c *,#femsubmissionsex
  ; %c *,#baby&toddlerlove
  ; %c *,#0!FuckMywife
  ; %c *,#jack-off-str8
  ; %c *,#masturbation
  ; %c *,#phonesex
  ; %c *,#100%pk.highschoolsexpics
  ; %c *,#femhumiliationsex
  ; %c *,#cybersex
  ; %c *,#analsex
  ; %c *,#smalltitpics

  ; *****
  hsave %h $qt(%f)
}
alias -l cck.badchans.load1 { if ($hfind(cck.HBadChans,$1,1,W) == $null) { hadd cck.HBadChans $1 0 Never } }

; +++ BAD CHANNELS / ADD
; IN32 $1 = network or * $2 = channel
; OUT32 $1 = EXIST or DONE
alias cck.BadChans.Add {
  var %nc = $1 $+ , $+ $2
  if ($hfind(cck.HBadChans,%nc,1,W)) { cck.echo/ BADCHANS:12 %nc Already exists (wildcard match). | return EXIST }
  hadd cck.HBadChans %nc 0 Never | hsave cck.HBadChans $qt($hget(cck.HDisk,BadChans))
  cck.diaMAIN.upd BadChans ADD %nc
  cck.echo+ BADCHANS:12 %nc Added. | return DONE
}

; +++ BAD CHANNELS / REMOVE
; IN32 $1 = network or * $2 = channel
; OUT32 $1 = NOTFOUND or DONE
alias cck.BadChans.Rem {
  var %nc = $1 $+ , $+ $2
  if (!$hfind(cck.HBadChans,%nc,1)) { cck.echo- BADCHANS:12 %nc Not Found. | return NOTFOUND }
  hdel cck.HBadChans %nc | hsave cck.HBadChans $qt($hget(cck.HDisk,BadChans))
  cck.diaMAIN.upd BadChans REM %nc
  cck.echo+ BADCHANS:12 %nc Removed. | return DONE
}

; +++ BAD CHANNELS / CHECK IF GIVEN CHANNEL IS A MATCH
; IN32 $1 = network $2 = channel
; OUT32 $1 = 1 (match) or 0 (no match)
alias cck.BadChans.Check {
  var %nc = $1 $+ , $+ $2 | if ($hfind(cck.HBadChans,%nc,1,W) == $null) { return 0 }
  var %nc = $v1 | tokenize 32 $hget(cck.HBadChans,%nc) | hadd cck.HBadChans %nc $calc($1 + 1) $ctime
  hsave cck.HBadChans $qt($hget(cck.HDisk,BadChans))
  cck.diaMAIN.upd BadChans REP %nc  
  return 1
}

; +++ BAD CHANNELS / SET DEFAULT
alias cck.BadChans.Default {
  if ($cck.confirm(This is undoable - Sure?)) {
    .remove $qt($hget(cck.HDisk,BadChans)) | cck.BadChans.Load | cck.diaMAIN.load BadChans
  }
}

;===================================================================================================
; CONFIG / BAD STRINGS
;===================================================================================================

; +++ BAD STRINGS / LOAD
alias cck.BadStrings.Load {
  var %h = cck.HBadStrings | if ($hget(%h)) { hfree %h } | hmake %h 30
  var %f = $hget(cck.HDisk,BadStrings) | if ($isfile(%f)) { hload %h $qt(%f) }
  var %c = cck.badstrings.load1
  ; *****

  ; %c kid
  ; %c young
  ; %c teen
  ; %c boy
  ; %c girl
  ; %c daughter
  ; %c dad
  ; %c mom
  ; %c incest
  ; %c horse
  ; %c dog
  ; %c animal

  ; *****
  hsave %h $qt(%f)
}
alias -l cck.badstrings.load1 { if ($hfind(cck.HBadStrings,$1,1) == $null) { hadd cck.HBadStrings $1 0 Never } }

; +++ BAD STRINGS / ADD
; IN32 $1 = string
; OUT32 $1 = EXIST or DONE
alias cck.BadStrings.Add {
  if ($hfind(cck.HBadStrings,$1,1)) { cck.echo/ BADSTRINGS:12 $1 Already exists. | return EXIST }
  hadd cck.HBadStrings $1 0 Never | hsave cck.HBadStrings $qt($hget(cck.HDisk,BadStrings))
  cck.diaMAIN.upd BadStrings ADD $1
  cck.echo+ BADSTRINGS:12 $1 Added. | return DONE
}

; +++ BAD STRINGS / REMOVE
; IN32 $1 = string
; OUT32 $1 = NOTFOUND or DONE
alias cck.BadStrings.Rem {
  if (!$hfind(cck.HBadStrings,$1,1)) { cck.echo- BADSTRINGS:12 $1 Not found. | return NOTFOUND }
  hdel cck.HBadStrings $1 | hsave cck.HBadStrings $qt($hget(cck.HDisk,BadStrings))
  cck.diaMAIN.upd BadStrings REM $1
  cck.echo+ BADSTRINGS:12 $1 Removed. | return DONE
}

; +++ BAD STRINGS / CHECK IF GIVEN STRING IS MATCH
; IN32 $1 = string
; OUT32 $1 = 1 (match) or 0 (no match)
alias cck.BadStrings.Check {
  var %c = $1, %h = cck.HBadStrings, %i = 1
  while ($hget(%h,%i).item) {
    var %s = $v1
    if (%s isin %c) {
      tokenize 32 $hget(%h,%s)
      hadd %h %s $calc($1 + 1) $ctime | hsave %h $qt($hget(cck.HDisk,BadStrings))
      cck.diaMAIN.upd BadStrings REP %s
      return 1
    }
    inc %i
  }
  return 0
}

; +++ BAD STRINGS / SET DEFAULTS
alias cck.BadStrings.Default {
  if ($cck.confirm(This is undoable - Sure?)) {
    .remove $qt($hget(cck.HDisk,BadStrings)) | cck.BadStrings.Load | cck.diaMAIN.load BadStrings
  }
}

;===================================================================================================
; CONFIG / GOOD CHANNELS
;===================================================================================================

; +++ GOOD CHANNELS / LOAD
alias cck.GoodChans.Load {
  var %h = cck.HGoodChans | if ($hget(%h)) { hfree %h } | hmake %h 30
  var %f = $hget(cck.HDisk,GoodChans) | if ($isfile(%f)) { hload %h $qt(%f) }
  var %c = cck.goodchans.load1
  ; *****

  %c UnderNet,#horsepower
  %c UnderNet,#dogtraining
  %c UnderNet,#paulyoung
  %c UnderNet,#daddy'splace


  ; *****
  hsave %h $qt(%f)
}
alias -l cck.goodchans.load1 { if ($hfind(cck.HGoodChans,$1,1,W) == $null) { hadd cck.HGoodChans $1 0 Never } }

; +++ GOOD CHANNELS / ADD
; IN32 $1 = network or * $2 = channel
; OUT32: $1 = EXIST or DONE
alias cck.GoodChans.Add {
  var %nc = $1 $+ , $+ $2
  if ($hfind(cck.HGoodChans,%nc,1,W)) { cck.echo/ GOODCHANS:12 %nc Already exists (wildcard match). | return EXIST }
  hadd cck.HGoodChans %nc 0 Never | hsave cck.HGoodChans $qt($hget(cck.HDisk,GoodChans))
  cck.diaMAIN.upd GoodChans ADD %nc
  cck.echo+ GOODCHANS:12 %nc Added. | return DONE
}

; +++ GOOD CHANNELS / REMOVE
; IN32 $1 = network or * $2 = channel
; OUT32 $1 = NOTFOUND or DONE
alias cck.GoodChans.Rem {
  var %nc = $1 $+ , $+ $2
  if (!$hfind(cck.HGoodChans,%nc,1)) { cck.echo/ GOODCHANS:12 %nc Not found. | return NOTFOUND }
  hdel cck.HGoodChans %nc | hsave cck.HGoodChans $qt($hget(cck.HDisk,GoodChans))
  cck.diaMAIN.upd GoodChans REM %nc
  cck.echo+ GOODCHANS:12 %nc Removed. | return DONE
}

; +++ GOOD CHANNELS / CHECK IF GIVEN CHANNEL IS MATCH
; IN32 $1 = channel
; OUT32 $1 = 1 (match) or 0 (no match)
alias cck.GoodChans.Check {
  var %nc = $1 $+ , $+ $2 | if ($hfind(cck.HGoodChans,%nc,1,W) == $null) { return 0 }
  var %nc = $v1 | tokenize 32 $hget(cck.HGoodChans,%nc)
  hadd cck.HGoodChans %nc $calc($1 + 1) $ctime | hsave cck.HGoodChans $qt($hget(cck.HDisk,GoodChans))
  cck.diaMAIN.upd GoodChans REP %nc | return 1
}

; GOOD CHANNELS / SET DEFAULT
alias cck.GoodChans.Default {
  .remove $qt($hget(cck.HDisk,GoodChans)) | cck.GoodChans.Load | cck.diaMAIN.load GoodChans
}

;===================================================================================================
; CONFIG / TRACK USERS
;===================================================================================================

; +++ TRACK USERS / LOAD
alias cck.TrackUsers.Load {
  var %h = cck.HTrackUsers | if ($hget(%h)) { hfree %h } | hmake %h 30
  var %f = $hget(cck.HDisk,TrackUsers) | if ($isfile(%f)) { hload %h $qt(%f) }
  var %c = cck.trackusers.load1
  ; *****

  ; Example: next rule set has tag 'Default1' and will match ppl that:
  ; - Are operator on a channel named '#screwyou' (INCLUDE,WILDCARD)
  ; - AND have 'fuck' inside their real name (INCLUDE,WILDCARD)
  ; - AND are NOT authed (EXclude,Wildcard * - matches any authname)
  ; %c Default1,IN1W,PCHANNEL @#screwyou
  ; %c Default1,IN1W,REALNAME *fuck*
  ; %c Default1,EX1W,AUTHNAME *

  ; - When detected perform ACT: ASK or KICK or BAN
  ; %c Default1,ACT ASK
  ; %c Default1,KICKMSG Look like a lamer? Treated like a lamer.

  ; Example: next rule has tag 'Default2' and will match ppl that:
  ; - Have their real name starting with 'you suck' (INCLUDE,WILDCARD)
  ; - AND NOT on the irc networks  UnderNet and QuakeNet
  ; %c Default2,IN1W,REALNAME you suck*
  ; %c Default2,EX1W,NETWORK UnderNet
  ; %c Default2,EX2W,NETWORK QuakeNet

  ; *****
  hsave %h $qt(%f)
}
alias -l cck.trackusers.load1 { if ($hfind(cck.HTrackUsers,$1,1) == $null) { hadd cck.HTrackUsers $1- } }

; the ^ prefix in some parameters indicate that they need SpecialWhois to retrieve.
; others may only be showed in own whois or may require IRC operator privileges
alias cck.TrackUsers.Pars {
  return NETWORK NICK USER HOST MASK REALHOST USERIP REALNAME REGNICK AUTHNAME PCHANNEL $&
    AWAY ^LOGON ^IDLE SERVHOST SERVINFO BOT SERVICE HELPOP IRCOP SSL FILTERING ACT KICKMSG
}

; +++ TRACK USERS / ADD RULE
; IN32 $1 = tag $2 = INW or INR or EXW or EXR $3 = parameter $4- = value
; OUT32: $1 = INVALID or EXIST or DONE
alias cck.TrackUsers.AddRule {
  var %4 = $chr(44)
  if ($1 !isalnum) || (!$1) || ($len($1) > 8) {
    cck.echo- TRACKUSERS: $+(04,$1,12,%4,$2,%4,$3,) Tag allows a-zA-Z0-9 characters only, $&
      cannot be only zeroes, and should be max 8 characters.
    return INVALID
  }
  var %h = cck.HTrackUsers, %hi, %i = 1
  while ($hfind(%h,$+($1,%4,$left($2,2),%i,$right($2,1),%4,$3),1)) {
    %hi = $v1
    if ($hget(%h,%hi) === $4-) { cck.echo/ TRACKUSERS:12 %hi Rule already exists with value $qt($4-) $+ . | return EXIST }
    inc %i
  }
  var %hi = $+($1,%4,$left($2,2),%i,$right($2,1),%4,$3)
  hadd %h %hi $4- | hsave %h $qt($hget(cck.HDisk,TrackUsers))
  cck.diaMAIN.upd TrackUsers ADD %hi
  cck.echo+ TRACKUSERS:12 %hi Rule added (value $qt($4-) $+ )
  if ($istok(^LOGON ^IDLE,$3,32)) && ($hget(cck.HConfig,SpecialWhois) == OFF) {
    cck.echo/ TRACKUSERS:12 %hi SpecialWhois needs to be ON for ^LOGON and ^IDLE. )
  }
  return DONE
}

; +++ TRACK USERS / REMOVE RULE
; IN32 $1 = tag $2 = IN<N>W or IN<N>R or EX<N>W or EX<N>R $3 = parameter
; OUT32 $1 = NOTFOUND or DONE
alias cck.TrackUsers.RemRule {
  var %hi = $+($1,$chr(44),$2,$chr(44),$3), %h = cck.HTrackUsers
  if (!$hfind(%h,%hi,1)) { cck.echo- TRACKUSERS:12 %hi Rule not found. | return NOTFOUND }
  var %hv = $hget(%h,%hi) | hdel %h %hi | hsave %h $qt($hget(cck.HDisk,TrackUsers))
  cck.diaMAIN.upd TrackUsers REM %hi
  cck.echo+ TRACKUSERS:12 %hi Rule removed (value $qt(%hv) $+ ).
  return DONE
}

; +++ TRACK USERS / ADD-CHANGE CONFIG
; IN32 $1 = tag $2 = ACT or KICKMSG or  DO/LIST
; case ACT: $3- = ASK or KICK or BAN
; case KICKMSG: $3- = kick message
; OUT32: $1 = INVALID or EXIST or DONE
alias cck.TrackUsers.AddConfig {
  var %4 = $chr(44)
  if ($1 !isalnum) || (!$1) || ($len($1) > 8) {
    cck.echo- TRACKUSERS: $+(04,$1,,%4,12,$2,) Tag allows a-zA-Z0-9 characters only, $&
      cannot be only zeroes, and should be max 8 characters.
    return INVALID
  }
  if ($2 == ACT) {
    if (!$istok(ASK KICK BAN,$3-,32)) {
      cck.echo- TRACKUSERS: $+(12,$1,%4,ACT) Config has invalid value04 $3- $+ . Should be ASK, KICK or BAN.
      return INVALID
    }
  }
  var %hi = $+($1,%4,$2), %h = cck.HTrackUsers
  if ($hfind(%h,%hi,1)) {
    if ($2 == DO/LIST) { cck.echo/ TRACKUSERS:12 %hi Config already set. | return EXIST }
    if ($hget(%h,$v1) === $3-) { cck.echo/ TRACKUSERS:12 %hi Config already set to $qt($3-) $+ . | return EXIST }
    hdel %h %hi | cck.diaMAIN.upd TrackUsers REM %hi
  }
  hadd %h %hi $3- | cck.diaMAIN.upd TrackUsers ADD %hi
  hsave %h $qt($hget(cck.HDisk,TrackUsers))
  cck.echo+ TRACKUSERS:12 %hi $+  $iif($2 ==  DO/LIST,Config set.,Config set to $qt($3-) $+ .) | return DONE
}

; +++ TRACK USERS / REMOVE CONFIG
; IN32 $1 = tag $2 = ACT or KICKMSG or  DO/LIST
; OUT32 $1 = NOTFOUND or DONE
alias cck.TrackUsers.RemConfig {
  var %hi = $+($1,$chr(44),$2), %h = cck.HTrackUsers
  if (!$hfind(%h,%hi,1)) { cck.echo- TRACKUSERS:12 %hi Not found. | return NOTFOUND }
  hdel %h %hi | hsave %h $qt($hget(cck.HDisk,TrackUsers))
  cck.diaMAIN.upd TrackUsers REM %hi
  cck.echo+ TRACKUSERS:12 %hi Removed. | return DONE
}

; +++ TRACK USERS / CHECK
; IN32 $1 = hash name, layout parameter=value $2 = @window name, layout <prefixedchannel>
; OUT $1 = 0 (no match) or $1 = ASK or KICK or BAN $2 = first matching tag $3 = DO/LIST or NO/LIST $4- = kickmsg
alias cck.TrackUsers.Check {
  var %hin = $1, %win = $2, %h = cck.HTrackUsers, %hr = $rhash, %hi, %i1 = 1, %i2, %tag, %s, %4 = $chr(44)
  while ($hget(%h,%i1).item) { hadd %hr $gettok($v1,1,44) 0 | inc %i1 }

  %i1 = 1
  :nextTAG
  %tag = $hget(%hr,%i1).item | if (%tag == $null) { goto wipeIN }
  %i2 = 1

  ; wipe tags with Exclude matches
  :nextEX
  %hi = $hfind(%h,$+(%tag,%4,EX*,%4,*),%i2,w) | if (%hi == $null) { %i2 = 1 | goto nextIN }
  tokenize 44 %hi | %s = $right($2,1)
  if ($3 == PCHANNEL) { if ($fline(%win,$hget(%h,%hi),1,$iif(%s == R,2,w))) { hdel %hr %tag | goto nextTAG } }
  elseif (%s == W) { if ($hget(%h,%hi) iswm $hget(%hin,$3)) { hdel %hr %tag | goto nextTAG } }
  elseif (%s == R) { if ($regex($hget(%hin,$3),$hget(%h,%hi))) { hdel %hr %tag | goto nextTAG } }
  inc %i2 | goto nextEX

  ; count Include matches per tag
  :nextIN
  %hi = $hfind(%h,$+(%tag,%4,IN*,%4,*),%i2,w) | if (%hi == $null) { inc %i1 | goto nextTAG }
  tokenize 44 %hi | %s = $right($2,1)
  if ($3 == PCHANNEL) { if ($fline(%win,$hget(%h,%hi),1,$iif(%s == R,2,w))) { hinc %hr %tag } }  
  elseif (%s == W) { if ($hget(%h,%hi) iswm $hget(%hin,$3)) { hinc %hr %tag } }
  elseif (%s == R) { if ($regex($hget(%hin,$3),$hget(%h,%hi))) { hinc %hr %tag } }
  inc %i2 | goto nextIN

  ; wipe tags with no full Includes match
  :wipeIN
  %i1 = 1
  while ($hget(%hr,%i1).item) {
    %hi = $v1
    if ($hfind(%h,$+(%hi,%4,IN*,%4,*),0,w) > $hget(%hr,%hi)) { hdel %hr %hi } | else { inc %i1 }
  }
  %hi = $hget(%hr,1).item | if (%hi == $null) { hfree %hr | return 0 }
  %tag = $gettok(%hi,1,44) | %i = 2 | %s = %tag
  while ($hget(%hr,%i).item) { %s = %s $gettok($v1,1,44) | inc %i }
  hfree %hr
  if ($numtok(%s,32) > 1) { cck.echo/ TRACKUSERS: Detected overlapping RuleSets (12 $+ %s $+ )  }
  %s = $iif($hget(cck.HConfig,TrackUsers.DefaultDo/List) == ON,DO/LIST,NO/LIST)
  return $iif($hget(%h,$+(%tag,%4,ACT)),$v1,$hget(cck.HConfig,TrackUsers.DefaultAct)) %tag $&
    $iif($hfind(%h,$+(%tag,%4,DO/LIST),1),DO/LIST,%s) $&
    $iif($hget(%h,$+(%tag,%4,KICKMSG)),$v1,$hget(cck.HConfig,TrackUsers.DefaultKickMsg))
}
alias cck.TrackUsers.Default { .remove $qt($hget(cck.HDisk,TrackUsers)) | cck.TrackUsers.Load }

;===================================================================================================
; HELP
;===================================================================================================

; +++ HELP WINDOW
alias cck.help {
  var %w = @ChanCheck.Help | if ($window(%w)) { window -a %w | return }
  window -da %w -1 -1 $hget(cck.HConfig,WinXY) | var %c = aline -pi4 %w
  %c $+(,$hget(cck.HConfig,VersionLong),)
  %c -
  %c INTRODUCTION
  %c This script deals with that are on considered-bad channels or have considered-bad text in their IRC data.
  %c -
  %c WORKING PRINCIPLE
  %c To check users, the script sends WHOIS commands to the irc server.
  %c This can be started in 5 ways:
  %c - Manually: using the scripts interface.
  %c - At User Join: the moment the user joins your detection channels.
  %c - At Own Join: at the moment you join, script checks all users.
  %c - By Timer: every X secs, script will check everybody on the detection channels.
  %c - Continue: same as Own Join, but the end of the all-check immediately starts a next all-check
  %c Upon detection, 4 actions are available: ASK, WARN, KICK, BAN (the latter also kicks).
  %c In case ASK, the script will wait to take action and allow you to decide which of the 3 actions it has to perform.
  %c This can be selected in a dialog and by 3 configurable Function Keys (ex. SF10 = Shift-F10)
  %c -
  %c The channelnames of the users are matched in two ways, either exact, either the presence of a word in it.
  %c The exact way is named '04BadChans', the word presence way is named '07BadStrings'.
  %c Above actions are separately configurable for these two ways.
  %c So you can for ex. automatically BAN users in case 04BadChans match, and ASK in case 07BadStrings match.
  %c This approach allows you to add suspected words, giving you the chance to find out if the channel is really bad, before taking actions.
  %c If this BadStrings matching channel should not be considered bad, it can be added to the '03GoodChans' list.
  %c So this '03GoodChans' list acts as exclude list for the '07BadStrings' list.
  %c -
  %c The WARN and KICK message can be configured, and supports the tags <BADCHANS> and <MYCHANS>.
  %c These tags will be replaced by the script with the found bad channel list and the channel(s) the check happened.
  %c You can exclude channel Operators/Halfops/Voices and a list of nicks (mainly for networks' services) from checking.
  %c Keep in mind that it's still possible that the script checks these users since there is a delay between their join and mode.
  %c Also, if you check a channel that isn't in CheckChans, nobody except the list of nicks will be excluded and also no action will take place.
  %c -
  %c 04Track Users
  %c The script can also detect and act on specific users (or 'kind' of users) with dedicated Rule Sets, that are applied on the WHOIS results.
  %c These rules consist of Include Rules (all have to match) and Exclude Rules (none should match).
  %c So, besides bad channels, the script can also do bad <anything in WHOIS> checks.
  %c The Rules Sets are grouped by the <tag> field. There are:
  %c *** 2 types rules IN(clude)/EX(clude).
  %c *** 2 types matchstring W(ildcard)/R(egex).
  %c *** 2 Configuration items ACT/KICKMSG
  %c -
  %c INCLUDE: <tag>,<IN<N>W|IN<N>R>,<parameter> = <value of par>
  %c INW = INclude rule and Wildcard match text
  %c INR = INclude rule and Regular expression match text
  %c -
  %c EXCLUDE: <tag>,<EX<N>W|EX<N>R>,<parameter> = <value of par>
  %c EXW = EXclude rule and Wildcard match text
  %c EXR = EXclude rule and Regular expression match text
  %c A certain <tag> can have Multiple Include and Exclude Rules for the same parameter (but different value).
  %c The script will auto-insert a sequential number in the Rule Types field.
  %c A Rule Set has some other 'member' entries available:
  %c - ACT: <tag>,ACT = ASK|KICK|BAN
  %c - KICKMSG: <tag>,KICKMSG = text
  %c - DO/LIST: <tag>,DO/LIST = n/a (do a /list on all the channels returned for a matching user)
  %c NOTES
  %c To make mIRC not suffer hangs, a DeadGap function is provided, which will insert a delay (in milliseconds) between user checks. 
  %c The bigger you make this delay, the longer it will take to complete the check, so people on bad channels might be able to stay in for a while.
  %c But the lower you make it, the less mIRC is able to cope with other things, causing a higher risk of having periods of unresponsivity.
  %c If setting UsePING is ON then the script will send a PING after commands that are not answered by the IRC server.
  %c These commands are MSG NOTICE DESCRIBE CTCP and channel-user MODE's b, e or i (so an address mask as parameter)
  %c This allows eventdriven queue processing just like commands that do get IRC server responses.
  %c Drawback of this method is that it doubles the amount commands to the IRC server and thus cause more lag.
  %c To allow to disable UsePING without introducing a FloodDisconnect-risk , an alternate delay setting for DeadGap timer is provided.
  %c When UsePING is OFF, this second delay, named NoPINGGAP (also milliseconds), will be used for the mentioned commands.
  %c A setting of at least 2000 is recommended. If you see the script cause FloodDisconnect, increase it.
  %c I kept this setting in milliseconds to still allow a low setting for privileged IRC server users that have higher or no limits.
  %c Another setting Timeout in seconds avoids queue stalls/user intervention needed, when something in the eventdrive goes wrong.
}

;===================================================================================================
; MENU POPUPS
;===================================================================================================

menu status,channel,query,menubar,status,@ChanCheck.* {
  .$hget(cck.HConfig,VersionShort)
  .#
  ..Sweep: { cck.whoischan 1 $$network $$chan MENU }
  ..-
  ..Add: { cck.CheckChans.Add $$network $$chan OFF OFF OFF OFF }
  ..UserJoin ( $+ $cck.CheckChans.Get($network,$chan,USERJOIN) $+ )
  ...ON: { cck.CheckChans.Change $$network $$chan USERJOIN ON }
  ...OFF: { cck.CheckChans.Change $$network $$chan USERJOIN OFF }
  ..OwnJoin ( $+ $cck.CheckChans.Get($network,$chan,OWNJOIN) $+ )
  ...ON: { cck.CheckChans.Change $$network $$chan OWNJOIN ON }
  ...OFF: { cck.CheckChans.Change $$network $$chan OWNJOIN OFF }
  ..Timer ( $+ $cck.CheckChans.Get($network,$chan,TIMER) $+ )
  ...ON: { cck.CheckChans.Change $$network $$chan TIMER ON }
  ...OFF: { cck.CheckChans.Change $$network $$chan TIMER OFF }
  ..Continue ( $+ $cck.CheckChans.Get($network,$chan,CONTINUE) $+ )
  ...ON: { cck.CheckChans.Change $$network $$chan CONTINUE ON }
  ...OFF: { cck.CheckChans.Change $$network $$chan CONTINUE OFF }
  ..-
  ..Remove: { cck.CheckChans.Rem $$network $$chan }
  .-
  .Dialog MAIN: { cck.diaMAIN }
  .Dialog ASK: { cck.diaASK } 
  .-
  .Set Function Keys: { cck.key.config }
  .Queue ( $+ $cck.queue.get#(*,*) $+ )
  ..Process ( $+ $cck.queue.process $+ )
  ...ON: { cck.queue.process ON }
  ...OFF: { cck.queue.process OFF }
  ..Recover Stall: { cck.queue.recover }
  ..Flush: { cck.queue.remnet * }
  .( Help ): { cck.help }
}
menu nicklist {
  .$hget(cck.HConfig,VersionShort)
  ..Sweep Selected: {
    var %i = 1
    while ($snick(#,%i)) { var %n = $v1 | cck.queue.add 3 $network WHOIS %n - $iif($address(%n,0),$gettok($v1,2-,33),-) MENU | inc %i }
  }
}

;===================================================================================================
; DIALOG FUNCTION BASE
;===================================================================================================

; +++ DIALOG FUNCTIONS
alias cck.dia.RepSW { if ($did($1,$2,$3).state) { return -ock } | return -ok }
alias cck.dia.CheckEdit { var %i = 2 | while (%i <= $0) { if ($did($1,$ [ $+ [ %i ] ]) == $null) { return 0 } | inc %i } | return 1 }
alias cck.dia.CheckCombo { var %i = 2 | while (%i <= $0) { if ($did($1,$ [ $+ [ %i ] ],0) == $null) { return 0 } | inc %i } | return 1 }
alias cck.dia.OOsw { if ($1 == ON) { return -c } | return -u }
alias cck.dia.swOO {
  var %i = 2, %out
  while ($ [ $+ [ %i ] ] != $null) { %out = %out $iif($did($1,$v1).state,ON,OFF) | inc %i }
  return %out
}

; Select all listbox lines matching token on given position
; Input: $1 = dialog $2 = listid $3 = token position $4 = ascii token separator $5 = P or S or PS (wildcard * prefix/suffix-optional)
alias cck.dia.ListSelTokSame {
  var %d = $1, %id = $2, %pos = $3, %sep = $4, %ps = $5
  var %totalsel = $did(%d,%id,0).sel, %i = 1, %w = $rwin
  while (%i <= %totalsel) { var %l = $did(%d,%id,%i).sel | aline %w $gettok($did(%d,%id,%l),%pos,%sep) | inc %i }
  var %total = $did(%d,%id).lines, %i1 = 1
  while (%i1 <= %totalsel) {
    var %rec = $line(%w,%i1) | if (%ps == P) { var %rec = $+(*,%rec) } | elseif (%ps == S) { var %rec = $+(%rec,*) } | elseif (%ps == PS) { var %rec = $+(*,%rec,*) }
    var %i2 = 1 | while (%i2 <= %total) { if (%rec iswm $gettok($did(%d,%id,%i2),%pos,%sep)) { did -ck %d %id %i2 } | inc %i2 }
    inc %i1
  }
  window -c %w
}
; Select all listbox lines with given token on given position
; IN32 $1 = dialog $2 = listid $3 = token position $4 = ascii token separator $5 = token value
; OUT $1 = amount selected
alias cck.dia.ListSelTokVal {
  var %i = 1
  while ($did($1,$2,%i) != $null) { if ($gettok($v1,$3,$4) == $5) { did -ck $1 $2 %i } | inc %i }
}

;===================================================================================================
; DIALOG MAIN
;===================================================================================================

; +++ DIALOG MAIN / TABLE
dialog CCK.MAIN {
  title ""
  size -1 -1 274 165
  option dbu
  tab "Check Channels / Configuration1", 1, 0 -2 273 166
  list 11, 2 12 123 128, tab 1 sort size extsel hsbar vsbar
  check "UserJoin", 13, 3 141 26 10, tab 1 push
  edit "", 12, 2 152 123 10, tab 1 autohs
  check "OwnJoin", 14, 30 141 25 10, tab 1 push
  check "By Timer", 15, 56 141 25 10, tab 1 push
  button "Add", 17, 126 152 16 11, tab 1
  button "Rem", 16, 126 128 16 11, tab 1
  text "ActBadStrings", 18, 170 13 39 8, tab 1
  text "ActBadChannels", 20, 128 13 41 8, tab 1
  button "Set", 29, 258 152 13 11, tab 1
  edit "", 22, 126 41 146 31, tab 1 multi autovs vsbar
  text "WARN Message (tags: <BADCHANS> <MYCHANS>)", 23, 127 32 133 8, tab 1
  text "KICK Message (tags: <BADCHANS> <MYCHANS>)", 24, 127 73 133 8, tab 1
  edit "", 25, 126 82 146 31, tab 1 multi autovs vsbar
  combo 21, 127 20 41 42, tab 1 drop
  combo 19, 169 20 40 42, tab 1 drop
  edit "", 75, 239 142 17 10, tab 1 limit 3
  edit "", 74, 239 132 17 10, tab 1 limit 3
  edit "", 72, 239 122 17 10, tab 1 limit 4
  text "MaxDataLength", 73, 219 114 39 8, tab 1
  text "ASK", 76, 219 124 19 8, tab 1
  text "WARN", 77, 219 134 19 8, tab 1
  text "KICK", 78, 219 144 19 8, tab 1
  edit "", 80, 239 152 17 10, tab 1 limit 4
  text "LOG", 79, 219 154 19 8, tab 1
  check "Continue", 81, 82 141 26 10, tab 1 push
  button "", 91, 260 14 7 7, hide tab 1 ok
  button "Join", 106, 126 116 14 11, tab 1
  button "Part", 107, 141 116 14 11, tab 1
  tab "Bad Channels / Configuration2", 2
  list 34, 2 12 123 128, tab 2 sort size extsel hsbar vsbar
  edit "", 35, 2 152 123 10, tab 2 autohs
  button "Add", 36, 90 141 16 11, tab 2
  button "Rem", 37, 108 141 16 11, tab 2
  text "BAD CHANNELS", 47, 3 142 44 8, tab 2
  box "QUEUE + TIME SETTINGS", 46, 127 13 144 65, tab 2
  button "Set", 68, 258 152 13 11, tab 2
  edit "", 62, 181 65 87 10, tab 2
  text "Sweep Interval", 63, 133 23 38 8, tab 2
  text "Dead Gap Duration", 64, 133 34 47 8, tab 2
  edit "", 60, 181 21 20 10, tab 2
  edit "", 61, 181 32 25 10, tab 2
  text "sec.", 65, 207 23 12 8, tab 2
  text "msec.", 66, 207 34 15 8, tab 2
  text "TimeFormat", 67, 133 67 46 8, tab 2
  check "ShowNonMatches", 71, 221 109 49 10, tab 2 push
  check "@ Operators", 27, 131 126 35 10, tab 2 push
  box "Exclude from being checked", 30, 127 118 144 32, tab 2
  text "Nicks", 32, 251 130 16 7, tab 2
  check "+ Voices", 28, 197 126 26 10, tab 2 push
  check "% HalfOps", 26, 167 126 29 10, tab 2 push
  edit "", 31, 130 137 138 10, tab 2
  check "Don't abort check at PART/KICK", 33, 127 152 84 10, tab 2 push
  check "DetailedWHOIS", 70, 212 152 42 10, tab 2 push
  check "Monitor Queue", 96, 228 19 40 10, tab 2 push
  button "Flush", 97, 252 30 16 10, tab 2
  check "Process", 98, 228 30 23 10, tab 2 push
  check "UsePING", 99, 133 43 27 10, tab 2 push
  edit "", 100, 217 43 25 10, tab 2
  text "msec.", 101, 243 45 15 8, tab 2
  text "NoPING Gap Duration", 102, 162 45 55 8, tab 2
  text "Overall Timeout", 105, 133 56 39 8, tab 2
  edit "", 103, 173 54 20 10, tab 2
  text "sec.", 104, 194 56 15 8, tab 2
  tab "Bad Strings / Good Channels", 3
  list 38, 2 12 123 128, tab 3 sort size extsel hsbar vsbar
  edit "", 39, 2 152 123 10, tab 3
  button "Add", 40, 90 141 16 11, tab 3
  button "Rem", 41, 108 141 16 11, tab 3
  list 42, 148 12 123 128, tab 3 sort size extsel hsbar vsbar
  edit "", 45, 148 152 123 10, tab 3
  button "Add", 43, 236 141 16 11, tab 3
  button "Rem", 44, 254 141 16 11, tab 3
  text "BAD STRINGS", 48, 3 142 38 8, tab 3
  text "GOOD CHANNELS", 49, 149 142 48 8, tab 3
  text "SWEEP", 50, 127 45 21 8, tab 3
  button "Set", 59, 130 115 13 11, tab 3
  text "BAN", 53, 130 105 13 8, tab 3
  edit "", 58, 127 95 19 10, tab 3 limit 4
  text "KICK", 52, 130 85 14 8, tab 3
  edit "", 57, 127 75 19 10, tab 3 limit 4
  text "WARN", 51, 128 65 18 8, tab 3
  edit "", 56, 127 55 19 10, tab 3 limit 4
  edit "", 55, 127 35 19 10, tab 3 limit 4
  text "F-KEYS", 54, 127 26 21 8, tab 3
  button "Sound", 69, 127 13 19 11, tab 3
  tab "Track Users", 4
  list 5, 2 12 245 107, tab 4 sort size extsel hsbar vsbar
  button "Add", 7, 248 120 14 11, tab 4
  button "Remove", 8, 248 107 24 11, tab 4
  edit "", 10, 32 141 215 10, tab 4
  button "SetDefault", 85, 30 152 29 11, tab 4
  combo 87, 78 120 47 92, tab 4 vsbar drop
  combo 88, 3 141 28 36, tab 4 drop
  button "Sel Tag", 90, 248 95 24 11, tab 4
  edit "", 92, 2 120 50 10, tab 4 limit 8
  text "Wildcard Text / Regex", 95, 191 130 56 8, tab 4
  text "Tag of Rules Set", 93, 9 130 42 8, tab 4
  text "KICK Message", 94, 181 151 37 8, tab 4
  button "SetDefault", 82, 235 152 29 11, tab 4
  edit "", 83, 125 120 122 10, tab 4 autohs
  text "Parameter", 84, 91 131 26 8, tab 4
  text "ACT", 86, 3 152 11 8, tab 4
  combo 6, 53 120 24 43, tab 4 drop
  text "Type", 9, 55 131 15 8, tab 4
  button "Add", 89, 220 152 14 11, tab 4
  check "DO/LIST", 108, 91 152 26 10, tab 4 push
  button "SetDefault", 109, 133 152 29 11, tab 4
  button "Add", 111, 15 152 14 11, tab 4
  button "Add", 110, 118 152 14 11, tab 4
}
alias cck.diaMAIN { var %d = CCK.MAIN | if (!$dialog(%d)) { dialog -mdv %d %d } | else { dialog -ev %d %d } }

; +++ DIALOG MAIN / LOAD CONFIG
; $1 = system or <ALL>
alias cck.diaMAIN.load {
  var %d = CCK.MAIN, %i | if (!$dialog(%d)) { return }
  if ($1 != <ALL>) { goto $1 }

  :Config
  var %h = cck.HConfig
  cck.diaMAIN.title
  didtok %d 21,19 32 ASK WARN KICK BAN
  didtok %d 88 32 ASK KICK BAN
  didtok %d 87 32 $cck.TrackUsers.Pars
  didtok %d 6 32 INW EXW INR EXR
  did -c %d 21 $didwm(%d,21,$hget(%h,ActBadChans))
  did -c %d 19 $didwm(%d,19,$hget(%h,ActBadStrings))
  did -c %d 88 $didwm(%d,88,$hget(%h,TrackUsers.DefaultAct))
  did $cck.dia.OOsw($hget(%h,TrackUsers.DefaultDo/List)) %d 108
  did $cck.dia.OOsw($hget(%h,UsePING)) %d 99
  did $cck.dia.OOsw($hget(%h,WinLog.ShowNonMatches)) %d 71
  did $cck.dia.OOsw($hget(%h,Exclude@)) %d 27
  did $cck.dia.OOsw($hget(%h,Exclude%)) %d 26
  did $cck.dia.OOsw($hget(%h,Exclude+)) %d 28
  did $cck.dia.OOsw($hget(%h,NoAbort@PART-KICK)) %d 33
  did $cck.dia.OOsw($hget(%h,DetailedWhois)) %d 70
  did $cck.dia.OOsw($hget(%h,MonitorQueue)) %d 96

  did -ra %d 22 $hget(%h,WarnMsg)
  did -ra %d 25 $hget(%h,KickMsg)
  did -ra %d 10 $hget(%h,TrackUsers.DefaultKickMsg)
  did -o %d 72 1 $hget(%h,AskMsg.MaxDataLength)
  did -o %d 74 1 $hget(%h,WarnMsg.MaxDataLength)
  did -o %d 75 1 $hget(%h,KickMsg.MaxDataLength)
  did -o %d 80 1 $hget(%h,WinLog.MaxDataLength)
  did -o %d 60 1 $hget(%h,SweepInterval)
  did -o %d 61 1 $hget(%h,DeadGap)
  did -o %d 100 1 $hget(%h,NoPINGGap)
  did -o %d 103 1 $hget(%h,Timeout)
  did -o %d 62 1 $hget(%h,TimeFormat)
  did -o %d 31 1 $hget(%h,ExcludeNicks)
  did -o %d 55 1 $hget(%h,KeySweep)
  did -o %d 56 1 $hget(%h,KeyWARN)
  did -o %d 57 1 $hget(%h,KeyKICK)
  did -o %d 58 1 $hget(%h,KeyBAN)
  if ($1 != <ALL>) { return }

  :CheckChans
  did -r %d 11 | %i = 1
  while ($hget(cck.HCheckChans,%i).item) { did -a %d 11 $cck.diaMAIN.D2L(CheckChans,$v1) | inc %i }
  if ($1 != <ALL>) { return }

  :BadChans
  did -r %d 34 | %i = 1
  while ($hget(cck.HBadChans,%i).item) { did -a %d 34 $cck.diaMAIN.D2L(BadChans,$v1) | inc %i }
  if ($1 != <ALL>) { return }

  :BadStrings
  did -r %d 38 | %i = 1
  while ($hget(cck.HBadStrings,%i).item) { did -a %d 38 $cck.diaMAIN.D2L(BadStrings,$v1) | inc %i }
  if ($1 != <ALL>) { return }

  :GoodChans
  did -r %d 42 | %i = 1
  while ($hget(cck.HGoodChans,%i).item) { did -a %d 42 $cck.diaMAIN.D2L(GoodChans,$v1) | inc %i }
  if ($1 != <ALL>) { return }

  :TrackUsers
  did -r %d 5 | %i = 1
  while ($hget(cck.HTrackUsers,%i).item) { did -a %d 5 $cck.diaMAIN.D2L(TrackUsers,$v1) | inc %i }
  if ($1 != <ALL>) { return }

  :Session
  did $cck.dia.OOsw($cck.queue.process) %d 98
  if ($1 != <ALL>) { return }

}

; +++ DIALOG MAIN / UPDATE AT CONFIG CHANGE
; $1 = Config $2 = par $3- = val
; $1 = CheckChans or BadChans or BadStrings or GoodChans or TrackUsers $2 = ADD|REM|REP $3 = data reference parameter
; $1 = Session $2 = par $3 = val
alias cck.diaMAIN.upd {
  var %d = CCK.MAIN | if (!$dialog(%d)) { return }
  var %par = $2, %val = $3-, %sw = $cck.dia.OOsw($3)
  goto $1

  :Config
  if (%par == VersionShort) { cck.diaMAIN.title }
  elseif (%par == ActBadChans) { did -c %d 21 $didwm(%d,21,%val) }
  elseif (%par == ActBadStrings) { did -c %d 19 $didwm(%d,19,%val) }
  elseif (%par == TrackUsers.DefaultAct) { did -c %d 88 $didwm(%d,88,%val) }
  elseif (%par == TrackUsers.DefaultDo/List) { did %sw %d 108 }
  elseif (%par == UsePING) { did %sw %d 99 }
  elseif (%par == WinLog.ShowNonMatches) { did %sw %d 71 }
  elseif (%par == Exclude@) { did %sw %d 27 }
  elseif (%par == Exclude%) { did %sw %d 26 }
  elseif (%par == Exclude+) { did %sw %d 28 }
  elseif (%par == NoAbort@PART-KICK) { did %sw %d 33 }
  elseif (%par == DetailedWhois) { did %sw %d 70 }
  elseif (%par == MonitorQueue) { did %sw %d 96 | cck.diaMAIN.title }
  elseif (%par == WarnMsg) { did -ra %d 22 %val }
  elseif (%par == KickMsg) { did -ra %d 25 %val }
  elseif (%par == TrackUsers.DefaultKickMsg) { did -ra %d 10 %val }
  elseif (%par == AskMsg.MaxDataLength) { did -o %d 72 1 %val }
  elseif (%par == WarnMsg.MaxDataLength) { did -o %d 74 1 %val }
  elseif (%par == KickMsg.MaxDataLength) { did -o %d 75 1 %val }
  elseif (%par == WinLog.MaxDataLength) { did -o %d 80 1 %val }
  elseif (%par == SweepInterval) { did -o %d 60 1 %val }
  elseif (%par == DeadGap) { did -o %d 61 1 %val }
  elseif (%par == NoPINGGap) { did -o %d 100 1 %val }
  elseif (%par == Timeout) { did -o %d 103 1 %val }
  elseif (%par == TimeFormat) { did -o %d 62 1 %val }
  elseif (%par == ExcludeNicks) { did -o %d 31 1 %val }
  elseif (%par == KeySweep) { did -o %d 55 1 %val }
  elseif (%par == KeyWARN) { did -o %d 56 1 %val }
  elseif (%par == KeyKICK) { did -o %d 57 1 %val }
  elseif (%par == KeyBAN) { did -o %d 58 1 %val }
  return

  :CheckChans | var %id = 11 | goto upd
  :BadChans | var %id = 34 | goto upd
  :BadStrings | var %id = 38 | goto upd
  :GoodChans | var %id = 42 | goto upd
  :TrackUsers | var %id = 5 | goto upd

  :upd
  if ($2 == ADD) { did -azk %d %id $cck.diaMAIN.D2L($1,$3) }
  elseif ($2 == REP) {
    if ($didwm(%d,%id,$replace($3,$chr(44),$chr(32)) *)) { 
      var %l = $v1 | did $cck.dia.RepSW(%d,%id,%l) %d %id %l $cck.diaMAIN.D2L($1,$3) 
    }
  }
  elseif ($2 == REM) { did -dzk %d %id $didwm(%d,%id,$replace($3,$chr(44),$chr(32)) *) }
  return

  :Session
  if (%par == QueueProcess) { did $cck.dia.OOsw(%val) %d 98 }

}

; Convert system data storage format to dialog list format
; Input: $1 = system $2 = reference parameter
; Output: $result = dialog list record
alias cck.diaMAIN.D2L {
  var %hi = $2 | goto $1
  :CheckChans | tokenize 44 %hi | return $1-2 $hget(cck.HCheckChans,%hi)
  :BadChans | tokenize 44 %hi | var %nc = $1-2 | tokenize 32 $hget(cck.HBadChans,%hi) | return %nc $1 $iif($2 == Never,$2,$cck.time($2))
  :BadStrings | tokenize 32 $hget(cck.HBadStrings,%hi) | return %hi $1 $iif($2 == Never,$2,$cck.time($2))
  :GoodChans | tokenize 44 %hi | var %nc = $1-2 | tokenize 32 $hget(cck.HGoodChans,%hi) | return %nc $1 $iif($2 == Never,$2,$cck.time($2))
  :TrackUsers | tokenize 44 %hi | return $1- $hget(cck.HTrackUsers,%hi)
}

; +++ DIALOG MAIN / UPDATE TITLE
alias cck.diaMAIN.title {
  if (!$dialog(CCK.MAIN)) { return }
  dialog -t CCK.MAIN $hget(cck.HConfig,VersionShort) Main Dialog $&
    $iif($hget(cck.HConfig,MonitorQueue) == ON,- Queue: $cck.queue.getstatus,$null)
}

; +++ DIALOG MAIN / EVENTS
on *:DIALOG:CCK.MAIN:init:0:{
  did -b $dname 17,16,106,107,29,36,37,68,40,41,43,44,59,7,89,110,111,8,90,85,82
  cck.diaMAIN.load <ALL>
}
on *:DIALOG:CCK.MAIN:sclick:*:{
  var %d = $dname, %c = 0, %sw = $iif($did,$cck.dia.swOO(%d,$did))
  ; Config
  if ($did == 21) { cck.Config ActBadChans $$did(%d,21,0) }
  elseif ($did == 19) { cck.Config ActBadStrings $$did(%d,19,0) }
  elseif ($did == 99) { cck.Config UsePING %sw }
  elseif ($did == 71) { cck.Config WinLog.ShowNonMatches %sw }
  elseif ($did == 27) { cck.Config Exclude@ %sw }
  elseif ($did == 26) { cck.Config Exclude% %sw }  
  elseif ($did == 28) { cck.Config Exclude+ %sw }
  elseif ($did == 33) { cck.Config NoAbort@PART-KICK %sw }
  elseif ($did == 70) { cck.Config DetailedWhois %sw }
  elseif ($did == 96) { cck.Config MonitorQueue %sw }
  elseif ($did == 109) { cck.Config TrackUsers.DefaultDo/List $cck.dia.swOO(%d,87) }
  elseif ($did == 69) { cck.BadSound SET }
  elseif ($did == 29) {
    if ($did(%d,22).edited) { cck.Config WarnMsg $$didtok(%d,22,32) | if ($ok($result)) { inc %c | did -j %d 22 } }
    if ($did(%d,25).edited) { cck.Config KickMsg $$didtok(%d,25,32) | if ($ok($result)) { inc %c | did -j %d 25 } }
    if ($did(%d,72).edited) { cck.Config AskMsg.MaxDataLength $$did(%d,72) | if ($ok($result)) { inc %c | did -j %d 72 } }
    if ($did(%d,74).edited) { cck.Config WarnMsg.MaxDataLength $$did(%d,74) | if ($ok($result)) { inc %c | did -j %d 74 } }
    if ($did(%d,75).edited) { cck.Config KickMsg.MaxDataLength $$did(%d,75) | if ($ok($result)) { inc %c | did -j %d 75 } }
    if ($did(%d,80).edited) { cck.Config WinLog.MaxDataLength $$did(%d,80) | if ($ok($result)) { inc %c | did -j %d 80 } }
    if (%c) { did -b %d $did }
  }
  elseif ($did == 85) { cck.Config TrackUsers.DefaultAct $$did(%d,88,0) | if ($ok($result)) { did -b %d $did } }
  elseif ($did == 82) { cck.Config TrackUsers.DefaultKickMsg $$did(%d,10) | if ($ok($result)) { did -b %d $did } }
  elseif ($did == 68) {
    if ($did(%d,60).edited) { cck.Config SweepInterval $$did(%d,60) | if ($ok($result)) { inc %c | did -j %d 60 } }
    if ($did(%d,61).edited) { cck.Config DeadGap $$did(%d,61) | if ($ok($result)) { inc %c | did -j %d 61 } }
    if ($did(%d,100).edited) { cck.Config NoPINGGap $$did(%d,100) | if ($ok($result)) { inc %c | did -j %d 100 } }
    if ($did(%d,103).edited) { cck.Config Timeout $$did(%d,103) | if ($ok($result)) { inc %c | did -j %d 103 } }
    if ($did(%d,62).edited) { cck.Config TimeFormat $$did(%d,62) | if ($ok($result)) { inc %c | did -j %d 62 } }
    if ($did(%d,31).edited) { cck.Config ExcludeNicks $did(%d,31) | if ($ok($result)) { inc %c | did -j %d 31 } }      
    if (%c) { did -b %d $did }
  }
  elseif ($did == 59) {
    if ($did(%d,55).edited) { cck.Config KeySweep $$did(%d,55) | if ($ok($result)) { inc %c | did -j %d 55 } }
    if ($did(%d,56).edited) { cck.Config KeyWARN $$did(%d,56) | if ($ok($result)) { inc %c | did -j %d 56 } }
    if ($did(%d,57).edited) { cck.Config KeyKICK $$did(%d,57) | if ($ok($result)) { inc %c | did -j %d 57 } }
    if ($did(%d,58).edited) { cck.Config KeyBAN $$did(%d,58) | if ($ok($result)) { inc %c | did -j %d 58 } }
    if (%c) { did -b %d $did }
  }

  ; CheckChans
  elseif ($did == 11) {
    if ($did(%d,11,0).sel == 1) {
      tokenize 32 $did(%d,11,$did(%d,11,1).sel)
      did -o %d 12 1 $1-2
      did $cck.dia.OOsw($3) %d 13
      did $cck.dia.OOsw($4) %d 14
      did $cck.dia.OOsw($5) %d 15
      did $cck.dia.OOsw($6) %d 81
    }
    else { did -u %d 13,14,15,81 }
    did -e %d 16,106,107 | did -b %d 17
  }
  elseif ($did == 17) {
    cck.CheckChans.Add $$did(%d,12) $cck.dia.swOO(%d,13,14,15,81)
    if ($ok($result)) { did -b %d $did }
  }
  elseif ($did == 16) {
    var %i = 1, %h = $rhash | while ($did(%d,11,%i).sel) { tokenize 32 $did(%d,11,$v1) | hadd %h %i $1-2 | inc %i }
    var %i = 1 | while ($hget(%h,%i)) { cck.CheckChans.Rem $v1 | if ($ok($result)) { inc %c } | inc %i }
    dec %i | hfree %h | if (%c == %i) { did -b %d 16,106,107 }
  }
  elseif ($istok(106 107,$did,32)) {
    var %i = 1, %c = $iif($did == 106,JOIN,PART)
    while ($did(%d,11,%i).sel) { tokenize 32 $did(%d,11,$v1) | cck.queue.add 8 $1 %c $2 - - MENU | inc %i }
  }
  elseif ($istok(13 14 15 81,$did,32)) {
    var %p = $gettok(USERJOIN OWNJOIN TIMER CONTINUE,$findtok(13 14 15 81,$did,1,32),32), %i = 1
    while ($did(%d,11,%i).sel) {
      tokenize 32 $did(%d,11,$v1) | cck.CheckChans.Change $1-2 %p $cck.dia.swOO(%d,$did) | inc %i
    }
  }

  ; BadChans
  elseif ($did == 34) {
    if ($did(%d,34,0).sel == 1) { tokenize 32 $did(%d,34,$did(%d,34,1).sel) | did -o %d 35 1 $1-2 }
    did -e %d 37 | did -b %d 36
  }
  elseif ($did == 36) { cck.BadChans.Add $$did(%d,35) | if ($ok($result)) { did -b %d $did } }
  elseif ($did == 37) {
    var %i = 1, %h = $rhash | while ($did(%d,34,%i).sel) { tokenize 32 $did(%d,34,$v1) | hadd %h %i $1-2 | inc %i }
    var %i = 1 | while ($hget(%h,%i)) { cck.BadChans.Rem $v1 | if ($ok($result)) { inc %c } | inc %i }
    dec %i | hfree %h | if (%c == %i) { did -b %d $did }
  }

  ; BadStrings
  elseif ($did == 38) {
    if ($did(%d,38,0).sel == 1) { tokenize 32 $did(%d,38,$did(%d,38,1).sel) | did -o %d 39 1 $1 }
    did -e %d 41 | did -b %d 40
  }
  elseif ($did == 40) { cck.BadStrings.Add $$did(%d,39) | if ($ok($result)) { did -b %d $did } }
  elseif ($did == 41) {
    var %i = 1, %h = $rhash | while ($did(%d,38,%i).sel) { tokenize 32 $did(%d,38,$v1) | hadd %h %i $1 | inc %i }
    var %i = 1 | while ($hget(%h,%i)) { cck.BadStrings.Rem $v1 | if ($ok($result)) { inc %c } | inc %i }
    dec %i | hfree %h | if (%c == %i) { did -b %d $did }
  }

  ; GoodChannels
  elseif ($did == 42) {
    if ($did(%d,42,0).sel == 1) {
      tokenize 32 $did(%d,42,$did(%d,42,1).sel)
      did -o %d 45 1 $1-2
    }
    did -e %d 44 | did -b %d 43
  }
  elseif ($did == 43) { cck.GoodChans.Add $$did(%d,45) | if ($ok($result)) { did -b %d $did } }
  elseif ($did == 44) {
    var %i = 1, %h = $rhash | while ($did(%d,42,%i).sel) { tokenize 32 $did(%d,42,$v1) | hadd %h %i $1-2 | inc %i }
    var %i = 1 | while ($hget(%h,%i)) { cck.GoodChans.Rem $v1 | if ($ok($result)) { inc %c } | inc %i }
    dec %i | hfree %h | if (%c == %i) { did -b %d $did }
  }

  ; TrackUsers
  elseif ($did == 5) {
    if ($did(%d,5,0).sel == 1) {
      tokenize 32 $did(%d,5,$did(%d,5,1).sel)
      did -o %d 92 1 $1 | %c = $left($2,2) $+ $right($2,1)
      if ($istok(INW EXW INR EXR,%c,32)) {
        did -c %d 6 $didwm(%d,6,%c)
        did -c %d 87 $didwm(%d,87,$3)
        did -o %d 83 1 $4-
      }
      elseif ($2 == ACT) { did -c %d 88 $didwm(%d,88,$3) | did -e %d 85 }
      elseif ($2 == KICKMSG) { did -o %d 10 1 $3- | did -e %d 82 }
      elseif ($2 == DO/LIST) { did -c %d 108 }
      did -e %d 110
    }  
    did -e %d 90,8 | did -b %d 7,89
  }
  elseif ($did == 90) { cck.dia.ListSelTokSame %d 5 1 32 }
  elseif ($istok(6 87,$did,32)) {
    if ($cck.dia.CheckCombo(%d,6,87)) && ($cck.dia.CheckEdit(%d,92,83)) { did -e %d 7 } | else { did -b %d 7 }
    did -u %d 5 | did -b %d 90,8
  }
  elseif ($did == 88) {
    if ($cck.dia.CheckCombo(%d,88)) {
      if ($cck.dia.CheckEdit(%d,92)) { did -e %d 111 } | else { did -b %d 111 }
      did -e %d 85
    }
  }
  elseif ($did == 87) {
    if ($cck.dia.CheckCombo(%d,88)) {
      if ($cck.dia.CheckEdit(%d,92)) { did -e %d 111 } | else { did -b %d 111 }
      did -e %d 11
    }
  }
  elseif ($did == 8) {
    var %i = 1, %h = $rhash
    while ($did(%d,5,%i).sel) {
      tokenize 32 $did(%d,5,$v1)
      if ($istok(ACT KICKMSG DO/LIST,$2,32)) { hadd %h %i cck.TrackUsers.RemConfig $1-2 }
      elseif ($istok(INW EXW INR EXR,$left($2,2) $+ $right($2,1),32)) { hadd %h %i cck.TrackUsers.RemRule $1-3 }
      inc %i
    }
    var %i = 1 | while ($hget(%h,%i)) { $v1 | if ($ok($result)) { inc %c } | inc %i }
    dec %i | hfree %h | if (%c == %i) { did -b %d $did }
  }
  elseif ($did == 7) {
    cck.TrackUsers.AddRule $$did(%d,92) $$did(%d,6,0) $$did(%d,87,0) $$did(%d,83)
    if ($ok($result)) { did -b %d $did }
  }
  elseif ($did == 111) {
    cck.TrackUsers.AddConfig $$did(%d,92) ACT $$did(%d,88,0) | if ($ok($result)) { inc %c }
    if (%c) { did -b %d $did }
  }
  elseif ($did == 89) {
    cck.TrackUsers.AddConfig $$did(%d,92) KICKMSG $$did(%d,10) | if ($ok($result)) { inc %c }
    if (%c) { did -b %d $did }
  }
  elseif ($did == 110) {
    cck.TrackUsers.AddConfig $$did(%d,92) DO/LIST n/a | if ($ok($result)) { inc %c }
    if (%c) { did -b %d $did }
  }

  ; Session
  elseif ($did == 97) { cck.queue.remnet * }
  elseif ($did == 98) { cck.queue.process %sw }

}
on *:DIALOG:CCK.MAIN:edit:*:{
  var %d = $dname
  ; Config
  if ($istok(22 25 72 74 75 80,$did,32)) { if ($cck.dia.CheckEdit(%d,22,25,72,74,75,80)) { did -e %d 29 } | else { did -b %d 29 } }
  elseif ($istok(60 61 62 31 100 103,$did,32)) { if ($cck.dia.CheckEdit(%d,60,61,62,100,103)) { did -e %d 68 } | else { did -b %d 68 } }
  elseif ($istok(55 56 57 58,$did,32)) { if ($cck.dia.CheckEdit(%d,55,56,57,58)) { did -e %d 59 } | else { did -b %d 59 } }
  ; CheckChans
  elseif ($did == 12) { did -u %d 11 | did -b %d 16 | if ($numtok($did(%d,$did),32) == 2) { did -e %d 17 } | else { did -b %d 17 } }
  ; BadChans
  elseif ($did == 35) { did -u %d 34 | did -b %d 37 | if ($numtok($did(%d,$did),32) == 2) { did -e %d 36 } | else { did -b %d 36 } }
  ; BadStrings
  elseif ($did == 39) { did -u %d 38 | did -b %d 41 | if ($numtok($did(%d,$did),32) == 1) { did -e %d 40 } | else { did -b %d 40 } } 
  ; GoodChans
  elseif ($did == 45) { did -u %d 42 | did -b %d 44 | if ($numtok($did(%d,$did),32) == 2) { did -e %d 43 } | else { did -b %d 43 } }
  ; TrackUsers
  elseif ($istok(92 83,$did,32)) {
    did -u %d 5 | did -b %d 90,8
    if ($cck.dia.CheckCombo(%d,6,87)) && ($cck.dia.CheckEdit(%d,92,83)) { did -e %d 7 } | else { did -b %d 7 }
    if ($cck.dia.CheckEdit(%d,92)) && ($cck.dia.CheckCombo(%d,88)) { did -e %d 82 } | else { did -b %d 82 }
  }
  elseif ($did == 10) {
    did -u %d 5 | did -b %d 90,8,7,111,110
    if ($cck.dia.CheckEdit(%d,92,10)) { did -e %d 82,89 } | else { did -b %d 82,89 }
  }
}

;===================================================================================================
; DIALOG ASK
;===================================================================================================

; +++ DIALOG ASK / TABLE
; <timestamp> <# or $ or T> <network> <nick> <bad channels or tag of first TrackUsers match>
dialog CCK.ASK {
  title ""
  size -1 -1 274 102
  option dbu
  list 1, 0 1 274 90, size extsel hsbar vsbar
  button "Warn", 2, 1 92 18 10
  button "Kick", 3, 20 92 15 10
  button "KickBan", 4, 36 92 24 10
  button "Sweep", 5, 173 92 21 10, flat
  button "", 6, 175 94 8 7, hide ok
  button "Rem", 7, 258 92 15 10
  check "Empty->Close", 8, 61 92 38 10, push
  button "All", 9, 234 92 11 10
  edit "", 10, 143 92 15 10, limit 3
  text "MaxDataLength", 11, 103 94 39 8
  button "Set", 12, 159 92 13 10
  button "Sel T", 13, 195 92 17 10
  button "#", 14, 214 92 9 10
  button "$", 15, 224 92 9 10
  button "CB", 16, 246 92 11 10
}
alias cck.diaASK { var %d = CCK.ASK | if (!$dialog(%d)) { dialog -mdv %d %d } | else { dialog -ev %d %d } }

; +++ DIALOG ASK / LOAD CONFIG
alias cck.diaASK.load {
  var %d = CCK.ASK | if (!$dialog(%d)) { return }
  cck.diaASK.title
  did $cck.dia.OOsw($hget(cck.HConfig,DiaASK.CloseWhenEmpty)) %d 8
  did -o %d 10 1 $hget(cck.HConfig,DiaASK.MaxDataLength)
}

; +++ DIALOG ASK / UPDATE AT CONFIG CHANGE
; <par> <val>
alias cck.diaASK.upd {
  var %d = CCK.ASK | if (!$dialog(%d)) { return }
  var %par = $1, %val = $2-
  if (%par == VersionShort) { cck.diaASK.title }
  elseif (%par == DiaASK.CloseWhenEmpty) { did $cck.dia.OOsw($2) %d 8 }
  elseif (%par == DiaASK.MaxDataLength) { did -o %d 10 1 %val }
}

; +++ DIALOG ASK / UPDATE TITLE
alias cck.diaASK.title {
  if (!$dialog(CCK.ASK)) { return }
  dialog -t CCK.ASK $hget(cck.HConfig,VersionShort) Ask Dialog $&
    $iif($hget(cck.HConfig,MonitorQueue) == ON,- Queue: $cck.queue.getstatus,$null)
}

; +++ DIALOG ASK / EVENTS
on *:DIALOG:CCK.ASK:init:0:{ did -b $dname 2,3,4,7,12,16 | cck.diaASK.load }
on *:DIALOG:CCK.ASK:sclick:*:{
  var %d = $dname, %c = 0
  if ($did == 1) { did -e %d 2,3,4,7,16 }
  elseif ($istok(2 3 4,$did,32)) {
    var %act = $gettok(WARN KICK BAN,$findtok(2 3 4,$did,1,32),32), %t = $did(%d,1,0).sel, %i = 1
    while (%i <= %t) {
      tokenize 32 $did(%d,1,$did(%d,1,%i).sel)
      var %actmsg = $iif($2 == T,$6-,$cck.actmsg(%act,$3,$4,$6-))
      cck.netwarnkickban %act $3 $4 $5 %actmsg
      inc %i
    }
  }
  elseif ($did == 5) { cck.CheckChans.Sweep }
  elseif ($did == 7) { while ($did(%d,1,1).sel) { did -dzk %d 1 $v1 } | did -b %d 2,3,4,7,16 }
  elseif ($did == 8) { cck.Config DiaASK.CloseWhenEmpty $cck.dia.swOO(%d,8) }
  elseif ($did == 9) { did -c %d 1 | if ($did(%d,1,1).sel) { did -e %d 7,2,3,4,16 } | else { did -b %d 7,2,3,4,16 } }
  elseif ($istok(13 14 15,$did,32)) {
    %c = $gettok(T $chr(35) $,$findtok(13 14 15,$did,1,32),32)
    did -u %d 1 | cck.dia.ListSelTokVal %d 1 2 32 %c
    if ($did(%d,1,1).sel) { did -e %d 7,2,3,4,16 } | else { did -b %d 7,2,3,4,16 }
  }
  elseif ($did == 12) { cck.Config DiaASK.MaxDataLength $$did(%d,10) }
  elseif ($did == 16) { var %i = 1 | while ($did(%d,1,%i).sel) { clipboard -an $did(%d,1,$v1) | inc %i } }
}
on *:DIALOG:CCK.ASK:edit:*:{
  var %d = $dname
  if ($did == 10) { did $iif($did(%d,10) != $null,-e,-b) %d 12 }
}

; DIALOG ASK / UPDATE LIST
; List layout: timestamp #|$|T network nick user@host badchans|trackuserskickmsg
; If nick already present, replace according to priority 1) TrackUsers T 2) BadChans # 3) BadStrings $
; <# or $ or T> <network> <nick> <user@host> <foundchans or TrackUser first matching tag>
alias cck.diaASK.add {
  var %d = CCK.ASK | if (!$dialog(%d)) { cck.DiaASK }
  var %l = $didwm(%d,1,& & $2 $3 *) | if (!%l) { did -azk %d 1 $cck.time $1- | return }
  var %rec = $did(%d,1,%l), %type = $gettok(%rec,2,32), %p1 = $pos(T#$,$1,1), %p2 = $pos(T#$,%type,1)
  if (%p1 <= %p2) { did -ok %d 1 %l $cck.time $1- }
}
; <network> <nick> (wildcards allowed)
alias cck.DiaASK.rem {
  var %d = CCK.ASK | if (!$dialog(%d)) { return }
  if ($didwm(%d,1,& & $1 $2 *)) { did -dzk %d 1 $v1 | cck.DiaASK.closeempty | return }
}
; <network> <nick>
alias cck.DiaASK.get {
  if ($dialog(CCK.ASK)) && ($didwm(CCK.ASK,1,& & $1 $2 *)) { return $did(CCK.ASK,1,$v1) }
  return 0
}
; <network>
alias cck.DiaASK.getlatest { 
  var %d = CCK.ASK | if (!$dialog(%d)) { return 0 }
  var %i = $did(%d,1).lines
  while (%i) { var %rec = $did(%d,1,%i) | if ($gettok(%rec,3,32) == $1) { return %rec } | dec %i }
  return 0
}
; <network> <nick> <newnick>
alias cck.DiaASK.updnick {
  var %d = CCK.ASK
  if ($dialog(%d)) && ($didwm(%d,1,& & $1 $2 *)) {
    var %l = $v1 | did -ok %d 1 %l $puttok($did(%d,1,%l),$3,4,32) | return 1
  }
  return 0
}
; <network> <channel> (to exclude - pass through to onchan function)
alias cck.DiaASK.clean {
  var %d = CCK.ASK
  if (!$dialog(%d)) { return }
  var %net = $1, %chan = $2, %t = $did(%d,1).lines, %i = 1
  while (%i <= %t) {
    tokenize 32 $did(%d,1,%i)
    if ($3 == %net) && (!$cck.onchan(*,$3,$4,%chan)) { did -dzk %d 1 %i | dec %t } | else { inc %i }
  }
  cck.DiaASK.closeempty
}
; assumed present
alias cck.DiaASK.closeempty {
  if ($hget(cck.HConfig,DiaASK.CloseWhenEmpty) == ON) && (!$did(CCK.ASK,1).lines) { dialog -k CCK.ASK }
  elseif (!$did(CCK.ASK,1,0).sel) { did -b CCK.ASK 7,2,3,4,16 }
}

;===================================================================================================
; IRC / COMMON EVENTS
;===================================================================================================

; +++ IRC EVENTS / COMMON
on *:PART:#: {
  if ($nick == $me) {
    if (!$cck.rawclean(PART,#,-,-)) { cck.queue.rem $network PART # - - }
    if ($hget(cck.HConfig,NoAbort@PART-KICK) != ON) { cck.queue.clean $network # }
    cck.diaASK.clean $network #
  }
  elseif (!$cck.onchan(*,$network,$nick,#)) {
    if ($hget(cck.HConfig,NoAbort@PART-KICK) != ON) { cck.queue.rem $network WHOIS $nick - & }
    cck.diaASK.rem $network $nick
  }
  cck.queue.rem $network KICK # & $nick
  cck.queue.rem $network MODE # & $nick
}
#cck.raw.part off
; You're not on that channel
RAW 442:*: { if ($cck.rawclean(PART,$2,-,-)) { haltdef } }
; No such channel
RAW 403:*: { if ($cck.rawclean(PART,$2,-,-)) { haltdef } }
#cck.raw.part end

on *:KICK:#: {
  if ($knick == $me) {
    if ($hget(cck.HConfig,NoAbort@PART-KICK) != ON) { cck.queue.clean $network # }
    cck.diaASK.clean $network #
  }
  elseif (!$cck.onchan(*,$network,$knick,$chan)) {
    if ($hget(cck.HConfig,NoAbort@PART-KICK) != ON) { cck.queue.rem $network WHOIS $knick - * }
    cck.diaASK.rem $network $knick
  }
  if (!$cck.rawclean(KICK,#,-,$knick)) { cck.queue.rem $network KICK # & $knick }
  cck.queue.rem $network MODE # & $knick
}
on *:NICK: {
  cck.queue.updnick $network $nick $newnick
  cck.diaASK.updnick $network $nick $newnick
}
on *:QUIT: {
  cck.queue.rem $network WHOIS $nick - *
  cck.queue.rem $network KICK & - $nick
  cck.queue.rem $network MODE & & $nick
  cck.queue.rem $network MSG $nick - -
  cck.diaASK.rem $network $nick
}
on *:DISCONNECT: { hdel -w cck.H $+($network,$chr(44),*) | cck.queue.remnet $network | cck.diaASK.rem $network * }

;===================================================================================================
; IRC / WHOIS
;===================================================================================================

; +++ IRC EVENTS / WHOIS
#cck.raw.whois on
raw 275:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw SSL 1 } }
raw 301:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw AWAY $3- } }
raw 307:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw REGNICK $2 } }
raw 310:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw HELPOP 1 } }
raw 311:*:{
  if ($cck.raw(WHOIS,$2,-,*)) { 
    var %c = hadd cck.HRaw | %c NETWORK $network | %c NICK $2 | %c USER $3 | %c HOST $4 | %c REALNAME $6-
    %c MASK $+($2,!,$3,@,$4)  
  }
}
raw 312:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw SERVHOST $3 | hadd cck.HRaw SERVINFO $4- } }
raw 313:*:{
  if (!$cck.raw(WHOIS,$2,-,*)) { return }
  if (service isin $3-) { hadd cck.HRaw SERVICE 1 }
  if (operator isin $3-) { hadd cck.HRaw IRCOP 1 }
}
raw 317:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw ^IDLE $3 | hadd cck.HRaw ^LOGON $4 } }
raw 318:*:{ if ($cck.raw(WHOIS,$2,-,*)) { cck.whois.process $2 } }
raw 319:*:{
  if (!$cck.raw(WHOIS,$2,-,*)) { return }
  var %i = 3 | while ($ [ $+ [ %i ] ] != $null) { aline @cck.raw $v1 | inc %i }
}
raw 330:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw AUTHNAME $3 } }
raw 335:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw BOT 1 } }
raw 338:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw REALHOST $3 } }
raw 378:*:{
  if (!$cck.raw(WHOIS,$2,-,*)) { return }
  hadd cck.HRaw REALHOST $iif(@ isin $6,$gettok($6,2,64),$6)
  hadd cck.HRaw USERIP $7
}
raw 401:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw OFFLINE 1 } }
raw 402:*:{
  if (!$cck.raw(WHOIS,$2,-,*)) { return }
  hadd cck.HRaw OFFLINE 1 | cck.whois.process $2
}
raw 535:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw FILTERING 1 } }
raw 671:*:{ if ($cck.raw(WHOIS,$2,-,*)) { hadd cck.HRaw SSL 1 } }
#cck.raw.whois end

; IN32 $1 = nick // Data in hash cck.Hraw + win @cck.raw
alias cck.whois.process {
  var %nick = $1, %hc = cck.HConfig, %w = @cck.raw, %h = cck.HRaw
  var %s = $cck.queue.get($network,WHOIS,%nick,-,*) | if (!%s) { cck.rawclean | return }
  tokenize 32 %s | var %pr = $1, %addr = $6, %sysd = $7
  if ($hget(%h,OFFLINE)) {
    if (%addr == -) { cck.rawclean | return }
    tokenize 64 %addr | hadd %h USER $1 | hadd %h HOST $2 | hadd %h MASK $+(%nick,!,%addr)
  }  
  %addr = $+($hget(%h,USER),@,$hget(%h,HOST))
  var %nolist, %wr = $rwin | filter -ww %w %wr *
  var %show = $iif($hget(%hc,WinLog.ShowNonMatches) == ON && !$istok(CONTINUE TIMER,%sysd,32),1,0)

  :track
  var %track = $cck.TrackUsers.Check(%h,%wr)
  if (%show) || (%track) {
    tokenize 32 %track
    var %c = cck.echoLog $+(,$iif(%track,04,10),$network %nick,)
    if (%track) { %c matches TrackUsers RuleSet "12 $+ $2 $+ " - Action12 $1 $+ : }
    if ($hget(%h,OFFLINE)) { %c OFFLINE }
    %c USER: $hget(%h,USER) HOST: $hget(%h,HOST)
    %c REALNAME: $hget(%h,REALNAME)
    var %s
    if ($hget(%h,REGNICK) != $null) { %s = REGNICK: $v1 }
    if ($hget(%h,AUTHNAME) != $null) { %s = %s AUTHNAME: $v1 }
    if ($hget(%h,USERIP) != $null) { %s = %s USERIP: $v1 }
    if ($hget(%h,REALHOST) != $null) { %s = %s REALHOST: $v1 }
    if (%s) { %c %s }
    if ($hget(%h,AWAY) != $null) { %c AWAY: $v1 }
    var %s
    if ($hget(%h,^LOGON) != $null) { 
      %s = ^LOGON: $asctime($v1,$hget(cck.HConfig,TimeFormat)) ( $+ $duration($calc($ctime - $v1)) ago)
    }
    if ($hget(%h,^IDLE) != $null) { %s = %s ^IDLE: $duration($v1) }
    if (%s) { %c %s }
    %c SERVHOST: $hget(%h,SERVHOST) SERVINFO: $hget(%h,SERVINFO)
    var %s
    if ($hget(%h,IRCOP) != $null) { var %s = FLAGS: IRCOP }
    if ($hget(%h,HELPOP) != $null) { var %s = %s HELPOP }
    if ($hget(%h,SERVICE) != $null) { var %s = %s SERVICE }
    if ($hget(%h,BOT) != $null) { var %s = %s BOT }
    if ($hget(%h,FILTERING) != $null) { var %s = %s FILTERING }
    if ($hget(%h,SSL) != $null) { var %s = %s SSL }                
    if (%s) { %c %s }
  }
  if (!%track) { window -c %wr | %s = $+(10,$network %nick,) | goto channels }
  %s = $+(04,$network %nick,)
  if ($istok(KICK BAN,$1,32)) {
    cck.netwarnkickban $1 $network %nick %addr $cck.limittokenstring(32,$hget(%hc,KickMsg.MaxDataLength),$4-)
    var %actdone = 1
  }
  elseif ($1 == ASK) {
    cck.mychans $network %nick echo -t 10 $+ $network %nick %addr is a TrackUsers RuleSet12 $2 match $+ . Press $cck.key.info
    if ($cck.onchan(*,$network,%nick)) {
      cck.diaASK.add T $network %nick %addr $cck.limittokenstring(32,$hget(%hc,DiaASK.MaxDataLength),$4-)
      cck.badsound
    }
  }
  if ($3 == DO/LIST) { %nolist = 1 }
  window -c %wr

  :channels
  if ($hget(%h,OFFLINE)) { cck.echoLog %s OFFLINE | cck.rawclean | return }
  if (!$line(%w,1)) { cck.echoLog %s not found on any visible channels. | cck.rawclean | return }
  var %i = 0, %foundbad = 0, %foundstring = 0, %list, %list1, %p, %c, %pchanc, %pchan, %len
  :channels.next
  inc %i | %pchan = $line(%w,%i) | if (%pchan == $null) { goto channels.act }
  %pchanc = $cck.getprefixchan($network,%pchan)
  if (%pchanc == INVALID) { 
    %list1 = %list %pchan $+ (04ParsingFailure)
    rline %w %i %pchanc NONE
    cck.echo- SYSTEM: Parsing failure for channel12 %pchan $+ .
    goto channels.output
  }
  tokenize 32 %pchanc | %p = $iif($1 != <none>,$1,$null) | %c = $2
  if (%nolist) { cck.queue.add 4 $network LIST %c - - $+(TRACKUSERS;,$1,;,%nick,;,%addr) }
  if ($cck.BadChans.Check($network,%c)) {
    rline %w %i %c $hget(%hc,ActBadChans) | inc %foundbad | %list1 = %list $+(%p,04,%c,)
  }
  elseif ($cck.BadStrings.Check(%c)) {
    if ($cck.GoodChans.Check($network,%c)) { dline %w %i | dec %i | %list1 = %list $+(%p,03,%c,) }
    else { rline %w %i %c $hget(%hc,ActBadStrings) | inc %foundstring | %list1 = %list $+(%p,07,%c,) }
  }
  else { dline %w %i | dec %i | %list1 = %list %p $+ %c }
  :channels.output
  %len = $len(%list1)
  if (%len < $hget(%hc,WinLog.MaxDataLength)) { %list = %list1 | goto channels.next }
  if (%show) || ($calc(%foundbad + %foundstring)) || (%track) { cck.echoLog %s is on %list }
  if (%len > $hget(%hc,WinLog.MaxDataLength)) { %list = $gettok(%list1,-1,32), %list1 } | else { %list = $null }
  goto channels.next
  :channels.act
  if (%list) && ((%show) || ($calc(%foundbad + %foundstring))) || (%track) { cck.echoLog %s is on %list }
  if (!$calc(%foundbad + %foundstring)) { cck.rawclean | return }
  var %ask = $fline(%w,& ASK,1), %warn = $fline(%w,& WARN,1), %kick = $fline(%w,& KICK,1), %ban = $fline(%w,& BAN,1)
  if ($fline(%w,& BAN,1)) {
    if (!%actdone) {
      filter -wwc %w %w & BAN
      var %msg = $cck.col2tok(%w,32,1,32,$hget(%hc,KickMsg.MaxDataLength))
      cck.netwarnkickban BAN $network %nick %addr $cck.actmsg(BAN,$network,%nick,%msg)
    }
  }
  elseif ($fline(%w,& KICK,1)) {
    if (!%actdone) {
      filter -wwc %w %w & KICK
      var %msg = $cck.col2tok(%w,32,1,32,$hget(%hc,KickMsg.MaxDataLength))
      if (!%actdone) { cck.netwarnkickban KICK $network %nick %addr $cck.actmsg(KICK,$network,%nick,%msg) }
    }
  }
  elseif ($fline(%w,& WARN,1)) {
    if (!%actdone) {
      filter -wwc %w %w & WARN
      var %msg = $cck.col2tok(%w,32,1,32,$hget(%hc,WarnMsg.MaxDataLength))
      cck.netwarnkickban WARN $network %nick %addr $cck.actmsg(WARN,$network,%nick,%msg)
    }
  }
  elseif ($fline(%w,& ASK,1)) {
    filter -wwc %w %w & ASK
    var %msg = $cck.col2tok(%w,32,1,32,$hget(%hc,AskMsg.MaxDataLength))
    if (!$cck.DiaASK.get($network,%nick)) {
      cck.mychans $network %nick echo -t 10 $+ $network %nick %addr on %msg $+ . Press $cck.key.info
    }
    if ($cck.onchan(*,$network,%nick)) {
      cck.diaASK.add $iif(%foundbad,$chr(35),$) $network %nick %addr $cck.col2tok(%w,32,1,32,$hget(%hc,DiaASK.MaxDataLength))
      cck.badsound
    }
  }
  cck.rawclean
}

;===================================================================================================
; IRC / JOIN
;===================================================================================================

on *:JOIN:#: {
  if ($nick == $me) {
    hadd cck.H $s2c($network,JOIN,$chan) 1
    if (!$cck.rawclean(JOIN,#,*,*)) { cck.queue.rem $network JOIN # - & }
  }
  if (!$cck.CheckChans.Check($network,$chan,USERJOIN)) { return }
  if ($cck.exclude($network,$nick)) || ($istok($replace($hget(cck.HConfig,ExcludeNicks),<ME>,$me),$nick,32)) { return }
  cck.queue.add 2 $network WHOIS $nick - $address USERJOIN
}
RAW 366:*:{
  var %s = $s2c($network,JOIN,$2) | if (!$hget(cck.H,%s)) { return } | hdel cck.H %s
  if ($cck.CheckChans.Check($network,$2,OWNJOIN)) { cck.whoischan 2 $network $2 OWNJOIN }
}
#cck.raw.join off
RAW 384:*:{ cck.join.process $2 CBAN }
RAW 403:*:{ cck.join.process $2 NOSUCHCHAN }
RAW 405:*:{ cck.join.process $2 TOOMANY }
RAW 439:*:{ if ($left($2,1) isin $chantypes) { cck.join.process $2 TOOFAST } }
RAW 470:*:{ cck.join.process $2 LIMITED-LINKED $wildtok($3-,$+($left($2,1),*),2,32) }
RAW 471:*:{ cck.join.process $2 LIMITED }
RAW 473:*:{ cck.join.process $2 INVITE-ONLY }
RAW 474:*:{ cck.join.process $2 BANNED }
RAW 475:*:{ cck.join.process $2 NEEDKEY }
RAW 476:*:{ cck.join.process $2 BADCHANMASK }
RAW 477:*:{ if ($istok($3-,join,32)) { cck.join.process $2 NEEDREGISTERED } }
RAW 479:*:{ cck.join.process $2 GLINED }
RAW 485:*:{ if ($3-5 == Cannot join channel) { cck.join.process $2 FREEREASON $remove($6,$chr(40),$chr(41)) $2 } }
RAW 489:*:{ cck.join.process $2 CHANNEL+Z }
RAW 490:*: { cck.join.process $2 NEEDSSL }
RAW 495:*: { cck.join.process $2 DELAYEDJOINAFTERKICK $2 }
RAW 500:*: { cck.join.process $2 TOOMANYJOINS $2 }
RAW 520:*: { cck.join.process $2 NEEDIRCOP }
RAW 530:*: { cck.join.process $2 NEWONLYBYIRCOPS $2 }
on *:SNOTICE:*** Can not join * Channel Reserved For Services: { 
  cck.join.process $gettok($5,1,58) RESERVEDFORSERVICES
}
#cck.raw.join end
; IN32 $1 = channel $2 = result flag
alias cck.join.process {
  if (!$cck.raw(JOIN,$1,*,*)) { return }
  var %s = $cck.queue.getpar($network,JOIN,$1,*,*) | if (!%s) { cck.rawclean | return }
  cck.echo- SYSTEM: JOIN12 $1 failed ( $+ $2 $+ ).

  cck.rawclean
}

;===================================================================================================
; IRC / MODE
;===================================================================================================

on *:RAWMODE:#: {
  cck.ChanModeParse $network $1-
  var %w = $result, %total = $line(%w,0), %i = 1
  while (%i <= %total) { cck.mode $gettok($line(%w,%i),2-,32) | inc %i }
  window -c %w
}
; Input: $1 = modeflag $2 = modetextlabel|UNKNOWN $3 = nick or mask
alias -l cck.mode {
  var %flag = $1, %mode = $2, %par = $3
  if ($istok(OP HALFOP VOICE,%mode,32)) {
    if ($cck.exclude($network,%par)) { cck.queue.rem $network WHOIS %par - * }
  }
  if (!$cck.rawclean(MODE,#,%flag,%par)) { cck.queue.rem $network MODE # %flag %par }
}

#cck.raw.mode off
; <channel> You're not channel operator
RAW 482:*: { if ($cck.rawclean(MODE,$2,*,*)) || ($cck.rawclean(KICK,$2,*,*)) { haltdef } }
; <flag> <nick> is a channel admin/owner/network service
RAW 974:*:{ if ($cck.rawclean(MODE,*,? $+ $2,$3)) || ($cck.rawclean(KICK,*,*,$2)) { haltdef } }
; <nickname> <channel> :They aren't on that channel
RAW 441:*: { if ($cck.rawclean(MODE,$3,*,$2)) || ($cck.rawclean(KICK,$3,-,$2)) { haltdef } }
#cck.raw.mode end

;===================================================================================================
; IRC / LIST
;===================================================================================================

#cck.raw.list on
; Channel :Users Name
RAW 321:*:{
  if ($cck.raw(LIST,*,-,-)) { cck.list.close@ }
}
; <channel> <users> :<topic>
RAW 322:*:{ if ($cck.raw(LIST,*,-,-)) { cck.list.close@ | aline @cck.raw $2- } }
; :End of /LIST
RAW 323:*:{ if ($cck.raw(LIST,*,-,-)) { cck.list.close@ | cck.list.process } }
alias cck.list.process {
  var %rec = $cck.queue.get($network,LIST,*,-,-) | if (!%rec) { cck.rawclean | return }
  tokenize 32 %rec | var %c = $4, %sysd = $7, %w = @cck.raw
  if (TRACKUSERS;* iswm %sysd) {
    var %l = $fline(%w,%c *,1) | if (!%l) { cck.rawclean | return }
    tokenize 59 %sysd | var %p = $iif($2 != <none>,$2,$null), %nick = $3, %addr = $4
    cck.echoLog $+(04,$network %nick,) CHANNEL: $+(%p,%c) USERS: $gettok($line(%w,%l),2,32) TOPIC: $gettok($line(%w,%l),3-,32)
  }
  cck.rawclean
}
#cck.raw.list end
alias -l cck.list.close@ { if ($window(channels list)) { window -c "channels list" } }

;===================================================================================================
; IRC COMMAND QUEUE
;===================================================================================================

; +++ QUEUE / EVENTS CHECK
; Queue format:
; Item: <network>,<WHOIS|JOIN|PART|MODE|KICK|LIST|MSG|NOTICE|DESCRIBE>,<nick|channel>,<switch|->,<whoisnick-user@host|pass|nick|banmask|->
; Data: <systemdata> <kickmsg|partmsg|message>

; Too many lines in your output
RAW 416:*: { 
  if (!$cck.raw(LIST,*,-,-)) { cck.list.process }

}

; +++ QUEUE / FORCED RESPONSE CASE MSG|NOTICE|DESCRIBE
#cck.raw.ping off
on ^*:PONG: { if ($network $2 == $hget(cck.H,QPING)) { haltdef | cck.rawclean } }
#cck.raw.ping end

; +++ QUEUE / CHECK IF GIVEN EVENT PARAMETERS MATCH THE CURRENT BUSY (current connection)
; IN32 $1 = command $2 = par1 $3 = switch $4 = par2
alias cck.raw { if ($network $1- * iswm $hget(cck.H,QBUSY)) { haltdef | return 1 } | return 0 }

; +++ QUEUE / CHECK + CLEANUP RAW DATA
; IN32 see cck.raw, direct call in case just one response (optional)
alias cck.rawclean {
  if ($1 != $null) && ($network $1- * !iswm $hget(cck.H,QBUSY)) { return 0 }
  hdel -w cck.HRaw * | clear @cck.raw
  tokenize 32 $hget(cck.H,QBUSY) | hdel cck.H QBUSY | .disable cck.raw. $+ $2
  if ($2 != PING) { cck.queue.rem $1-5 }
  .timercck.Timeout OFF | .timercck.DeadGap -oih 1 $hget(cck.HConfig,DeadGap) cck.queue.donext
  return 1
}

; +++ QUEUE / ADD
; IN32 $1 = priority 1-9 $2 = network  $3 = command $4 = par1 $5 = switch $6 = par2 $7 = sysdata [$8- = msg]
alias cck.queue.add {
  var %netw = $2 | if (* !isin $2) { var %net = $2 | goto single }
  var %i = 0
  :next | inc %i | if (!$scon(%i)) { cck.queue.donext | return }
  if ($scon(%i).status != connected) || (%netw !iswm $scon(%i).network) { goto next }
  var %net = $scon(%i).network
  :single
  if ($hget(cck.H,QBUSY) == %net $3-6) { goto next }
  var %rec = $cck.queue.get(%net,$3,$4,$5,$6) | if (%rec) && ($gettok(%rec,1,32) >= $1) { return }
  var %4 = $chr(44), %hi = $+(%net,%4,$3,%4,$4,%4,$5,%4,$6)
  if (%rec) { hdel cck.HQ $+ %pr %hi }
  hadd cck.HQ $+ $1 %hi $7- | if (* isin %netw) { goto next }
  cck.queue.donext
}

; +++ QUEUE / GET DATA
; IN32 $1 = network $2 = command $3 = par1 $4 = switch $5 = par2 (wildcards allowed)
; OUT32 $1- = 0 (notfound) or $1- = priority hash-item data, all space separated
alias cck.queue.get {
  var %4 = $chr(44), %wm = $+($1,%4,$2,%4,$3,%4,$4,%4,$5), %i = 1, %h
  while (%i < 10) {
    %h = cck.HQ $+ %i
    if ($hfind(%h,%wm,1,w)) { return %i $replace($v1,$chr(44),$chr(32)) $hget(%h,$v1) }
    inc %i
  }
  return 0
}

; +++ QUEUE / GET AMOUNT QUEUE ENTRIES FOR GIVEN COMMAND+SWITCH
; IN32 $1 = command $2 = switch
alias cck.queue.get# {
  var %4 = $chr(44), %wm = $+(*,%4,$1,%4,*,%4,$2,%4,*), %i = 10, %count = 0
  while (%i) { inc %count $hfind(cck.HQ $+ %i,%wm,0,w) | dec %i }
  return %count
}

; +++ QUEUE / CHECK IF QUEUE IS EMPTY FOR GIVEN COMMAND+SWITCH
; IN32 $1 = command $2 = switch
; OUT32 $1 = 0 (not empty) or 1 (empty)
alias cck.queue.empty {
  var %4 = $chr(44), %wm = $+(*,%4,$1,%4,*,%4,$2,%4,*), %i = 10
  while (%i) { if ($hfind(cck.HQ $+ %i,%wm,1,w)) { return 0 } | dec %i }
  return 1
}

; +++ QUEUE / CHECK IF THE BUSY ONE IS STILL IN A QUEUE HASH, IF NOT, REMOVE BUSY FLAG AND DO NEXT
; to be done after removal(s)
alias cck.queue.checkbusy {
  cck.diaMAIN.title | cck.diaASK.title
  var %hi = $hget(cck.H,QBUSY) | if (!%hi) || ($numtok(%hi,32) == 1) { return }
  tokenize 32 %hi | if (!$cck.queue.get($1,$2,$3,$4,$5)) { hdel cck.H QBUSY | cck.queue.donext }
}

; +++ QUEUE / DO NEXT
; walk from hash9 to hash1 (priority into effect)
alias cck.queue.donext {
  cck.diaMAIN.title | cck.diaASK.title
  if ($cck.queue.process != ON) || ($hget(cck.H,QBUSY)) || (($timer(cck.DeadGap) && ($ctimer != cck.DeadGap))) { return }
  var %i = 9
  :next
  if ($hget(cck.HQ $+ %i,1).item) { goto found }
  dec %i | if (%i) { goto next }
  cck.CheckChans.Sweep CONTINUE | return
  :found
  var %hi = $v1, %hv = $hget(cck.HQ $+ %i,%hi) | tokenize 44 %hi | scid $cck.net2cid($1)
  goto $2

  :WHOIS | $2 $iif($hget(cck.HConfig,DetailedWhois) == ON,$3 $3,$3) | .enable #cck.raw.whois | goto timeout
  :JOIN | if ($me !ison $3) { $2-4 | .enable #cck.raw.join | goto timeout } | goto del
  :PART | if ($me ison $3) { $2-3 $gettok(%hv,2-,32) | .enable #cck.raw.part | goto timeout } | goto del
  :MODE | $2-5 | if (!$istok(b e i,$remove($4,+,-),32)) { .enable #cck.raw.mode | goto timeout }
  goto ping
  :KICK | $2-3 $5 $gettok(%hv,2-,32) | goto timeout
  :LIST | $2-3 | .enable #cck.raw.list | goto timeout
  :MSG | :NOTICE | :DESCRIBE | $2-3 $gettok(%hv,2-,32) | goto ping

  :del | hdel cck.HQ $+ %i %hi | cck.diaMAIN.title | cck.diaASK.title | goto next
  :ping
  hdel cck.HQ $+ %i %hi
  if ($hget(cck.HConfig,UsePING) != ON) { .timercck.DeadGap -oih 1 $hget(cck.HConfig,NoPINGGap) cck.queue.donext }
  else { var %s = cck. $+ $ticks | scid %cid .quote PING %s | hadd cck.H QPING $1 %s | .enable #cck.raw.ping }
  :timeout | hadd cck.H QBUSY $1- %hv
  .timercck.Timeout -oi 1 $hget(cck.HConfig,Timeout) cck.queue.timeout $1- %hv
}
alias cck.queue.timeout { if ($1-5 iswm $hget(cck.H,QBUSY)) { cck.queue.recover } }

alias cck.queue.recover {
  if ($hget(cck.H,QBUSY) == $null) { return }
  tokenize 32 $v1 | hdel cck.H QBUSY | hdel cck.H QPING | .disable cck.raw. $+ $2
  cck.queue.rem $1-5 | hdel -w cck.HRaw * | clear @cck.raw | cck.queue.donext
}

; +++ QUEUE / UPDATE NICK (current connection
; IN32 $1 = network $2 = old nick $3 = new nick
alias cck.queue.updnick {
  var %wm = $+($1,$chr(44),*), %n0 = $2, %n1 = $3, %i1 = 1, %h, %i2, %hr = $rhash, %4 = $chr(44), %hi, %hv
  while (%i1 < 10) {
    %h = cck.HQ $+ %i1 | %i2 = 1
    while ($hfind(%h,%wm,%i2,w)) {
      %hi = $v1 | %hv = $hget(%h,%hi) | tokenize 44 %hi | goto $2

      :WHOIS | :MSG | :NOTICE | :DESCRIBE
      if ($3 === %n0) { hadd %hr $+(%i1,%4,$puttok(%hi,%n1,3,44)) %hv | goto del }
      inc %i2 | continue
      :MODE
      if ($gettok($5,1,33) === %n0) { hadd %hr $+(%i1,%4,$puttok(%hi,$puttok($5,%n1,1,33),5,44)) %hv | goto del }
      inc %i2 | continue
      :KICK
      if ($5 === %n0) { hadd %hr $+(%i1,%4,$puttok(%hi,%n1,5,44)) %hv | goto del }
      inc %i2 | continue
      :LIST | :JOIN | :PART | inc %i2 | continue

      :del | if ($gettok($hget(cck.H,QBUSY),1-5,32) != $replace(%hi,$chr(44),$chr(32))) { hdel %h %hi } | else { inc %i2 }
    }
    inc %i1
  }
  %i1 = 1
  while ($hget(%hr,%i1).item) {
    hadd cck.HQ $+ $gettok($v1,1,44) $gettok($v1,2-,44) $hget(%hr,$v1)
    inc %i1
  }
  hfree %hr
}

; +++ QUEUE / REMOVE
; IN32 $1 = network $2 = command $3 = par1 $4 = switch $5 = par2 (wildcards allowed)
alias cck.queue.rem {
  var %4 = $chr(44), %wmi = $+($1,%4,$2,%4,$3,%4,$4,%4,$5), %i = 1, %h
  while (%i < 10) {
    %h = cck.HQ $+ %i | while ($hfind(%h,%wmi,1,w)) { hdel %h $v1 }    
    inc %i
  }
}

; +++ QUEUE / QUEUE CLEAN (current connection)
; removes entries at parts/quits/kicks (ban only if the banmask has a nick)
; IN32 $1 = network $2 = optional channel to force as not present (mIRC IAL not updated yet)
alias cck.queue.clean {
  var %wm = $+($1,chr(44),*), %i1 = 1, %hi, %hv, %n
  while (%i1 < 10) {
    var %h = cck.HQ $+ %i1, %i2 = 1
    while ($hfind(%h,%wm,%i2,w)) {
      %hi = $v1 | goto $gettok(%hi,2,44)

      :WHOIS | %n = $gettok(%hi,3,44) | goto check
      :MSG | :NOTICE | :DESCRIBE
      %n = $gettok(%hi,3,44) | if (%n !isin $chantypes) { goto check }
      inc %i2 | continue
      :MODE | %n = $gettok($gettok(%hi,5,44),1,33) | goto check
      :KICK | %n = $gettok(%hi,5,44) | goto check
      :LIST | :JOIN | :PART | inc %i2 | continue

      :check
      if (!$cck.onchan(*,$1,%n,$2)) { hdel %h %hi } | else { inc %i2 }
    }
    inc %i1
  }
  cck.queue.checkbusy
}

; +++ QUEUE / WIPE ALL FOR GIVEN NETWORK
; IN32 $1 = network
alias cck.queue.remnet {
  var %i = 1 | while (%i < 10) { hdel -w cck.HQ $+ %i $1 $+ ,* | inc %i }
  cck.queue.checkbusy
}

; +++ QUEUE / GET STATUS
alias cck.queue.getstatus {
  var %i = 9, %list
  while (%i) { if ($hget(cck.HQ $+ %i,0).item) { %list = %list $+(%i,:,$v1) } | dec %i }
  return $iif(%list,%list,empty)
}

; +++ QUEUE / PROCESSING
; IN32 $1 = ON or OFF (optional, if not specified, status ON/OFF will be returned) $2 = SILENT (optional - no report)
alias cck.queue.process {
  if (!$1) { return $hget(cck.H,QPROC) }
  if ($hget(cck.H,QPROC) == $1) { return }
  goto $1
  :ON
  hadd cck.H QPROC ON | cck.diaMAIN.upd Session QueueProcess ON | cck.queue.donext
  if (!$2) { cck.echo+ QUEUE: Processing ON. } | return
  :OFF
  hadd cck.H QPROC OFF | cck.diaMAIN.upd Session QueueProcess OFF
  if (!$2) { cck.echo+ QUEUE: Processing OFF. } | return
}

;===================================================================================================
; IRC FUNCTION BASE
;===================================================================================================

; +++ FUNCTION / WHOIS CHANNEL
; IN32 $1 = priority 1-9 $2 = network $3 = channel $4 = sysdata
alias cck.whoischan {
  var %cid = $cck.net2cid($2) | if (!%cid) { return } | if ($cid != %cid) { scid %cid }
  var %i = 1, %list = $replace($hget(cck.HConfig,ExcludeNicks),<ME>,$me), %s = $iif($istok(KEY MENU,$4,32),1,0)
  while ($nick($3,%i)) {
    var %n = $v1 | if ($istok(%list,%n,32)) { inc %i | continue }
    if (!%s) && ($cck.exclude($2,%n)) { inc %i | continue }
    cck.queue.add $1 $2 WHOIS %n - $iif($address(%n,0),$gettok($v1,2-,33),-) $4
    inc %i
  }
}

; +++ FUNCTION / CHECK IF NICK SHOULD BE CHECKED 
; IN32 $1 = @ or % or + or * $2 = network $3 =nick $4 = optional channel to force as not present (mIRC IAL not updated yet)
; $1 is to exclude Operators/Halfops/Voices, * means don't exclude them
; OUT32 $1 = 1 (check user|user present) or 0 (don't check user|user not present)
alias cck.onchan {
  var %cid = $cck.net2cid($2) | if (!%cid) { return 0 } | if ($cid != %cid) { scid %cid }
  var %i = 1, %x = $1, %count = 0
  while ($comchan($3,%i)) {
    var %c = $v1 | if (%c == $4) { inc %i | continue }
    if (!$cck.CheckChans.Check($2,%c,ANY)) { inc %i | continue }
    if (@ isin %x) { if ($3 isop %c) { return 0 } }
    if (% isin %x) { if ($3 ishop %c) { return 0 } }
    if (+ isin %x) { if ($3 isvoice %c) { return 0 } }
    inc %count | inc %i
  }
  if (%count) { return 1 } | return 0
}

; +++ FUNCTION / GET LIST OF THE SCRIPT-ACTIVE CHANNELS FOR THE GIVEN NICK / PERFORM COMMAND ON THEM
; Requires also +o
; IN32 $1 = network $2 = nick $3 = command $4 = -switches or <none> $5 = parameters ($3- optional)
; OUT32 $result = list channels
alias cck.mychans {
  var %cid = $cck.net2cid($1) | if (!%cid) { return 0 } | if ($cid != %cid) { scid %cid }
  var %i = 1, %list, %c, %list
  while ($comchan($2,%i)) {
    %c = $v1
    if ($me !isop %c) || (!$cck.CheckChans.Check($1,%c,ANY)) { inc %i | continue }
    %list = %list %c | if ($3 != $null) { $3 $iif($4 != <none>,$4,$null) %c (04CCK) $5- }
    inc %i
  }
  return %list
}

; +++ FUNCTION / GET TAG-REPLACED WARN OR KICK MESSAGE FOR GIVEN USER
; IN32 $1 = WARN or KICK or BAN $2 = network $3 = nick $4- = warn or kick message
alias cck.actmsg {
  var %act = $iif($1 == BAN,KICK,$1)
  return $replace($hget(cck.HConfig,%act $+ Msg),<BADCHANS>,$4-,<MYCHANS>,$cck.mychans($2,$3))
}

; +++ FUNCTION / PERFORM ACTION ON USER
; IN32 $1 = WARN or KICK or BAN $2 = network $3 = nick $4 = user@host $5- = warn/kickmsg
; OUT32 $1 = 1 (done) or 0 (nothingtodo)
alias cck.netwarnkickban {
  var %cid = $cck.net2cid($2) | if (!%cid) { return 0 } | if ($cid != %cid) { scid %cid }
  var %i = 1, %a = *!*@ $+ $gettok($4,2,64), %count = 0
  while ($comchan($3,%i)) {
    var %c = $v1
    if ($me isop %c) {
      inc %count
      if ($1 == WARN) { cck.queue.add 4 $2 MSG $3 - - - $5- | return %count }
      elseif ($1 == BAN) { cck.queue.add 8 $2 MODE %c +b %a - - | cck.kickclones $2 %c %a $5- }
      elseif ($1 == KICK) { cck.kickclones $2 %c %a $5- }
    }
    inc %i
  }
  return %count
}

; +++ FUNCTION / KICK CLONES
; IN32 $1 = network $2 = channel $3 = mask $4- = kickmsg
; Output: $result = amount kicks
alias cck.kickclones {
  var %cid = $cck.net2cid($1) | if (!%cid) { return 0 } | if ($cid != %cid) { scid %cid }
  if ($me !isop $2) { return 0 }
  var %i = 1 | while ($ialchan($3,$2,%i).nick) { cck.queue.add 7 $1 KICK $2 - $v1 - $4- | inc %i }
  return $calc(%i - 1)
}

; +++ FUNCTION / SPLIT WHOIS CHANNELPREFIXES FROM CHANNELNAME
; IN32 $1 = network $2 = [prefixes]<channelname>
; OUT32 $result = INVALID or $1 = prefixes $2 = channelname
; notes:
; prefix < = channel mode +D and the whoissed user is hidden
; prefix - = when user mode +d,  doesnt receive text notice action (channel PRIVMSG)
; prefix ! = when your server has accepted part/kick but the other server hasn't, when the servers aren't synced at the exact time you do a whois
alias cck.getprefixchan {
  var %cid = $cck.net2cid($1) | if (!%cid) { return INVALID } | if ($cid != %cid) { scid %cid }
  var %total = $len($2), %i = 1
  while (%i <= %total) {
    var %char = $mid($2,%i,1) | if (%char isin $prefix $+ -<!) { inc %i | continue }
    if (%char !isin $chantypes) { inc %i | continue }
    var %chan = $mid($2,%i) | if (%i == 1) { return <none> %chan } | else { return $left($2,$calc(%i - 1)) %chan } 
    inc %i
  }
  return INVALID
}

; +++ FUNCTION / GET CID VALUE FOR GIVEN NETWORK
alias cck.net2cid {
  var %total = $scon(0), %i = 1
  while (%i <= %total) { if ($scon(%i).network == $1) && ($scon(%i).status == connected) { return $scon(%i) } | inc %i }
  return 0
}

; +++ FUNCTION / PARSE RAW MODE STRING
; Input: $1 = network $2- = raw mode string
; Output: $result = NOTFOUND or $1 = name of @window layout:
; case USER: USER <modeflag> <modetextlabel|UNKNOWN> <nick or mask>
; case CHAN: CHAN <modeflag> <modetextlabel|UNKNOWN> <optional value>
alias cck.ChanModeParse {
  var %cid = $cck.net2cid($1) | if ($cid != %cid) { scid %cid }
  var %net = $1, %rmf = $2, %rmp = $3-, %total = $len(%rmf), %i = 1, %wr = $rwin, %set, %ipar = 0
  while (%i <= %total) {
    var %c = $mid(%rmf,%i,1)
    if ($istok(+ -,%c,32)) { var %set = %c | inc %i | continue }
    if (!%set) { inc %i | continue }
    var %type = $cck.ChanModeType(%net,%c) | if (!%type) { inc %i | continue }
    var %flag = $+(%set,%c), %mode =  $cck.flag2mode(%flag) | if (!%mode) { var %mode = UNKNOWN }
    goto %type
    :A | inc %ipar | aline %wr USER %flag %mode $gettok(%rmp,%ipar,32) | inc %i | continue
    :B | inc %ipar | aline %wr CHAN %flag %mode $gettok(%rmp,%ipar,32) | inc %i | continue
    :C
    if (%set == +) { inc %ipar | aline %wr CHAN %flag %mode $gettok(%rmp,%ipar,32) } | else { aline %wr CHAN %flag %mode }
    inc %i | continue
    :D | aline %wr CHAN %flag %mode | inc %i | continue
  }
  return %wr
}

; +++ FUNCTION / CHANNEL MODES - GET TYPE
; Input: $1 = network $2 = flag
; Output: $result = 0 or $1 = A or B or C or D
alias cck.ChanModeType {
  var %net = $1, %flag = $2, %cid = $cck.net2cid($1) | if ($cid != %cid) { scid %cid }
  var %i = 1
  while ($gettok($chanmodes,%i,44) != $null) {
    if (%flag isincs $v1) {
      var %type = $gettok(A B C D,%i,32)
      if (%type) { return %type }
      return 0
    }
    inc %i
  }
  return 0
}

; +++ FUNCTION / MODE FLAG <-> NAME CONVERSION
alias cck.mode2flag { return $gettok($cck.flaglist,$findtok($cck.modelist,$1,1,32),32) }
alias cck.flag2mode { return $gettok($cck.modelist,$findtokcs($cck.flaglist,$1,1,32),32) }
alias cck.modelist {
  return OP DEOP HALFOP DEHALFOP VOICE DEVOICE BAN UNBAN EXCEPT UNEXCEPT INVEX DEINVEX ADMIN DEADMIN OWNER DEOWNER $&
    MODERATED DEMODERATED KEYED UNKEYED SECRET UNSECRET
}
alias cck.flaglist { return +o -o +h -h +v -v +b -b +e -e +I -I +a -a +q -q +m -m +k -k +s -s }

Comments

  (6)  RSS
Atr
Comments: 60
 
mIRC Snippet:  Channel Checker 1.07
Posted on Aug 8, 2009 9:10 am
So from your description, anyone who has a swear word in their whois can't join any channel you're op in?
Cracker200
Comments: 257
 
mIRC Snippet:  Channel Checker 1.07
Posted on Aug 8, 2009 10:22 am
Yes Hm.... Looks like it to me But thats just dumb though i mean it's a good snippet but half the people On chat servers have Bad words in there /whois
Cracker200
Comments: 257
 
mIRC Snippet:  Channel Checker 1.07
Posted on Aug 8, 2009 10:31 am
Errm Can some one tell me where i post if i need some help on something ?
Atr
Comments: 60
 
mIRC Snippet:  Channel Checker 1.07
Posted on Aug 8, 2009 10:35 am
@Cracker200, try the forums :)
Cracker200
Comments: 257
 
mIRC Snippet:  Channel Checker 1.07
Posted on Aug 8, 2009 10:44 am
Um.... where is the forums lmao? NVM lol i found it but how do i post on it ???? :) sorry i am a n00b to this site xD
Qc
Comments: 14
 
mIRC Snippet:  Channel Checker 1.07
Posted on Aug 8, 2009 12:15 pm
If half the people of (your?) chat servers have bad words in their whois, and you have no problem with it, then you do not need a script.
If that isn't obvious, ofcourse. :)

The scope of this script is far beyond bad/swear words in whois.
You want to know more about the people visiting your channels?
You want to know on which other channels they are, maybe to visit them too?
Your channel is pestered by a bunch lamers and they all seem to be on a certain channel (whatever it is named, bad/swear words or not)?
You want to keep track of all people that are op on other channels?

This script is essentially nothing more than a versatile filter that automatically grabs on request-available data for you, filters it according to your information needs, and can act, if desired. It gives you a much higher awareness of the people on your channels. And that is its purpose. 'Check' Channels.

Commenting Options

Register or Login to Hawkee.com or use your Facebook or Twitter account by clicking the corresponding button below.

  
Bottom