#by wiebe @ QuakeNet

#################################################################
#config
#################################################################

#default delay settings (minutes)
set autovoicealldefault(delay) 3

#default users setting
#how many to voice in 1 go
set autovoicealldefault(users) 3

#default max setting
#maximum number of voiced users on the channel
set autovoicealldefault(max) 50

#default hidden setting
#voice hidden users (1=yes,0=no)
set autovoicealldefault(hidden) 1

#################################################################
#config end
#################################################################

#################################################################
#code
#################################################################

#setting flags
setudef flag autovoiceall
setudef flag autovoiceall-hidden
setudef int autovoiceall-delay
setudef int autovoiceall-users
setudef int autovoiceall-max


#proc to count voiced users
proc autovoiceall:voiced { chan } {
  if { ![validchan $chan] } { return 0 }
  set voiced 0
  foreach user [chanlist $chan] {
    if { ([isvoice $user $chan]) && (![isop $user $chan]) && (![ishalfop $user $chan]) } {
      incr voiced 1
    }
  }
  return $voiced
}


#proc to return regular users
proc autovoiceall:reg { chan } {
  if { ![validchan $chan] } { return 0 }
  set reg ""
  foreach user [chanlist $chan] {
    if { (![isvoice $user $chan]) && (![isop $user $chan]) && (![ishalfop $user $chan]) } {
      lappend reg $user
    }
  }
  return [join $reg]
}


#bind to start the check each minute
bind time - "* * * * *" autovoiceall.allcheck

#autovoiceall.allcheck, check all chans
proc autovoiceall.allcheck { mi ho da mo ye } {
  global autovoicealldefault autovoicealltime server

  if { $server == "" } { return 1 }

  set now [clock seconds]
  if { [info exist now] } {

#loop through channels
    foreach chan [channels] {

#+autovoiceall is set
      if { [channel get $chan autovoiceall] } {

#bot is +o or +h
        if { ([botisop $chan]) || ([botishalfop $chan]) } {

#get and check delay
          set delay [expr $autovoicealldefault(delay) * 60]
          if { [channel get $chan autovoiceall-delay] != "" } {
            set delay [expr [channel get $chan autovoiceall-delay] * 60]
          }
          if { ($delay < 0) || (![info exist delay]) } {
            set delay [expr 3 * 60]
          }

          if { ![info exist autovoicealltime($chan)] } { set autovoicealltime($chan) 1 }
          set last $autovoicealltime($chan)
          if { $last == "1" } {
            set autovoicealltime($chan) $now
            autovoiceall.check $chan
          }
          if { $last != "1" } {
            if {  $now >= [expr $last + $delay] } {
              set autovoicealltime($chan) $now
              autovoiceall.check $chan
            }
          }
          if { [info exist last] } { unset last }
          if { [info exist delay] } { unset delay }
        }
      }
    }
  }
}


#autovoiceall.check chan, check chan
proc autovoiceall.check { chan } {
  global autovoicealldefault autovoiceallhidden

  if { ![validchan $chan] } { return 0 }

#check if +autovoiceall is set
  if { ![channel get $chan autovoiceall] } { return 0 }

#check if bot is +o or +h
  if { (![botisop $chan]) && (![botishalfop $chan]) } { return 0 }

#get and check settings users
  set users [channel get $chan autovoiceall-users]
  if { ($users < 0) || (![info exist users]) } { set users $autovoicealldefault(users) }
  if { (![string is digit $users]) || $users < 0 || (![info exist users]) } { set users 6 }

#get and check settings max
  set max [channel get $chan autovoiceall-max]
  if { ($max < 0) || (![info exist max]) } { set max $autovoicealldefault(max) }
  if { (![string is digit $max]) || $max < 0 || (![info exist max]) } { set max 10 }

  set voiced [autovoiceall:voiced $chan]
  set regulars [autovoiceall:reg $chan]
  if { $voiced >= $max && $max > 0 } { return 1 }

#check if we need to check for hidden users
  if { [channel get $chan autovoiceall-hidden] && [string match *d* [lindex [split [string tolower [getchanmode $chan]]] 0]] && [llength $regulars] < $users && (([expr $voiced + [llength $regulars]] < $max && $max > 0) || ($max == 0)) } {
#checking hidden users
    set autovoiceallhidden($chan) "1"
    set autovoiceallhidden($chan,max) "$max"
    set autovoiceallhidden($chan,users) "$users"
    puthelp "NAMES -d $chan"
  } else {
#voice some users
    set x 0
    foreach nick [split $regulars] {
      if { $users == 0 || $x < $users } {
        if { $max == 0 || [expr $voiced + $x] < $max } {
          pushmode $chan +v [join [split $nick]]
          incr x
        }
      }
    }
  }
}


#355 <you> = <chan> :<hidden users>
bind raw -|- "355" autovoiceall.hidden

proc autovoiceall.hidden { server raw ar } {
  global autovoiceallhidden
  set chan [lindex [split $ar] 2]
  set users [join [lrange [split $ar] 3 end]]
  regsub -all \\\\ $users \\\\\\\\ users
  set users [string trimleft [join [lrange [split $users] 0 end]] :]
#set users [join [lrange [split $users :] 0 end]]
#check var
  if { [info exist autovoiceallhidden($chan)] } {
    if { $autovoiceallhidden($chan) == "1" } {
      autovoiceall.check.hidden $chan $users
      unset autovoiceallhidden($chan)
    }
  }
  return 0
}


#autovoiceall.check.hidden chan
proc autovoiceall.check.hidden { chan nicks } {
  global autovoicealldefault autovoiceallhidden {modes-per-line}

  set nicks "[join [split $nicks]]"

#check if +autovoiceall is set
  if { ![channel get $chan autovoiceall] } { return 1 }

#check if bot is +o or +h
  if { (![botisop $chan]) && (![botishalfop $chan]) } { return 1 }

#get and check settings users
  set users [channel get $chan autovoiceall-users]
  if { ($users < 0) || (![info exist users]) } { set users $autovoicealldefault(users) }
  if { (![string is digit $users]) || $users < 0 || (![info exist users]) } { set users 6 }

#get and check settings max
  set max [channel get $chan autovoiceall-max]
  if { ($max < 0) || (![info exist max]) } { set max $autovoicealldefault(max) }
  if { (![string is digit $max]) || $max < 0 || (![info exist max]) } { set max 10 }

  set voiced [autovoiceall:voiced $chan]
  set regulars [autovoiceall:reg $chan]
  if { $voiced >= $max && $max > 0 } { return 1 }

  set x 0
  set m 0
  set mode "+"
  foreach nick [split $regulars] {
    if { $users == 0 || $x < $users } {
      if { $max == 0 || [expr $voiced + $x] < $max } {
        set mode "[lindex [split $mode] 0]v [join [lrange [split $mode] 1 end]] $nick"
        incr m
        incr x
        if { $m == ${modes-per-line} } {
          set m 0
          puthelp "MODE $chan $mode"
          set mode "+"
        }
      }
    }
  }
  if { $users == 0 || $x < $users } {
    if { $max == 0 || [expr $voiced + $x] < $max } {
      foreach nick $nicks {
        if { $users == 0 || $x < $users } {
          if { $max == 0 || [expr $voiced + $x] < $max } {
            set mode "[lindex [split $mode] 0]v [join [lrange [split $mode] 1 end]] $nick"
            incr m
            incr x
            if { $m == ${modes-per-line} } {
              set m 0
              puthelp "MODE $chan $mode"
              set mode "+"
            }
          }
        }
      }
    }
  }
  if { $mode != "+" } {
    puthelp "MODE $chan $mode"
  }
}


proc autovoiceall.info { chan } {
  global autovoicealldefault

#check if autovoiceall is on or off
  if { ![channel get $chan autovoiceall] } {
    set status off
  } else {
    set status on
  }

#get and check settings delay
  set delay [channel get $chan autovoiceall-delay]
  if { (![string is digit $delay]) || $delay <= 0 || (![info exist delay]) } {
    set delay $autovoicealldefault(delay)
    channel set $chan autovoiceall-delay $delay
  }
  if { (![string is digit $delay]) || $delay <= 0 || (![info exist delay]) } {
    set delay 3
    channel set $chan autovoiceall-delay $delay
  }

#get and check settings users
  set users [channel get $chan autovoiceall-users]
  if { (![string is digit $users]) || $users <= 0 || (![info exist users]) } {
    set users $autovoicealldefault(users)
    channel set $chan autovoiceall-users $users
  }
  if { (![string is digit $users]) || $users <= 0 || (![info exist users]) } {
    set users 10
    channel set $chan autovoiceall-users $users
  }

#get and check settings max
  set max [channel get $chan autovoiceall-max]
  if { (![string is digit $max]) || $max < 0 || (![info exist max]) } {
    set max $autovoicealldefault(max)
    channel set $chan autovoiceall-max $max
  }
  if { (![string is digit $max]) || $max < 0 || (![info exist max]) } {
    set max 3
    channel set $chan autovoiceall-max $max
  }

#get and check setting for hidden users
  if { ![channel get $chan autovoiceall-hidden] } {
    set hidden 0
  } else {
    set hidden 1
  }
  return "status=$status delay=$delay users=$users max=$max hidden=$hidden"
}


proc autovoiceall.set { ar } {
  global autovoicealldefault
  set chan [lindex [split $ar] 0]

#get and check settings delay
  set delay [lindex [split $ar] 1]
  if { $delay == "-" } { set delay $autovoicealldefault(delay) }
  if { (![string is digit $delay]) || $delay <= 0 || (![info exist delay]) } {
    set delay $autovoicealldefault(delay)
  }
  if { (![string is digit $delay]) || $delay <= 0 || (![info exist delay]) } {
    set delay 3
  }
  channel set $chan autovoiceall-delay $delay

#get and check settings users
  set users [lindex [split $ar] 2]
  if { $users == "-" } { set users $autovoicealldefault(users) }
  if { (![string is digit $users]) || $users <= 0 || (![info exist users]) } {
    set users $autovoicealldefault(users)
  }
  if { (![string is digit $users]) || $users <= 0 || (![info exist users]) } {
    set users 10
  }
  channel set $chan autovoiceall-users $users

#get and check settings max
  set max [lindex [split $ar] 3]
  if { $max == "-" } { set max $autovoicealldefault(max) }
  if { (![string is digit $max]) || $max < 0 || (![info exist max]) } {
    set max $autovoicealldefault(max)
  }
  if { (![string is digit $max]) || $max < 0 || (![info exist max]) } {
    set max 3
  }
  channel set $chan autovoiceall-max $max

  set hidden [lindex [split $ar] 4]
  if { $hidden == "-" } { set hidden $autovoicealldefault(hidden) }
  if { $hidden != 1 && $hidden != 0 } { set hidden 0 }
  if { $hidden == 1 } { channel set $chan +autovoiceall-hidden } else { channel set $chan -autovoiceall-hidden }

}


bind dcc - autovoiceall autovoiceall.dcc

proc autovoiceall.dcc { handle idx ar } {
  global lastbind
  set chan [lindex [split $ar] 0]
  if { ![validchan $chan] } {
    putidx $idx "autovoiceall: error, $lastbind <chan> <on|off|info|set> \[delay|-\] \[users|-\] \[max|-\] \[hidden|-\]"
    return
  }
  set cmd [lindex [split $ar] 1]
  if { $cmd == "" } {
    putidx $idx "autovoiceall: error, $lastbind <chan> <on|off|info|set> \[delay|-\] \[users|-\] \[max|-\] \[hidden|-\]"
    return
  }
  if { (![matchattr $handle m|- $chan]) && (![matchattr $handle -|m $chan]) } {
   putidx $idx "autovoiceall: you have no access for $chan"
   return
  }
  if { $cmd == "info" } {
    putidx $idx "autovoiceall: settings for $chan [autovoiceall.info $chan]"
  } elseif { $cmd == "set" } {
    autovoiceall.set "$chan [join [lrange [split $ar] 2 end]]"
    channel set $chan +autovoiceall
    putidx $idx "autovoiceall: settings for $chan [autovoiceall.info $chan]"
  } elseif { $cmd == "off" } {
    channel set $chan -autovoiceall
    putidx $idx "autovoiceall: off for $chan"
  } elseif { $cmd == "on" } {
    autovoiceall.set "$chan [join [lrange [split $ar] 2 end]]"
    channel set $chan +autovoiceall
    putidx $idx "autovoiceall: on for $chan with settings [autovoiceall.info $chan]"
  } else {
    putidx $idx "autovoiceall: error, $lastbind <chan> <on|off|info|set> \[delay|-\] \[users|-\] \[max|-\] \[hidden|-\]"
  }
}


#bind msg mn|mn autovoiceall autovoiceall:msg

proc autovoiceall:msg { nick uhost handle text } {
  set chan [lindex [split $text] 0]
  set cmd [lindex [split $text] 1]
  if { (![validchan $chan] || ![matchattr $handle mn|mn $chan]) && ![string equal $chan ""] } {
    lappend output "$chan\017 is an unknown channel or you have no access on it."
  } elseif { [string equal $cmd ""] } {
    lappend output "usage: autovoiceall <chan> <on|off|info|set> \[delay|-\] \[users|-\] \[max|-\] \[hidden|-\]"
  } elseif { [string equal $cmd info] } {
    lappend output "autovoiceall settings for $chan [autovoiceall.info $chan]"
  } elseif { [string equal $cmd set] } {
    autovoiceall.set "$chan [join [lrange [split $text] 2 end]]"
    channel set $chan +autovoiceall
    lappend output "autovoiceall settings for $chan [autovoiceall.info $chan]"
  } elseif { [string equal $cmd off] } {
    channel set $chan -autovoiceall
    lappend output "autovoiceall off for $chan"
  } elseif { [string equal $cmd on] } {
    autovoiceall.set "$chan [join [lrange [split $text] 2 end]]"
    channel set $chan +autovoiceall
    lappend output "autovoiceall on for $chan with settings [autovoiceall.info $chan]"
  } else {
    lappend output "usage: autovoiceall <chan> <on|off|info|set> \[delay|-\] \[users|-\] \[max|-\] \[hidden|-\]"
  }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
}

