#by wiebe @ QuakeNet


#+banlist		(enable/disable script)
# banlist-delay		(check every N minutes)
# banlist-max		(number of bans to leave set)
#+banlist-lock		(enable/disabel locking)
# banlist-lockmode	(modes to set when locking imrD)
#+banlist-msg		(when locking, inform channel)



#flags
setudef flag banlist
setudef flag banlist-lock
setudef flag banlist-msg
setudef int banlist-delay
setudef int banlist-max
setudef str banlist-lockmode



#time
bind time -|- * banlist:time

proc banlist:time { mi ho da mo ye } {

#check channels
  foreach c [channels] { banlist:checkchan $c }
}



#checkchan
proc banlist:checkchan { c } {
  global banlist

#max-bans is wrong
  if { ![info exists ::max-bans] } { return 0 }
  if { ![string is digit ${::max-bans}] } { return 0 }

  if { ![validchan $c] } { return 0 }
  if { ![botisop $c] && ![botishalfop $c] } { return 0 }
  if { ![channel get $c banlist] } { return 0 }

#get max setting, min 10
  set max [channel get $c banlist-max]
  if { $max < "10" || $max > ${::max-bans} } { return 0 }

  if { ![botisop $c] && ![botishalfop $c] } { return 0 }
  if { [llength [chanbans $c]] <= $max } {
#no ban checking needed, unlock if needed
    banlist:unlock $c
    return 0
  }

#delay check
  set delay [channel get $c banlist-delay]
  if { $delay < 1 } { return 0 }
  if { [info exists banlist($c,check)] && [expr ([unixtime] - $banlist($c,check)) / 60] < $delay } {
#no ban checking, lock if needed
    banlist:lock $c
    return 0
  }
  set banlist($c,check) [unixtime]

#remove bans
  set bc [llength [chanbans $c]]
  foreach b [chanbans $c] {
    set b [lindex $b 0]
#on internal banlist and sticky
    if { [isban $b $c] && [isbansticky $b $c] } { continue }
    incr bc -1
    pushmode $c -b $b
    if { [string equal $bc $max] } { break }
  }

#unlock
  if { $bc >= ${::max-bans} } { return 0 }
  banlist:unlock $c
}



#modes
bind mode -|- "% +b" banlist:mode
bind mode -|- "% -b" banlist:mode
bind mode -|- "% +o" banlist:mode
bind mode -|- "% +h" banlist:mode

proc banlist:mode { nick uhost handle chan mode victim } {
  if { ![info exists ::max-bans] } { return 0 }
  if { ![string is digit ${::max-bans}] } { return 0 }
  if { ![botisop $chan] && ![botishalfop $chan] } { return 0 }

#+b
  if { [string equal $mode +b] } {
    if { ![string equal ${::max-bans} [expr [llength [chanbans $chan]] +1]] } { return 0 }
    banlist:lock $chan

#-b
  } elseif { [string equal $mode -b] } {
    if { ![string equal ${::max-bans} [llength [chanbans $chan]]] } { return 0 }
    banlist:unlock $chan

#+o / +h
  } elseif { [string match {+[oh]} $mode] && [isbotnick $victim] } {
    banlist:checkchan $chan
  }
}



#raw
bind raw -|- "368" banlist:raw

proc banlist:raw { source numeric text } {
  if { ![string equal $numeric 368] } { return 0 }
  set chan [lindex [split $text] 1]
  if { ![validchan $chan] } { return 0 }
  if { ![botisop $chan] && ![botishalfop $chan] } { return 0 }
  banlist:checkchan $chan
}



#unlock
proc banlist:unlock { chan } {
  global banlist
  if { ![info exists ::max-bans] } { return 0 }
  if { ![string is digit ${::max-bans}] } { return 0 }
  if { ![channel get $chan banlist-lock] } { return 0 }
  set lockmode [channel get $chan banlist-lockmode]
  if { [string equal $lockmode ""] } { return 0 }
  set chanmode [lindex [split [getchanmode $chan]] 0]
  if { ![info exists banlist($chan,mode)] } { return 0 }
  foreach m [split $lockmode ""] {
    if { ![string match *$m* $chanmode] } { continue }
    if { ![string match {[imrD]} $m] } { continue }
    if { ![string match *$m* $banlist($chan,mode)] } { continue }
    pushmode $chan -$m
  }
  set banlist($chan,mode) ""
}



#lock
proc banlist:lock { chan } {
  global banlist
  if { ![info exists ::max-bans] } { return 0 }
  if { ![string is digit ${::max-bans}] } { return 0 }
  if { ![channel get $chan banlist-lock] } { return 0 }
  set lockmode [channel get $chan banlist-lockmode]
  if { [string equal $lockmode ""] } { return 0 }
  set chanmode [lindex [split [getchanmode $chan]] 0]
  set do 0
  foreach m [split $lockmode ""] {
    if { [string match *$m* $chanmode] } { continue }
    if { ![string match {[imrD]} $m] } { continue }
    if { [string match *$m* [lindex [split [getchanmode $chan]] 0]] } { continue }
    set do 1
    pushmode $chan +$m
    if { ![info exists banlist($chan,mode)] } { set banlist($chan,mode) "" }
    set banlist($chan,mode) $banlist($chan,mode)$m
  }
  if { $do && [channel get $chan banlist-msg] } {
    set delay [channel get $chan banlist-delay]
    puthelp "PRIVMSG $chan :>>> Channel ban/ignore list is full. Locking channel until some are removed by channel operators or automatic removal (in max. $delay minutes). <<<"
  }
}

