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

####################################################
# mode:help:pubm
####################################################
bind pubm omn|omn "% ${botnet-nick} help mode" mode:help:pubm
proc mode:help:pubm { n u h c t } {
  if {[matchattr $h bkZ]} { return 0 }
  lappend o "mode: usage mode \[<chan>\] \[+-\]<modes> \[<params>\] \[<modes>\] \[<params\]"
  lappend o "mode: changes channel modes, syntax is the same as the IRC mode command. if no - or + precedes the mode a + is assumed. mode -k does not require a parameter. modes 'vhob' are not allowed."
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "mode: " } }
  putloglev c $c "help: $n $u $h $c mode"
  return 1
}


####################################################
# mode:help:msg
####################################################
bind msgm omn|omn "help mode" mode:help:msgm
proc mode:help:msgm { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }
  lappend o "mode: usage mode <chan> \[+-\]<modes> \[<params>\] \[<modes>\] \[<params\]"
  lappend o "mode: changes channel modes, syntax is the same as the IRC mode command. if no - or + precedes the mode a + is assumed. mode -k does not require a parameter. modes 'vhob' are not allowed."
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "mode: " } }
  putcmdlog "($n!$u) !$h! help mode"
  return 1
}


####################################################
# mode:pub
####################################################
bind pubm omn|omn "% ${botnet-nick} mode" mode:pubm
bind pubm omn|omn "% ${botnet-nick} mode *" mode:pubm
proc mode:pubm { n u h c t } {
  if {[matchattr $h bkZ]} { return 0 }
  set t [join [lrange [split $t] 2 end]]
  if {[string equal $t ""]} { lappend o "mode: usage mode \[<chan>\] \[+-\]<modes> \[<params>\] \[<modes>\] \[<params\]"
  } else { set o [mode:mode $h $t $c $n] }
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "mode: " } }
  putloglev c $c "mode: $n $u $h $c $t"
  return 1
}


####################################################
# mode:msg
####################################################
bind msg omn|omn mode mode:msg
proc mode:msg { n u h t } {
  if {[matchattr $h bkZ]} { return 0 }
  if {[string equal $t ""]} {
    lappend o "mode: usage mode <chan> \[+-\]<modes> \[<params>\] \[<modes>\] \[<params\]"
  } else { set o [mode:mode $h $t "" $n] }
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "mode: " } }
  return 1
}


####################################################
# mode:dcc
####################################################
bind dcc -|- mode mode:dcc
proc mode:dcc { h i t } {
  if {![valididx $i]} { return 0 }
  set c [lindex [split [console $i]] 0]
  if {![validchan $c]} { set c "" }
  if {[string equal $t ""]} {
    lappend o "mode: usage mode \[<chan>\] \[+-\]<modes> \[<params>\] \[<modes>\] \[<params\]"
    lappend o "mode: changes channel modes, syntax is the same as the IRC mode command. if no - or + precedes the mode a + is assumed. mode -k does not require a parameter. modes 'vhob' are not allowed."
  } else { set o [mode:mode $h $t $c] }
  foreach l $o { putidx $i $l }
  return 1
}


####################################################
# mode:mode
####################################################
proc mode:mode { h t {c ""} {u ""} } {
  set t [split $t]; set d [lindex $t 0]
  if {[string equal $c ""] || [string match {[#&]*} $d]} {
    set c $d; set t [join [lrange $t 1 end]]
  }
  if {![validchan $c] && ![string equal [info procs whichchan] ""]} { set c [whichchan $h $c] }
  if {![validchan $c] || ![matchattr $h omn|omn $c]} {
    lappend o "mode: no access or unknown channel $c"
  } elseif {[string equal $t ""]} {
    lappend o "mode: usage mode \[<chan>\] \[+-\]<modes> \[<params>\] \[<modes>\] \[<params\]"
  } elseif {![botonchan $c]} {
    lappend o "mode: I am not on $c"
  } elseif {![botisop $c] && ![botishalfop $c]} {
    lappend o "mode: I am not opped on $c"
  } else {
    set t [split $t]; set m [split [lindex $t 0] ""]; set p [lrange $t 1 end]; set s 1; set v +
    set x ""; set y ""; set z 0; set k [mode:key $c]; set l [mode:limit $c]
    set f ""; set g ""; set d ""; set e ""; set A -1; set P -1
    if {![string equal [info procs isupport] ""]} {
      set A [isupport chanmodes]; set P [isupport prefix]
    }
    if {[string equal $A "-1"]} { set A "b,k,l,imnpstrDdcCNu" }
    set A [split $A ,]; set B [lindex $A 1]; set C [lindex $A 2]; set D [lindex $A 3]
    set A [lindex $A 0]; set a [lindex [split [getchanmode $c]] 0]
    if {[string equal $P "-1"]} { set P "(ov)@+" }

    while {![string equal $m ""]} {
      foreach n $m {
        # disallow vhob modes
        if {[string match {[vhob]} $n]} { continue }
        if {[string equal $n "+"]} { set s 1; set v +
        } elseif {[string equal $n "-"]} { set s 0; set v -
        } elseif {[string match {[vho]} $n] && [string equal $u ""]} {
          set f [mode:add $f "$v$n"]

# key
        } elseif {[string equal $n "k"] && [string match "*$n*" $B]} {
          if {$s} {
            set r [lindex $p $z]; incr z 1
            if {[string equal $k $r]} { set e [mode:add $e "'$v$n $r'"]
            } elseif {[string equal $r ""]} { set f [mode:add $f "$v$n"]
            } else {
              if {![string equal $k ""]} { pushmode $c -$n $k; set e [mode:add $e "'-$n $k'"] }
              pushmode $c $v$n $r; set e [mode:add $e "'$v$n $r'"]
            }
          } else {
            if {[string equal $k ""]} { set f [mode:add $f "$v$n"]
            } else { pushmode $c $v$n $k; set e [mode:add $e "'$v$n $k'"] }
          }

# limit
        } elseif {[string equal $n "l"] && [string match "*$n*" $C]} {
          if {$s} {
            set r [lindex $p $z]; incr z 1
            if {[string equal $r ""]} { set f [mode:add $f "$v$n"]
            } elseif {![string is digit $r] || $r > [expr pow(2,32)] || [string equal $l $r]} {
              set g [mode:add $g "'$v$n $r'"]
            } else { pushmode $c +$n $r; set e [mode:add $e "'$v$n $r'"] }
          } elseif {[string match "*$n*" $a]} { pushmode $c -$n; set d [mode:add $d "$v$n"]
          } else { set f [mode:add $f "$v$n"] }

# misc modes, dont try to change pseudo mode d
        } elseif {[string match "*$n*" $D] && $n != "d"} {
          if {($s && ![string match "*$n*" $a]) || (!$s && [string match "*$n*" $a])} {
            pushmode $c $v$n; set d [mode:add $d "$v$n"]
          } else { set f [mode:add $f "$v$n"] }

# unknown/disallowed modes
        } else { set f [mode:add $f "$v$n"] }
      }
      set m [split [lindex $p $z] ""]; set p [lrange $p [expr $z +1] end]; set z 0
    }
    if {![string equal $d$e ""]} { lappend o "mode: parsed modes [join "$d $e" "  "] on $c"
      if {![string equal [info procs ircconsole] ""]} {
        ircconsole $c m MODE "$h changes modes [join "$d $e" "  "]"
      }
    }
    if {![string equal $f$g ""]} { lappend o "mode: failed modes [join "$f $g" "  "] on $c" }
    if {[string equal $d$e$f$g ""]} { lappend o "mode: done on $c" }
  }
  return $o
}


####################################################
# mode:key
####################################################
proc mode:key { c } {
  set m [split [getchanmode $c]]; set p [lrange $m 1 end]; set m [lindex $m 0]
  if {![string match "*k*" $m]} { return "" }
  if {[string equal [llength $p] "0"]} { return "" }
  if {[string equal [llength $p] "1"]} { return [lindex $p 0] }
  set x 0; set m [split $m ""]
  foreach n $m {
    if {[string equal $n "k"]} { break }
    if {[string equal $n "l"]} { incr x 1 }
  }
  set k [lindex $p $x]
  return $k
}


####################################################
# mode:limit
####################################################
proc mode:limit { c } {
  set m [split [getchanmode $c]]; set p [lrange $m 1 end]; set m [lindex $m 0]
  if {![string match "*l*" $m]} { return "" }
  if {[string equal [llength $p] "0"]} { return "" }
  if {[string equal [llength $p] "1"]} { return [lindex $p 0] }
  set x 0; set m [split $m ""]
  foreach n $m {
    if {[string equal $n "l"]} { break }
    if {[string equal $n "k"]} { incr x 1 }
  }
  set l [lindex $p $x]
  return $l
}


####################################################
# mode:mask
####################################################
proc mode:mask { m } {
  if {[string match "?*@?*" $m] && ![string match "?*!?*@?*" $m]} { return "*!$m"
  } elseif {[string match "*.*" $m] && ![string match "?*!?*@?*" $m]} { return "*!*@$m"
  } elseif {[string match "?*!?*" $m] && ![string match "?*!?*@?*" $m]} { return "$m@*"
  } elseif {[string match "\#?*" $m] && ![string match "?*!?*@?*" $m]} {
    return "*!*@[string range $m 1 end].users.quakenet.org"
  } elseif {![string match "?*!?*@?*" $m]} { return "$m!*@*" } else { return $m }
}


####################################################
# mode:ban
####################################################
proc mode:ban { c m } {
  set m [newchanban:lower $m]
  foreach b [chanbans $c] {
    set b [lindex $b 0]
    set b [mode:lower $b]
    regsub -all {[][\\]} $b {\\\0} b
    if {[string match $b $m]} { return 1 }
  }
  return 0
}


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


####################################################
# mode:add
####################################################
proc mode:add { l i } {
  if {[string equal [lsearch -exact $l $i] "-1"]} { lappend l $i }
  return $l
}


set scriptdb(mode) {
  "provides mode command to change channel modes"
}

