####################################################
# by wiebe @ QuakeNet
#
# adds bans properly, see below
#
####################################################

####################################################
#
# newchanban / newban basicly do "pushmode ..; flushmode ..; putkick ..
# when you ban 5 users using newban this happens (+dynamicbans):
# mode +b host1
# kick nick1
# mode +b host2
# kick nick2
# mode +b host3
# kick nick3
# mode +b host4
# kick nick4
# mode +b host5
# kick nick5
# this takes 2 * 5 = 10 commands
#
# while it should do it neat, like this:
# mode +bbbbb host1 host2 host3 host4 host5
# kick nick1
# kick nick2
# kick nick3
# kick nick4
# kick nick5
# this takes 1 + 5 = 6 commands (4 commands/lines less)
####################################################

####################################################
# newban:ban
####################################################
proc newban:ban { ban creator comment {lifetime ""} {options ""} } {
  set b $ban; set e $creator; set r $comment; set l $lifetime; set o $options
  set o [string tolower $o]; if {[string equal $o ""]} { set o "none" }
  # hidden ban, forward
  if {[string match @*!*@* $b] && [info procs hiddenbans:checkmask] != ""} {
    newban $b $e $r $l $o
    hiddenbans:checkmask $b
    return 1
  }
  if {[info exists ::max-bans]} { set h ${::max-bans} } else { set h "45" }
  set g 0;  set d ""
  if {[isban $b] || [isban &$b]} { return 0 }
  foreach c [channels] {
    set f 1
    if {![botisop $c] && ![botishalfop $c]} { set f 0 }
    if {[llength [chanbans $c]] >= $h} { set f 0 }
    if {[newban:set $c $b]} { set f 0 }
    if {![newban:activate $c $b]} { set f 0 }
    if {[string equal $o "sticky"]} { set f 1 }
    if {$f} { set g 1; pushmode $c +b $b }
    if {![channel get $c dynamicbans]} { lappend d $c }
  }
  if {$g} {
    foreach n $d { channel set $n +dynamicbans }
    newban &$b $e $r $l $o
    foreach n $d { channel set $n -dynamicbans }
  } else { newban $b $e $r $l $o }
  putallbots "nb $b"
  return 1
}


####################################################
# newban:mode
#
# check for &ban in banlist and change it
####################################################
bind mode -|- "% +b" newban:mode
proc newban:mode { nick uhost handle chan mode ban } {
  if {![isban &$ban]} { return 0 }

  if {[info exists ::max-bans]} { set mb ${::max-bans} } else { set mb "45" }
  foreach c [channels] {
    set b 1
    set bc [llength [chanbans $c]]
    if {![botisop $c] && ![botishalfop $c]} { set b 0 }
    if {$bc >= $mb} { set b 0 }
    if {[newban:set $c $ban]} { set b 0 }
    if {![newban:activate $c $ban]} { set b 0 }
    if {!$b} { continue }
    return 0
  }
  set now [clock seconds]
  foreach b [banlist] {
    set h [lindex $b 0]
    if {![string equal -nocase &$ban $h]} { continue }
    set r [lindex $b 1]
    set e [lindex $b 2]
    set c [lindex $b 5]
    set l [expr ($e - $now) / 60]
    set s "none"
    if {[isbansticky $b]} { set s "sticky" }
    newban $ban $c $r $l $s
    killban $h
    return 0
  }
}


####################################################
# newban:time
#
# check for &bans and activate them
####################################################
bind time -|- "* * * * *" newban:time
proc newban:time { mi ho da mo ye } {
  set now [clock seconds]
  foreach ban [banlist] {
    set h [lindex $ban 0]
    if {![string match -nocase &* $h]} { continue }
    set a [lindex $ban 3]
    if {[expr $now - $a] < "120"} { continue }
    set r [lindex $ban 1]
    set e [lindex $ban 2]
    set c [lindex $ban 5]
    set l [expr ($e - $now) / 60]
    set s "none"
    if {[isbansticky $h]} { set s "sticky" }
    killban $h
    set h [string range $h 1 end]
    newban $h $c $r $l $s
  }
}


####################################################
# newban:activate
#
# return 1 if ban needs to be activated
####################################################
proc newban:activate { chan ban } {
  set ban [newban:lower $ban]
  regsub -all {[][\\]} $ban {\\\0} ban
  set h 0
  foreach nick [chanlist $chan] {
    if {[isbotnick $nick]} { continue }
    if {[onchansplit $nick $chan]} { continue }
    set mask $nick![getchanhost $nick $chan]
    set mask [newban:lower $mask]
    if {![string match $ban $mask]} { continue }
    set hand [nick2hand $nick $chan]
    if {[matchattr $hand omn|omn $chan] && [channel get $chan dontkickops]} { continue }
    set h 1
    if {[isop $nick $chan]} { pushmode $chan -o $nick }
    if {[ishalfop $nick $chan]} { pushmode $chan -h $nick }
  }
  return $h
}


####################################################
# newban:set
#
# returns 1 if the ban is already set
####################################################
proc newban:set { chan ban } {
  if {[ischanban $ban $chan]} { return 1 }
  set ban [newban:lower $ban]
  foreach b [chanbans $chan] {
    set b [lindex $b 0]
    set b [newban:lower $b]
    regsub -all {[][\\]} $b {\\\0} b
    if {[string match $b $ban]} { return 1 }
  }
  return 0
}


####################################################
# newban:lower
#
# change text to lower, rfc1459 if needed
####################################################
proc newban:lower { text } {
  global rfc-compliant
  if {[info exists rfc-compliant] && [string equal ${rfc-compliant} "1"]} {
    set text [string map "\\{ \[ \\} \] ~ ^ \\\\ |" $text]
  }
  set text [string tolower $text]
  return $text
}


####################################################
# newban:bot
####################################################
bind bot -|- nb newban:bot
proc newban:bot { b c t } {
  if {![islinked $b]} { return 0 }
  if {![string equal $c "nb"]} { return 0 }
  set t [split $t]; set b [lindex $t 0]
  if {[string equal $b ""]} { return 0 }
  if {![isban $b] && ![isban &$b]} { return 0 }
  foreach e [banlist] {
    set m [lindex $e 0]; set r [lindex $e 1]; set z [lindex $e 5]
    if {![string equal -nocase $m $b] && ![string equal -nocase $m &$b]} { continue }
    if {[isbansticky $b]} { set o "sticky" } else { set o "none" }
    set l [expr ([lindex $e 2] - [clock seconds]) / 60]
    if {[info exists ::max-bans]} { set h ${::max-bans} } else { set h "45" }
    set g 0;  set d ""
    foreach c [channels] {
      set f 1
      if {![botisop $c] && ![botishalfop $c]} { set f 0 }
      if {[newban:set $c $b]} { set f 0 }
      if {![newban:activate $c $b]} { set f 0 }
      if {[string equal $o "sticky"]} { set f 1 }
      if {[llength [chanbans $c]] >= $h} { set f 0 }
      if {$f} { set g 1; pushmode $c +b $b }
      if {![channel get $c dynamicbans]} { lappend d $c }
    }
    if {$g} {
      foreach n $d { channel set $n +dynamicbans }
      newban &$b $z $r $l $o
      foreach n $d { channel set $n -dynamicbans }
    } else { newban $b $z $r $l $o }
    return 1
  }
}


set scriptdb(newban) {
  "improvement of the eggdrop newban command, multiple bans in a short time are handled correct"
}

