####################################################
# by wiebe @ QuakeNet
#
#  provides chan command with various subcommands
#  for adding/deleting channels,
#  showing and changing channel settings
#  listing channels
#  cycle to make the bot rejoin channels
#
####################################################

# chan [<chan>] add|del|set|info|list|cycle|help

setudef int creationtime


####################################################
# chan:help:pubm
####################################################
bind pubm lomn|lomn "% ${botnet-nick} help chan" chan:help:pubm
proc chan:help:pubm { n u h c t } {
  if {[matchattr $h bkZ]} { return 0 }
  lappend o "chan: usage chan \[<chan>\] add|del|set|info|list|cycle|help"
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "chan: " } }
  putloglev c $c "help: $n $u $h $c chan"
  return 1
}


####################################################
# chan:help:msgm
####################################################
bind msgm lomn|lomn "help chan" chan:help:msgm
proc chan:help:msgm { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }
  lappend o "chan: usage chan \[<chan>\] add|del|set|info|list|cycle|help"
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "chan: " } }
  putcmdlog "($n!$u) !$h! help chan"
  return 1
}


####################################################
# chan:pubm
####################################################
bind pubm lomn|lomn "% ${botnet-nick} chan" chan:pubm
bind pubm lomn|lomn "% ${botnet-nick} chan *" chan:pubm
proc chan:pubm { n u h c t } {
  if {[matchattr $h bkZ]} { return 0 }
  
  if {![validchan $c]} { return 0 }
  set t [lrange [split $t] 2 end]; set d [string tolower [lindex $t 0]]
  if {[lsearch -exact "add del set info list cycle help" $d] == -1} {
    set d [string tolower [lindex $t 1]]
    if {$d == ""} { set d [string tolower [lindex $t 0]] }
  }
  
  if {$d == "add"} { set o [chan:add $h $t]
  } elseif {$d == "del"} { set o [chan:del $h $t]
  } elseif {$d == "set"} { set o [chan:set $h $t $c]
  } elseif {$d == "info"} { set o [chan:info $h $t $c]
  } elseif {$d == "list"} { set o [chan:list $h $t]
  } elseif {$d == "cycle"} { set o [chan:cycle $h $t $c]
  } elseif {$d == "help"} { set o [chan:help $t]
  } else {
    if {$d != ""} { lappend o "chan: unknown subcommand $d" }
    lappend o "chan: usage chan \[<chan>\] add|del|set|info|list|cycle|help"
  }
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "chan: " } }
  putloglev c $c "CHAN: $n $u $h $c $t"
  return 1
}


####################################################
# chan:msg
####################################################
bind msg lomn|lomn chan chan:msg
proc chan:msg { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }

  set t [split $t]; set d [string tolower [lindex $t 0]]
  if {[lsearch -exact "add del set info list cycle help" $d] == -1} {
    set d [string tolower [lindex $t 1]]
    if {$d == ""} { set d [string tolower [lindex $t 0]] }
  }

  if {$d == "add"} { set o [chan:add $h $t]
  } elseif {$d == "del"} { set o [chan:del $h $t]
  } elseif {$d == "set"} { set o [chan:set $h $t]
  } elseif {$d == "info"} { set o [chan:info $h $t]
  } elseif {$d == "list"} { set o [chan:list $h $t]
  } elseif {$d == "cycle"} { set o [chan:cycle $h $t]
  } elseif {$d == "help"} { set o [chan:help $t]
  } else {
    if {$d != ""} { lappend o "chan: unknown subcommand $d" }
    lappend o "chan: usage chan \[<chan>\] add|del|set|info|list|cycle|help"
  }
  if {[info procs cnotice] == ""} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "chan: " } }
  return 1
}


####################################################
# chan:dcc
####################################################
bind dcc -|- chan chan:dcc
proc chan:dcc { h i t } {
  if {![valididx $i]} { return 0 }
  set c [lindex [split [console $i]] 0]
  if {![validchan $c]} { set c "" }

  set t [split $t]; set d [string tolower [lindex $t 0]]
  if {[lsearch -exact "add del set info list cycle help" $d] == -1} {
    set d [string tolower [lindex $t 1]]
    if {$d == ""} { set d [string tolower [lindex $t 0]] }
  }

  if {$d == "add"} { set o [chan:add $h $t]
  } elseif {$d == "del"} { set o [chan:del $h $t]
  } elseif {$d == "set"} { set o [chan:set $h $t $c]
  } elseif {$d == "info"} { set o [chan:info $h $t $c]
  } elseif {$d == "list"} { set o [chan:list $h $t]
  } elseif {$d == "cycle"} { set o [chan:cycle $h $t $c]
  } elseif {$d == "help"} { set o [chan:help $t]
  } else {
    if {$d != ""} { lappend o "chan: unknown subcommand $d" }
    lappend o "chan: usage chan \[<chan>\] add|del|set|info|list|cycle|help"
  }
  foreach l $o { putidx $i $l }
  return 1
}


####################################################
# chan:add
####################################################
proc chan:add { h t } {
  set c ""; set e [lindex $t 0]; set d [lrange $t 1 end]
  if {![string equal -nocase $e "add"]} { set c $e; set d [lrange $t 2 end] }
  set d [join $d]

  if {$d == ""} { set d +inactive
  } elseif {[lsearch $d -inactive] == -1 && [lsearch $d +inactive] == -1} { set d "+inactive $d" }
  if {$c == ""} {
    lappend o "chan: no chan specified"
    lappend o "chan: chan <chan> add \[<settings>\]"
  } elseif {![matchattr $h mn]} {
    lappend o "chan: no access"
  } elseif {[validchan $c]} {
    lappend o "chan: channel $c already exists"
  } elseif {[catch {channel add $c $d} e]} {
    if {[validchan $c]} {
      lappend o "chan: added channel $c ($d)."
      lappend o "chan: error applying settings ([join $e])"
      if {[info procs ircconsole] != ""} { ircconsole global 5 CHAN "$h ADD $c ($d)" }
      putloglev c $c "CHAN $h ADD $c"
    } else { lappend o "chan: error adding channel $c ([join $e ;])" }
  } else {
    lappend o "chan: added channel $c ($d)"
    if {[info procs ircconsole] != ""} { ircconsole global 5 CHAN "$h ADD $c ($d)" }
    putloglev c $c "CHAN $h ADD $c"
  }
  return $o
}


####################################################
# chan:del
####################################################
proc chan:del { h t } {
  set c ""; set d [lindex $t 0]; set t [lrange $t 1 end]
  if {![string equal -nocase $d "del"]} { set c $d; set t [lrange $t 1 end] }

  set v [lindex $t 1]; set m [string range [md5 "$h [string tolower $c]"] 0 5]
  if {$c == ""} {
    lappend o "chan: chan <chan> del"
  } elseif {![matchattr $h mn]} {
    lappend o "chan: no access or unknown channel $c"
  } elseif {![validchan $c]} {
    lappend o "chan: unknown channel $c"
  } elseif {$v != $m} {
    channel set $c +inactive
    lappend o "chan: WARNING! this will remove $c from the bot"
    lappend o "chan: to confirm this command use: chan $c del $m"
  } elseif {[catch {channel remove $c} e]} { set e "([join $e])"
    if {![validchan $c]} {
      lappend o "chan: deleted channel $c from the bot $e"
      if {[info procs ircconsole] != ""} { ircconsole global 5 CHAN "$h DEL $c " }
      putloglev c $c "CHAN $h DEL $c"
    } else { lappend o "chan: error deleting channel $c $e" }
  } else {
    lappend o "chan: deleted channel $c from the bot"
    if {[info procs ircconsole] != ""} { ircconsole global 5 CHAN "$h DEL $c" }
    putloglev c $c "CHAN $h DEL $c"
  }
  return $o
}


####################################################
# chan:set
####################################################
proc chan:set { h t {c ""} } {
  set d [lindex $t 0]; set t [lrange $t 1 end]
  if {![string equal -nocase $d "set"]} { set c $d; set t [lrange $t 1 end] }
  if {![validchan $c] && [info procs whichchan] != ""} { set c [whichchan $h $c] }
  set d [join $t]; set h [string tolower $h]

  if {$c == ""} {
    lappend o "chan: no chan specified"
    lappend o "chan: chan \[<chan>\] set \[<settings>\]"
  } elseif {$c != "*" && (![validchan $c] || ![matchattr $h mn|mn $c])} {
    lappend o "chan: no access or unknown channel $c"
  } elseif {$c == "*" && ![matchattr $h mn]} {
    lappend o "chan: no access to use *"
  } elseif {[llength [channels]] == 0} {
    lappend o "chan: no channels are added"
  } elseif {$d == ""} {
    lappend o "chan: no setting specified"
    lappend o "chan: set <chan> \[<settings>\]"
  } else {
    set p 0; set s ""; set r ""; set n ""; set x $c; set z ""; set f " for $c"
    if {$c == "*"} {
      set z [channels]; set x [lindex $z 0]; set z [lrange $z 1 end]
      set c "all channels"; set f ""
    }
    if {[lsearch [split [string tolower $::owner]] $h] == -1} {
      set n [split "need-op need-invite need-key need-unban need-limit noparanoid"]
    }
    foreach b [split $d] { incr p 1
      if {[string match "-*" $b] || [string match "+*" $b]} {
        if {[catch {channel set $x $b}]} {
          lappend o "chan: error trying to set $b$f, invalid mode"
        } else { foreach a $z { channel set $a $b }; lappend s "$b" }
      } elseif {[lsearch $n [string tolower $b]] > -1} {
        lappend o "chan: no access to set $b"
      } else { set q [join [lrange [split $d] $p end]]
        if {[catch {channel set $x $b $q}]} {
          lappend o "chan: error trying to set $b$f, invalid option"
        } else { foreach a $z { channel set $a $b $q }; lappend s "$b \{ $q \}" }; break
      }
    }
    if {$s != ""} {
      set s [join $s]
      lappend o "chan: successfully set modes \{ $s \} on $c"
      if {[info procs ircconsole] != ""} { foreach a "$x $z" { ircconsole $a u CHAN "$h SET $s" } }
      if {$z == ""} { putloglev c $x "CHAN $h SET \{ $s \} $x"
      } else { putloglev c * "CHAN $h SET \{ $s \} on all channels" }
    }
  }  return $o
}


####################################################
# chan:info
####################################################
proc chan:info { h t {c ""} } {
  set d [lindex $t 0]; set t [lrange $t 1 end]
  if {![string equal -nocase $d "info"]} { set c $d; set t [lrange $t 1 end] }
  if {![validchan $c] && [info procs whichchan] != ""} { set c [whichchan $h $c] }

  set m [lindex $t 0]
  if {$c == ""} {
    lappend o "chan: no chan specified"
    lappend o "chan: chan \[<chan>\] info \[<setting>\]"
  } elseif {![validchan $c] || ![matchattr $h lomn|lomn $c]} {
    lappend o "chan: no access or unknown channel $c"
  } else {
    set p ""
    if {$m == ""} {
      set z "chanmode idle-kick aop-delay revenge-mode ban-time exempt-time invite-time flood-chan flood-ctcp flood-join flood-kick flood-deop flood-nick"
      foreach s $z { lappend p "\002$s\002='[channel get $c $s]'" }
      set z "inactive greet protectops bitch enforcebans protecthalfops dynamicexempts statuslog seen protectfriends autoop dynamicbans secret cycle revenge autovoice userbans dynamicinvites shared dontkickops revengebot nodesynch autohalfop userinvites"
      foreach s [lsort $z] {
        if {[channel get $c $s]} { lappend p \002+$s\002 } else { lappend p -$s }
      }
    } else {
      set z [channel info $c]; set z [lrange $z 43 end]; set z [lsort $z]; set x $m
      regsub -all {[][\\]} $x {\\\0} x
      foreach s $z {
        if {![string match -nocase $m [lindex $s 0]]} { continue }
        if {[string match +* $s]} { lappend p \002$s\002
        } elseif {[string match -* $s]} { lappend p $s
        } else {
          set v [lindex $s 1]; set s [lindex $s 0]; if {[llength [split $v]] > 1} { set v \{$v\} }
          lappend p "$s=$v"
        }
      }
    }
    if {$p != ""} { lappend o "chan: showing info for $c" "chan: [join $p "   "]"
    } else { lappend o "chan: no settings found matching $m on $c" }
  }
  return $o
}


####################################################
# chan:list
####################################################
proc chan:list { h t } {
  set d [lindex $t 0]; set p [lindex $t 1]
  if {![string equal -nocase $d "list"]} { set p "" }
  
  if {![matchattr $h mn]} {
    lappend o "chan: no access"
  } elseif {$p == ""} {
    lappend o "chan: no pattern specified"
    lappend o "chan: chan list <pattern>"
  } else {
    set r ""; set m $p; regsub -all {[][\\]} $m {\\\0} m
    foreach c [lsort [channels]] {
      if {![string match $m $c]} { continue }
      set x [getchanmode $c]
      if {[botisop $c]} { lappend r "@$c ($x)"
      } elseif {[botishalfop $c]} { lappend r "%$c ($x)"
      } elseif {[botisvoice $c]} { lappend r "+$c ($x)"
      } elseif {[channel get $c inactive]} { lappend r "!$c"
      } elseif {[ischanjuped $c]} { lappend r "*$c"
      } elseif {![botonchan $c]} { lappend r "~$c"
      } else { lappend r "_$c ($x)" }
    }
    if {$r != ""} {
      lappend o "chan: [join $r "    "]"
      lappend o "chan: where @=op, %=halfop, +=voice, _=regular, !=inactive, *=unable to join, ~=not joined."
      lappend o "chan: end of channel list matching $p"
    } else { lappend o "chan: no channels found matching $p" }
  }
  return $o
}


####################################################
# chan:cycle
####################################################
proc chan:cycle { h t {c ""} } {
  set d [lindex $t 0]; set t [lrange $t 1 end]
  if {![string equal -nocase $d "cycle"]} { set c $d; set t [lrange $t 1 end] }
  if {![validchan $c] && [info procs whichchan] != ""} { set c [whichchan $h $c] }
  set d [string tolower $c]; set v [lindex $t 1]
  set m [string range [md5 "$h $d"] 0 5]
  if {$c == ""} {
    lappend o "chan: no chan specified"
    lappend o "chan: chan cycle <chan>|all"
  } elseif {$d == "all" && ![matchattr $h mn]} {
    lappend o "chan: no access to cycle all channels"
  } elseif {$d != "all" && (![validchan $c] || ![matchattr $h mn|mn $c])} {
    lappend o "chan: no access or unknown channel $c"
  } elseif {$d != "all" && ![botonchan $c]} {
    lappend o "chan: bot is not on $c"
  } elseif {$v != $m} {
    if {$c == "all"} {
      lappend o "chan: WARNING! this will make the bot cycle all of its channel"
    } else { lappend o "chan: WARNING! this will make the bot cycle $c" }
    lappend o "chan: to confirm this command use: cycle $c $m"
  } else {
    if {$d == "all"} { puthelp "JOIN 0"; lappend o "chan: cycling all channels"
    } else { puthelp "PART $c"; lappend o "chan: cycling channel $c" }
  }
  return $o
}


####################################################
# chan:show
####################################################
# mode chan
# if not +s, elseif +s but known and ok to show then use internal info, else
# list chan
proc chan:show { h t p c n } {
  set c [lindex [split $t] 0]
  set d [chan:lower $c]
#  if {[catch {set m [isupport chanlen]}] || $m == -1} { set m 200 }
  set e "chan: chan \[<chan>\] show"
  if {$c == ""} {
    lappend o "chan: no chan specified"; lappend o $e
  } elseif {![regexp {^\#[^,\002\003\009\017\026\037]*$} $c] || [string length $c] > 200} {
    lappend o "chan: invalid chan specified"; lappend o $e
  } elseif {[validchan $c]} {
    global chandb
    set s [channel get $c creationtime]
    if {[string match *s* [lindex [split [getchanmode $c]] 0]] && $d != [chan:lower $p] && ([validchan $p] || ![matchattr $h lomn|lomn $c])} {
      set z "chan: unable to retrieve chan from $c (secret)"
    } else {
      set z "chan: chan on $c is '$t\017' $l     set by $b     on $s"
    }
    if {[validchan $p] && (![string match *m* [lindex [split [getchanmode $p]] 0]] || [botisvoice $p] || [botishalfop $p] || [botisop $p])} {
      if {[string match *c* [lindex [split [getchanmode $p]] 0]]} { set z [stripcodes bcru $z] }
      if {[info procs privmsg] == ""} { puthelp "PRIVMSG $p :$z" } else { privmsg $p $z puthelp "chan: " }
      return ""
    } else { lappend o $z }
  } elseif {![validchan $p] && ![valididx $p] && ![onchan $p]} {
    lappend o "chan: you are not on any of my channels"
  } else {
    global chandb; set x [clock seconds]
# chandb(s,from) ts to1 to2 ..
    if {[info exists chandb(s,$d)]} {
      set y [lindex [split $chandb(s,$d)] 0]
      if {[lsearch $chandb(s,$d) "$p $h $n"] == -1} { lappend chandb(s,$d) "$p $h $n" }
      if {[expr $x - $y] > 60} { puthelp "chan $d" }
    } else { lappend chandb(s,$d) $x; lappend chandb(s,$d) "$p $h $n"; puthelp "MODE $d" }
    return ""
    lappend o "chan: retrieving info from $c"
  }
  return $o
}


####################################################
# chan:raw
# 322 RPL_LIST    324 RPL_CHANNELMODEIS
# 329 RPL_CREATIONTIME    403 ERR_NOSUCHCHANNEL
####################################################
bind raw -|- "322" chan:raw; bind raw -|- "324" chan:raw
bind raw -|- "329" chan:raw; bind raw -|- "403" chan:raw
proc chan:raw { s n t } {
  set t [split $t]; set c [lindex $t 1]; set d [chan:lower $c]
  if {$n == 322} {

  } elseif {$n == 324} {

  } elseif {$n == 329} {
    set s [lindex $t 2]
    if {[validchan $c]} { channel set $c creationtime $s }

  } elseif {$n == 403} {

  }
}


####################################################
# chan:help
####################################################
proc chan:help { t } {
  set c [string tolower [lindex [split $t] 0]]
  if {$c == "add"} {
    lappend o "chan: chan <chan> add \[<settings>\]"
    lappend o "chan: adds the given channel to the bot with the specified settings (default +inactive)"
  } elseif {$c == "del"} {
    lappend o "chan: chan <chan> del"
    lappend o "chan: deletes the given channel from the bot"
  } elseif {$c == "set"} {
    lappend o "chan: chan \[<chan>\] set <settings>"
    lappend o "chan: changes settings for the given channel, use * for all channels"
  } elseif {$c == "info"} {
    lappend o "chan: chan \[<chan>\] info \[<pattern>\]"
    lappend o "chan: shows settings for the given channel, shows default eggdrop settings or custom settings matching the given pattern"
  } elseif {$c == "list"} {
    lappend o "chan: chan list <pattern>"
    lappend o "chan: lists channels added to the bot"
  } elseif {$c == "cycle"} {
    lappend o "chan: chan \[<chan>|all\] cycle"
    lappend o "chan: makes the bot rejoin all channels or the given channel"
  } else {
    lappend o "chan: usage help add|del|set|info|list|cycle"
    lappend o "chan: shows help in general or for the given subcommand"
  }
  return $o
}


####################################################
# chan:lower
####################################################
proc chan:lower { t } {
  global rfc-compliant
  if {[info exists rfc-compliant] && ${rfc-compliant} == 1} {
    set t [string map "\\{ \[ \\} \] ~ ^ \\\\ |" $t]
  }
  set t [string tolower $t]
  return $t
}


####################################################
# chan:ts
####################################################
proc chan:ts { t } {
  if {![string is digit $t]} { return 0 }
  set n [clock seconds]; set t [expr $t - $n]; if {$t < 0} { set t [expr $t * -1] }
  set t [duration $t]
  set t [string map "seconds s second s minutes m minute m hours h hour h" $t]
  set t [string map "days d day d weeks w week w years y year y" $t]
  return [join [lrange [split $t] 0 3] ""]
}


set scriptdb(chan) {
  "provides chan command with various subcommands for adding/deleting channels, showing and changing channel settings, listing channels, cycle to make the bot rejoin channels"
}

