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

####################################################
# structure of dnsdb array
#
# dnsdb(c,<host>) <ts> i <ip>
# dnsdb(c,<ip>) <ts> h <host>
# dnsdb(i,<nick>) <ip>
# dnsdb(h,<nick>) <host>
# dnsdb(q) "<nick> <user@host>"  "<nick2> <user@host2>" ...
#
####################################################

setudef flag dnsdb

####################################################
# dnsdb:join
####################################################
bind join -|- * dnsdb:join; bind rejn -|- * dnsdb:join
proc dnsdb:join { n u h c } {
  if {![validchan $c]} { return 0 }
  if {![channel get $c dnsdb]} { return 0 }
  global dnsdb
  if {[isbotnick $n]} { set c [dnsdb:lower $c]; set dnsdb(j,$c) "1" } else { dnsdb:check $n $u }
}


####################################################
# dnsdb:315
####################################################
bind raw - "315" dnsdb:315
proc dnsdb:315 { s n t } {
  set c [lindex [split $t] 1]
  set c [dnsdb:lower $c]
  if {![validchan $c]} { return 0 }
  if {![botonchan $c]} { return 0 }
  if {![channel get $c dnsdb]} { return 0 }
  global dnsdb
  if {![info exists dnsdb(j,$c)]} { return 0 }
  unset dnsdb(j,$c)
  foreach n [chanlist $c] { if {![onchansplit $n $c]} { dnsdb:check $n [getchanhost $n $c] } }
}


####################################################
# dnsdb:check
####################################################
proc dnsdb:check { n u } {
  global dnsdb
  set h [lindex [split $u @] 1]
  set n [string tolower $n]
  if {![string match "*.*" $h]} { return 0 }
  if {[string match -nocase "?*.quakenet.org" $h]} { return 0 }
  if {[string match -nocase "quakenet.org" $h]} { return 0 }
# dont have HOST
  if {![info exists dnsdb(h,$n)] || [string equal $dnsdb(h,$n) ""]} { set dnsdb(h,$n) $h }
# already have IP
  if {[info exists dnsdb(i,$n)] && ![string equal $dnsdb(i,$n) ""]} {
    dnsdb:forward $n $u; return 0
  }
# cache
  set h [string tolower $h]
  if {[info exists dnsdb(c,$h)]} {
    set i [split $dnsdb(c,$h)]; set t [lindex $i 0]; set w [lindex $i 1]; set i [lindex $i 2]
    set s [clock seconds]
    if {[expr $s - $t] < "86400"} {
      set h [lindex [split $u @] 1]
      if {[string equal $w "i"]} {
        set dnsdb(i,$n) $i; set dnsdb(h,$n) $h
      } else { set dnsdb(h,$n) $i; set dnsdb(i,$n) $h }
      dnsdb:forward $n $u
      return 0
    }
  }
# add to queue
  if {![info exists dnsdb(q)]} { set dnsdb(q) "" }
  if {[string equal $dnsdb(q) ""]} {
    lappend dnsdb(q) "$n $u"
    set h [lindex [split $u @] 1]
    dnslookup $h dnsdb:callback $u
  } else {
    lappend dnsdb(q) "$n $u"
  }
}


####################################################
# dnsdb:callback
####################################################
proc dnsdb:callback { ip host status uhost } {
  global dnsdb
  if {![info exists dnsdb(q)]} { return 0 }
  if {[string equal $dnsdb(q) ""]} { return 0 }

  set n [lindex $dnsdb(q) 0]
  set u [lindex [split $n] 1]
  set n [lindex [split $n] 0]
# trouble, what IF user sets +x while lookup is done?
  if {![string equal $uhost $u]} { set host ""; set ip "0.0.0.0" }
# did not resolve host
  if {[string equal $host $ip]} { set host "" }
# did not resolve ip
  if {[string equal $ip "0.0.0.0"]} { set ip "" }
  if {[onchan $n]} {
    set dnsdb(h,$n) $host
    set dnsdb(i,$n) $ip
    dnsdb:forward $n $u
  }  
  set now [clock seconds]
  if {![string equal $host ""] && ![string equal $ip ""]} {
    set dnsdb(c,$ip) "$now h $host"
    set host [string tolower $host]
    set dnsdb(c,$host) "$now i $ip"
  }

# check rest of queue
  set dnsdb(q) [lrange $dnsdb(q) 1 end]
  if {[string equal $dnsdb(q) ""]} { return 0 }

# recheck cache
  foreach e $dnsdb(q) {
    set u [lindex [split $e] 1]
    set h [lindex [split $e @] 1]
    set h [string tolower $h]
    if {[info exists dnsdb(c,$h)]} {
      set i [split $dnsdb(c,$h)]; set t [lindex $i 0]; set w [lindex $i 1]; set i [lindex $i 2]
      set now [clock seconds]
      if {[expr $now - $t] < "86400"} {
        if {![string equal $w "i"]} {
          set dnsdb(h,$n) $i
          set dnsdb(i,$n) [lindex [split $uhost @] 1]
        } else { set dnsdb(i,$n) $i }
        set dnsdb(q) [lrange $dnsdb(q) 1 end]
        continue
      }
    }

# do next
    set h [lindex [split $e @] 1]
    dnslookup $h dnsdb:callback $u
    break
  }
}


####################################################
# dnsdb:forward
####################################################
proc dnsdb:forward { n u } {
  set u [split $u @]; set r [lindex $u 1]; set u [lindex $u 0]
  set h [dnsdb:get $n h]; set i [dnsdb:get $n i]
  if {![string equal [info procs dnsbans:check] ""]} { dnsbans:check $n $u $r $h $i }
}


####################################################
# dnsdb:part
####################################################
bind part -|- * dnsdb:part
proc dnsdb:part { n u h c {m ""} } { dnsdb:leave $c $n }


####################################################
# dnsdb:kick
####################################################
bind kick -|- * dnsdb:kick
proc dnsdb:kick { n u h c t m } { dnsdb:leave $c $t }


####################################################
# dnsdb:sign
####################################################
bind sign -|- * dnsdb:sign; bind splt -|- * dnsdb:sign
proc dnsdb:sign { n u h c {m ""} } {
  if {[string equal -nocase $m "registered"]} { return 0 }
  if {[string equal -nocase $m "host change"]} { return 0 }
  dnsdb:leave $c $n
}


####################################################
# dnsdb:nick
####################################################
bind nick -|- * dnsdb:nick
proc dnsdb:nick { n u h c m } {
  global dnsdb; set n [string tolower $n]; set m [string tolower $m]
  if {[string equal $n $m]} { return 0 }
  if {[info exists dnsdb(i,$n)]} {set dnsdb(i,$m) $dnsdb(i,$n); unset dnsdb(i,$n) }
  if {[info exists dnsdb(h,$n)]} { set dnsdb(h,$m) $dnsdb(h,$n); unset dnsdb(h,$n) }
  if {![info exists dnsdb(q)]} { set dnsdb(q) "" }
  set p [lsearch -exact [split $dnsdb(q)] $n]
  if {![string equal $p "-1"]} { set dnsdb(q) [lreplace [split $dnsdb(q)] $p $p $m] }
}


####################################################
# dnsdb:leave
####################################################
proc dnsdb:leave { c n } {
  global dnsdb
  if {[isbotnick $n]} {
    if {![validchan $c]} {
      foreach e [array names dnsdb] {
        set t [lindex [split $e ,] 0]
        if {![string match {[ih]} $t]} { continue }
        set n [lindex [split $e ,] 1]
        if {[dnsdb:comchan $c $n]} { continue }
        dnsdb:unset $n
      }
    } else {
      foreach n [chanlist $c] {
        if {[onchansplit $n $c]} { continue }
        if {[dnsdb:comchan $c $n]} { continue }
        dnsdb:unset $n
      }
    }
  } else {
    set i [dnsdb:get $n i]; set h [dnsdb:get $n h]
    if {![dnsdb:comchan $c $n]} { dnsdb:unset $n }
    if {![string equal [info procs whowas:set] ""]} { whowas:set $n dnsdbh $h $c }
    if {![string equal [info procs whowas:set] ""]} { whowas:set $n dnsdbi $i $c }
  }
}


####################################################
# dnsdb:unset
####################################################
proc dnsdb:unset { n } {
  if {[isbotnick $n]} { return 0 }
  global dnsdb
  set t [clock seconds]
  set n [string tolower $n]
  set i ""; set h ""
  if {[info exists dnsdb(i,$n)]} {
    if {![string equal $dnsdb(i,$n) ""]} {
      set i $dnsdb(i,$n)
# whowas
      if {![string equal [info procs whowas:set] ""]} { whowas:set $n dnsdbi $i }
    }
    unset dnsdb(i,$n)
  }
  if {[info exists dnsdb(h,$n)]} {
    if {![string equal $dnsdb(h,$n) ""]} {
      set h $dnsdb(h,$n)
# whowas
      if {![string equal [info procs whowas:set] ""]} { whowas:set $n dnsdbh $h }
    }
    unset dnsdb(h,$n)
  }
  if {![string equal $i ""] && ![string equal $h ""]} {
    set dnsdb(c,$i) "$t h $h"; set h [string tolower $h];  set dnsdb(c,$h) "$t i $i"
  }
}


####################################################
# dnsdb:comchan
# returns 1 if the user is on another channel
####################################################
proc dnsdb:comchan { c n } {
  if {[onchansplit $n]} { return 0 }
  foreach d [channels] { if {[onchan $n $d] && ![onchansplit $n $d] && ![string equal -nocase $d $c]} { return 1 } }
  return 0
}


####################################################
# dnsdb:lower
####################################################
proc dnsdb: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
}


####################################################
# dnsdb:evnt
####################################################
bind evnt -|- init-server dnsdb:evnt
proc dnsdb:evnt { t } {
  global dnsdb
  foreach e [array names dnsdb] {
    set t [lindex [split $e ,] 0]
    if {![string match {[ih]} $t]} { continue }
    unset dnsdb($e)
  }
}


####################################################
# dnsdb:time
####################################################
bind time -|- "18 * * * *" dnsdb:time
proc dnsdb:time { mi ho da mo ye } {
  global dnsdb
  set n [clock seconds]
  foreach e [array names dnsdb] {
    set t [lindex [split $e ,] 0]
# not a cache entry - next
    if {![string equal $t "c"]} { continue }
    set t [lindex [split $dnsdb($e)] 0]
# less than a day old - next
    if {[expr $n - $t] < "86400"} { continue }
    unset dnsdb($e)
  }
}


####################################################
# dnsdb:get
####################################################
proc dnsdb:get { nick what } {
  global dnsdb; set w [string tolower $what]; set n [string tolower $nick]
  if {[string equal $w "h"]} { if {[info exists dnsdb(h,$n)]} { return $dnsdb(h,$n) } }
  if {[string equal $w "i"]} { if {[info exists dnsdb(i,$n)]} { return $dnsdb(i,$n) } }
  return ""
}


set scriptdb(dnsdb) {
  "collects host and IP info from users"
}

