####################################################
# by wiebe @ QuakeNet
#
####################################################

# bind time, queue, empty then, compact messages?
# multibot
# no, this should be in the scripts

# target multiple channels
# use flag to enable or disable
# when setting show what each means
# param for flags, for relay to users, global|chan flags


# CHANNEL FLAGS FOR LOMN
# a  chanlev
# b  ban
# c  clone ban
# d
# e  expire channel bans
# f  flood/flud actions
# g  global bans?
# h  banlist
# i  censor ban
# j  censor chanban
# k  censor kick
# l  censor warn
# m  clearmode/mode
# n  netsplitbans
# o  out
# p
# q  queue
# r
# s  spamscan
# t  topic
# u  chan set
# v
# w  warn
# x  kick
# y
# z
# A
# B
# C
# D
# E  expire global bans
# F
# G
# H
# I
# J
# K
# L  halfop commands?
# M  master commands?
# N  owner commands?
# O  op commands?
# P  global halfop commands?
# Q  global master commands?
# R  global owner commands?
# S  global op commands?
# T
# U
# V
# W
# X
# Y
# Z

# GLOBAL FLAGS FOR M N
# 1  add/del user?
# 2  glev?
# 3  botnet linking etc?
# 4  global bans
# 5  add/del chans
# 6
# 7
# 8
# 9
# 0


setudef flag ircconsole
setudef int ircconsole-way
setudef str ircconsole-to
setudef str ircconsole-from
setudef str ircconsole-mask



####################################################
# ircconsole
#
# usage: ircconsole <chan|global|*> <level> <type> <text>
#
####################################################
proc ircconsole { chan level type text {hash ""} } {
  if {[string equal $text ""]} { return 0 }
  set way ""
  set tchan ""
  if {[ircconsole:repeat $chan $hash]} { return 0 }
#relay to chan
  if {![string equal -nocase $chan "global"] } {
    if {![string equal $chan "*"] && ![channel get $chan ircconsole]} { return 0 }
    set tchan [ircconsole:relaychan $chan $level $type $text]
    set way [lindex [split $tchan] 1]
    set tchan [lindex [split $tchan] 0]
  }
#relay to users
  ircconsole:relayuser $chan $level $type $text $way $tchan
}



####################################################
# ircconsole:repeat
# split this up?
# check at start, only add when actually relaying the message!
####################################################
proc ircconsole:repeat { chan hash } {
  if {[string equal $hash ""]} { return 0 }
  set chan [string tolower $chan]
  if {![validchan $chan] && ![string equal $chan "global"] && ![string equal $chan "*"]} { return 1 }
  set now [clock seconds]
  global ircconsoledb
  set p 10
  while {$p > 0} {
    if {[info exists ircconsoledb($chan,$p)]} {
      set h [split $ircconsoledb($chan,$p)]
      set t [lindex $h 0]
      set h [lindex $h 1]
      if {[string equal $hash $h] && [expr $now - $t] < 60} { return 1 }
    }
    incr p -1
  }
  set p 9
  while {$p > 0} {
    if {[info exists ircconsoledb($chan,$p)]} {
      set ircconsoledb($chan,[expr $p +1]) $ircconsoledb($chan,$p)
    }
    incr p -1
  }
  set ircconsoledb($chan,1) "$now $hash"
  return 0
}



####################################################
# ircconsole:relaychan
#
# relays to channel
#
####################################################
proc ircconsole:relaychan { chan level type text } {

  set way ""
  set channels $chan
  if {[string equal $chan "*"]} { set channels [channels] }

  set chans ""
  foreach c $channels {
# to chan
    set tc [channel get $c ircconsole-to]
    if {![validchan $tc]} { continue }
    if {![channel get $tc ircconsole]} { continue }
    if {![botonchan $tc]} { continue }
# alone
    if {[string equal [llength [chanlist $tc]] "1"]} { continue }
# only bots
    if {[string equal [llength [chanlist $tc b]] [llength [chanlist $tc]]]} { continue }
    if {[string match *m* [lindex [split [getchanmode $tc]] 0]] && ![botisop $tc] && ![botishalfop $tc] && ![botisvoice $tc]} { continue }

# from chan
    set fc [channel get $tc ircconsole-from]
    set fcc [ircconsole:lower $fc]
    set cc [ircconsole:lower $c]
    if {[string equal [lsearch [split $fcc] $cc] "-1"] && ![string equal $fc "*"]} {
      continue
    }
    set mask [channel get $c ircconsole-mask]
if {[string equal $mask ""]} { set mask "bckm" }
    if {![string match *\[$level\]* $mask] && ![string equal $level "*"] && ![string equal $mask "*"]} { continue }

    set tc [ircconsole:lower $tc]
    if {![string equal [lsearch -exact $chans $tc] "-1"]} { continue }
    lappend chans $tc

    set output "-$level- $type $chan $text"

    set way [channel get $tc ircconsole-way]
    if {[string match *N* [lindex [split [getchanmode $tc]] 0]]} { set way "0" }
    if {[string equal $way "1"]} {
      set cmd "wallchops"
    } elseif {[string equal $way "2"]} {
      set cmd "wallvoices"
    } elseif {[string equal $way "3"]} {
      set cmd "notice"
    } else {
      set cmd "privmsg"
      if {[string match *c* [lindex [split [getchanmode $tc]] 0]]} {
        set output [stripcodes bcru $output]
      }
    }
    if {[string equal [info procs $cmd] ""]} { puthelp "$cmd $tc :$output"
    } else { $cmd $tc $output puthelp "`- $type: " }
  }
  if {[string equal $chan "*"]} { return }
  return "$tc $way"
}



####################################################
# ircconsole:relayuser
#
# relays to users
#
####################################################
proc ircconsole:relayuser { chan level type text way tchan } {
  if {[string equal -nocase $chan "global"]} {
    set nicks [ircconsole:relayuserglobal $level]
    set output "-$level- $type: GLOBAL $text"
  } elseif {[string equal $chan "*"]} {
    set nicks [ircconsole:relayuserallchan $level]
    set output "-$level- $type: * $text"
  } elseif {[validchan $chan]} {
    set nicks [ircconsole:relayuserchan $chan $level $way $tchan]
    set output "-$level- $type: $chan $text"
  } else { return 0 }
  if {[string equal $nicks ""]} { return 0 }
  if {[string equal [info procs notice] ""]} { puthelp "NOTICE $nicks :$output"
  } else { notice $nicks $output puthelp "`- $type: " }
}



####################################################
# ircconsole:relayuserglobal
#
# gets nicks to relay global
#
####################################################
proc ircconsole:relayuserglobal { level } {
  set nicks ""
  foreach chan [channels] {
    if {![botonchan $chan]} { continue }
    foreach nick [chanlist $chan mn] {
      if {![string equal [lsearch -exact $nicks $nick] "-1"]} { continue }
      set handle [nick2hand $nick]
      set mask [ircconsole:get $handle "global"]
      if {![string match *\[$level\]* $mask]} { continue }
      lappend nicks $nick
    }
  }
  return [join $nicks ,]
}



####################################################
# ircconsole:relayuserallchan
#
# gets nicks to relay all channels
#
####################################################
proc ircconsole:relayuserallchan { level } {
  set nicks ""
  foreach chan [channels] {
    if {![botonchan $chan]} { continue }
#check +ircconsole ?
    foreach nick [chanlist $chan lomn|lomn] {
      if {![string equal [lsearch -exact $nicks $nick] "-1"]} { continue }
      set handle [nick2hand $nick]
      if {[matchattr $handle b]} { continue }
      set mask [ircconsole:get $handle $chan]
      if {![string match *\[$level\]* $mask]} { continue }
      lappend nicks $nick
    }
  }
  return [join $nicks ,]
}



####################################################
# ircconsole:relayuserchan
#
# relays to user for channel
#
####################################################
proc ircconsole:relayuserchan { chan level way tchan } {
  set nicks ""
  foreach nick [chanlist $chan lomn|lomn] {
    set handle [nick2hand $nick]
    if {[matchattr $handle b]} { continue }

# already got message?
    if {[string match {[03]} $way] && [onchan $nick $tchan]} { continue }
    if {[string match {[12]} $way] && [isop $nick $tchan]} { continue }
    if {[string match {[2]} $way] && [ishalfop $nick $tchan]} { continue }
    if {[string match {[2]} $way] && [isvoice $nick $tchan]} { continue }

# check mask
    set mask [ircconsole:get $handle $chan]
    if {![string match *\[$level\]* $mask]} { continue }
    lappend nicks $nick
  }
  return [join $nicks ,]
}



####################################################
# ircconsole:lower
#
# for comparing strings rfc1459 charset
#
####################################################
proc ircconsole: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
}



####################################################
# ircconsole:dcc
#
# dcc ircconsole command
#
####################################################
bind dcc -|- ircconsole ircconsole:dcc

proc ircconsole:dcc { handle idx text } {
  if {[matchattr $handle b]} { return 0 }
  set output [ircconsole:cmd $handle $text]
  foreach line $output { putidx $idx $line }
  return 1
}



####################################################
# ircconsole:msg
#
# msg ircconsole command
#
####################################################
bind msg lomn|lomn ircconsole ircconsole:msg

proc ircconsole:msg { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }
  set o [ircconsole:cmd $h $t]
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "   " } }
  return 1
}



####################################################
# ircconsole:cmd
#
# shows and handles changes
#
# text: [<handle>] [<chan>] [<flags>]
#
####################################################
proc ircconsole:cmd { handle text } {

  set text [split $text]
  set arg1 [lindex $text 0]
  set arg2 [lindex $text 1]
  set arg3 [lindex $text 2]

# we have nothing
  if {[string equal $arg1 ""]} {
#show user his settings
    set mask [ircconsole:get $handle $arg1]
    if {[string equal $mask ""]} { set mask "<none>" }
    lappend output "ircconsole: all settings are: $mask"


# we have "handle" or "chan"
  } elseif {[string equal $arg2 ""]} {
    if {[validchan $arg1]} {
#show user his setting for channel arg1
      if {[matchattr $handle lomn|lomn $arg1]} {
        set mask [ircconsole:get $handle $arg1]
        if {[string equal $mask ""]} { set mask "<none>" }
        lappend output "ircconsole: chan setting on $arg1 is: $mask"
      } else {
        lappend output "ircconsole: no access or unknown channel/user $arg1"
      }
    } elseif {[string equal -nocase $arg1 "global"]} {
#show user his global settings
      set mask [ircconsole:get $handle $arg1]
      if {[string equal $mask ""]} { set mask "<none>" }
      lappend output "ircconsole: global setting is: $mask"
    } elseif {[validuser $arg1]} {
      if {[matchattr $handle mn]} {
#show user settings for user $arg1
        set mask [ircconsole:get $arg1 $arg2]
        if {[string equal $mask ""]} { set mask "<none>" }
        lappend output "ircconsole: all settings for user $arg1 are: $mask"
      } else {
#no access to view settings for user $arg1
        lappend output "ircconsole: no access to view all settings for user $arg1"
      }
    } else {
#no access or unknown channel/user $arg1
      lappend output "ircconsole: no access or unknown channel/user $arg1"
    }




# we have "handle chan" or "chan flags"
  } elseif {[string equal $arg3 ""]} {
    if {[validchan $arg1]} {
#change mask for user for channel $arg1
      if {[matchattr $handle lomn|lomn $arg1]} {
        set flags [ircconsole:set $handle $arg1 $arg2]
        lappend output "ircconsole: now set to $flags on channel $arg1"
      } else {
        lappend output "ircconsole: no access or unknown channel/user $arg1"
      }
    } elseif {[string equal -nocase $arg1 "global"]} {
#set global mask for user
      set flags [ircconsole:set $handle $arg1 $arg2]
      lappend output "ircconsole: now set to $flags for global"
    } elseif {[validuser $arg1]} {
      if {[validchan $arg2]} {
# show settings for user $arg1 on chan $arg2
        if {[matchattr $handle lomn|lomn $arg2]} {
          if {[matchattr $arg1 lomn|lomn $arg2]} {
            set mask [ircconsole:get $arg1 $arg2]
            if {[string equal $mask ""]} { set mask "<none>" }
            lappend output "ircconsole: channel setting on $chan for user $arg1 is: $mask"
          } else {
            lappend output "ircconsole: user $arg1 is not known on channel $arg2"
          }
        } else {
          lappend output "ircconsole: no access or unknown channel $arg2"
        }
      } elseif {[string equal -nocase $arg2 "global"]} {
# show global settings for user $arg1
        set mask [ircconsole:get $arg1 $arg2]
        if {[string equal $mask ""]} { set mask "<none>" }
        lappend output "ircconsole: global setting for user $arg1 is: $mask"
      } else {
        lappend output "ircconsole: no access or unknown channel $arg2"
      }
    } else {
#no access or unknown channel/user $arg1
      lappend output "ircconsole: no access or unknown channel/user $arg1"
    }

# we got "handle chan flags"
  } else {
    if {[validuser $arg1]} {
# change mask for user $arg1 on channel $arg2
      if {[validchan $arg2]} {
        if {[matchattr $handle mn|mn $arg2]} {
          if {[matchattr $arg2 lomn|lomn $arg2]} {
            set flags [ircconsole:set $arg1 $arg2 $arg3]
lappend output "ircconsole: now set to $flags on channel $arg2 for user $arg1"
          } else {
            lappend output "ircconsole: user $arg1 is not a channel halfop or higher"
          }
        } else {
          lappend output "ircconsole: no access or unknown channel $arg2"
        }
      } elseif {[string equal -nocase $arg2 "global"]} {
# change global mask for user $arg1
        if {[matchattr $handle mn]} {
          set flags [ircconsole:set $arg1 $arg2 $arg3]
          lappend output "ircconsole: now set to $flags for global for user $arg1"
        } else {
          lappend output "ircconsole: no access to change global settings"
        }
      } else {
        lappend output "ircconsole: no access or unknown channel $arg2"
      }
    }
  }
}



####################################################
# ircconsole:get
#
# returns mask for handle for chan
#
####################################################
proc ircconsole:get { handle chan } {
  set masks [getuser $handle XTRA ircconsole]
  if {[string equal $chan ""]} {
    set masks [join [split $masks] "     "]
    set masks [join [split $masks ,]]
    return $masks
  }
  set mask ""
  set chan [ircconsole:lower $chan]
  foreach m [split $masks] {
    set c [lindex [split $m ,] 0]
    set m [lindex [split $m ,] 1]
    set c [ircconsole:lower $c]
    if {[string equal $chan $c]} { return $m }
  }
}



####################################################
# ircconsole:set
#
# saves flags for handle for chan
#
####################################################
proc ircconsole:set { handle chan flags } {

#replace * with all flags
  set flags [string map [list "*" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" "search" "replace" "search" "replace"] $flags]

  set masks [getuser $handle XTRA ircconsole]
  set mask ""
  set chan [ircconsole:lower $chan]
  set p -1
  set oldflags ""
  foreach m [split $masks] {
    incr p 1
    set c [lindex [split $m ,] 0]
    set m [lindex [split $m ,] 1]
    if {[string equal $chan [ircconsole:lower $c]]} {
      set mask $c,$m
      set oldflags $m
      break
    }
  }
  set status ""
  if {![string match {[-+]*} $flags]} {
    set oldflags ""
    set status "0"
  }
  foreach f [split $flags ""] {
    if {[string match {[-+]} $f] && ![string equal $status "0"]} {
      set status $f
    } elseif {![string match -nocase {[a-z0-9]} $f]} {
      continue
#0-9 are for global only
    } elseif {[string match {[0-9]} $f] && ![string equal -nocase $chan "global"]} {
      continue
#0-9 global mn only
    } elseif {[string match {[0-9]} $f] && ![matchattr $handle mn]} {
      continue
    } elseif {[string match {[+0]} $status]} {
      if {![string match *$f* $oldflags]} { append oldflags $f }
    } elseif {[string equal $status "-"]} {
      if {[string match *$f* $oldflags]} {
        set oldflags [string map "$f \"\"" $oldflags]
      }
    }
  }
  set oldflags [join [lsort [split $oldflags ""]] ""]
  if {[string equal $oldflags ""]} {
    set masks [lreplace $masks $p $p ""]
  } elseif {[string equal $mask ""]} {
    set masks [split $masks]
    lappend masks $chan,$oldflags
  } else {
    set masks [lreplace $masks $p $p $chan,$oldflags]
  }
  setuser $handle XTRA ircconsole $masks
  return $oldflags
}



####################################################
# ircconsole:time
#
# cleans up user records
#
####################################################
bind time -|- "10 * * * *" ircconsole:time

proc ircconsole:time { mi ho da mo ye } {
  foreach handle [userlist] {
    set masks [getuser $handle XTRA ircconsole]
    set masks [split $masks]
    set p "-1"
    foreach mask $masks {
      incr p 1
      set chan [lindex [split $mask ,] 0]
      set chan [ircconsole:lower $chan]
      if {[string equal $chan "global"] && [matchattr $handle mn]} { continue }
      if {[string equal $chan "global"] || ([validchan $chan] && [matchattr $handle mn|lomn $chan])} { continue }
      set masks [lreplace $masks $p $p ""]
    }
    set masks [join $masks]
    setuser $handle XTRA ircconsole $masks
  }
}


set scriptdb(ircconsole) {
  "keeps channels and users informed about anything a script relays (bans, kicks, chanlev changes, etc), what kind of messages are received depends on channel and user settings"
  "settings: +ircconsole (enable on source & target channel), ircconsole-way (set on target channel, 1 = notice @#chan, 2 = wallvoices #chan, 3 = notice #chan, else privmsg #chan), ircconsole-to (set on source channel, set to target channel), ircconsole-from (set on target channel, set to source channel)"
  "ircconsole-mask (* means all, a  chanlev, b  ban, c  clone ban, d, e  expire channel bans, f  flood/flud actions, g  global bans?, h  banlist, i  censor ban, j  censor chanban, k  censor kick, l  censor warn, m  clearmode/mode, n  netsplitbans, o  out, p, q queue, r, s  spamscan, t  topic, u  chan set, v, w warn, x kick, y z A B C D, E  expire global bans, F G H I J K, L  halfop commands?, M  master commands?, N  owner commands?, O  op commands?, P  global halfop commands?, Q  global master commands?, R  global owner commands?, S  global op commands?, T U V W X Y Z)"
  "flags available to global masters (1  add/del user?, 2  glev?, 3  botnet linking etc?, 4  global bans, 5  add/del chans)"
}

