#by wiebe @ QuakeNet

#+dnsdb		on/off


#excluded hostmask, if a user has a matching host, do not perform a dns lookup
set dnsdbs(exclude) "*.quakenet.org quakenet.org"


#code

setudef flag dnsdb



#join
bind join -|- * dnsdb:join
bind rejn -|- * dnsdb:join

proc dnsdb:join { nick uhost handle chan } {
  global dnsdb dnsdbchase
  if { ![channel get $chan dnsdb] } { return 0 }
  if { [isbotnick $nick] } {
    dnsdb:checkall
    set dnsdb($chan) 1
  } else {
    dnsdb:lookup $nick $chan
  }

#chase, unset when exists
  set nick [string tolower $nick]
  if { [info exists dnsdbchase($nick,host)] } { unset dnsdbchase($nick,host) }
  if { [info exists dnsdbchase($nick,ip)] } { unset dnsdbchase($nick,ip) }
}



#raw
bind raw - "315" dnsdb:raw

proc dnsdb:raw { server numeric text } {
  global dnsdb
  set chan [string tolower [lindex [split $text] 1]]
  if { ![info exists dnsdb($chan)] } { return 0 }
  if { ![validchan $chan] } { return 0 }
  if { ![botonchan $chan] } { return 0 }
  if { ![channel get $chan dnsdb] } { return 0 }
  unset dnsdb($chan)
  foreach nick [chanlist $chan] { if { [dnsdb:lookup $nick $chan] } { break } }
}



#part
bind part -|- * dnsdb:part
proc dnsdb:part { nick uhost handle chan {msg ""} } {
  if { [isbotnick $nick] } {
    dnsdb:checkall
  } elseif { ![dnsdb:comchan $nick $chan] } {
    dnsdb:unset $nick
  }
}



#kick
bind kick -|- * dnsdb:kick
proc dnsdb:kick { nick uhost handle chan target msg } {
  if { [isbotnick $target] } {
    dnsdb:checkall
  } elseif { ![dnsdb:comchan $target $chan] } {
    dnsdb:unset $target
  }
}



#quit
bind sign -|- * dnsdb:sign
bind splt -|- * dnsdb:sign
proc dnsdb:sign { nick uhost handle chan {msg ""} } {
  global dnsdb

#keep the ip and host info when they get a spoofed host (+x)
  if { ![string equal -nocase $msg registered] } {
    dnsdb:unset $nick
  } elseif { [string equal [dnsdb:host $nick] -1] && [string equal [dnsdb:ip $nick] -1] } {
    set host [lindex [split $uhost @] 1]
    set nick [string tolower $nick]
    set dnsdb($nick,host) $host
  }
}



#nick
bind nick -|- * dnsdb:nick

proc dnsdb:nick { nick uhost handle chan newnick } {
  global dnsdb
  set nick [string tolower $nick]
  set newnick [string tolower $newnick]
  if { [string equal $nick $newnick] } { return 0 }
  if { [info exists dnsdb($nick,host)] } {
    set dnsdb($newnick,host) $dnsdb($nick,host)
    unset dnsdb($nick,host)
  }
  if { [info exists dnsdb($nick,ip)] } {
    set dnsdb($newnick,ip) $dnsdb($nick,ip)
    unset dnsdb($nick,ip)
  }
}



#lookup
proc dnsdb:lookup { nick chan } {
  global dnsdb dnsdbs
  set nick [string tolower $nick]
  if { ![onchan $nick] || [onchansplit $nick] } { return 0 }
  if { ![validchan $chan] } { return 0 }
  if { ![botonchan $chan] } { return 0 }
  if { ![channel get $chan dnsdb] } { return 0 }
  if { [info exists dnsdb($nick,ip)] && [info exists dnsdb($nick,host)] } { return 0 }
  set host [lindex [split [getchanhost $nick] @] 1]

#saved when user set +x
  if { ![info exists dnsdb($nick,ip)] && [info exists dnsdb($nick,host)] } {
    set host $dnsdb($nick,host)
    unset dnsdb($nick,host)
  }

#excluded hosts
  if { [info exists dnsdbs(exclude)] } {
    set exhosts $dnsdbs(exclude)
    foreach exhost [split $exhosts] {
      if { [string match -nocase $exhost $host] } {
        set dnsdb($nick,host) ""
        set dnsdb($nick,ip) ""
        return 0
      }
    }
  }

#invalid host
  if { ![string match *.* $host] } {
    set dnsdb($nick,host) ""
    set dnsdb($nick,ip) ""
    return 0
  }
  dnslookup $host dnsdb:callback $nick $chan
  return 1
}



#callback
proc dnsdb:callback { ip host status nick chan } {
  global dnsdb
  if { ![validchan $chan] } { return 0 }
  if { ![botonchan $chan] } { return 0 }
  if { ![channel get $chan dnsdb] } { return 0 }
  if { [onchan $nick] && ![onchansplit $nick] } {
    if { [string equal $host $ip] } { set host "" }
    if { [string equal $ip 0.0.0.0] } { set ip "" }
    set dnsdb($nick,host) $host
    set dnsdb($nick,ip) $ip
  }
  if { ![validchan $chan] } { return 0 }
  foreach nick [chanlist $chan] { if { [dnsdb:lookup $nick $chan] } { break } }
}



#unset, called from kick, quit, part
proc dnsdb:unset { nick } {
  global dnsdb dnsdbchase
  set nick [string tolower $nick]
  if { [info exists dnsdb($nick,host)] } {

#chase host
    if { ![string equal $dnsdb($nick,host) ""] } {
      set dnsdbchase($nick,host) "[unixtime] $dnsdb($nick,host)"
    }

    unset dnsdb($nick,host)
  }
  if { [info exists dnsdb($nick,ip)] } {

#chase ip
    if { ![string equal $dnsdb($nick,ip) ""] } {
      set dnsdbchase($nick,ip) "[unixtime] $dnsdb($nick,ip)"
    }

    unset dnsdb($nick,ip)
  }
}



#time, part of chasing
bind time -|- * dnsdb:time

proc dnsdb:time { mi ho da mo ye } {
  global dnsdbchase
  foreach name [array names dnsdbchase] {
    if { [expr [unixtime] - [lindex [split $dnsdbchase($name)] 0]] > "86400" } {
      unset dnsdbchase($name)
    }
  }
}



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



#dnsdb:ip
#[dnsdb:ip <nick>], returns the ip or -1 if not yet looked up
proc dnsdb:ip { nick } {
  global dnsdb
  set nick [string tolower $nick]
  if { ![info exists dnsdb($nick,ip)] } { return -1 }
  if { ![onchan $nick] || [onchansplit $nick] } {
    unset dnsdb($nick,ip)
    if { [info exists dnsdb($nick,host)] } { unset dnsdb($nick,host) }
  } else {
    return $dnsdb($nick,ip)
  }
}



#dnsdbchase:ip
#[dnsdbchase:ip <nick>], returns the ip or -1 if not known
proc dnsdbchase:ip { nick } {
  global dnsdbchase
  set nick [string tolower $nick]
  if { ![info exists dnsdbchase($nick,ip)] } { return -1 }
  if { [expr [unixtime] - [lindex [split $dnsdbchase($nick,ip)] 0]] > "86400" } {
    unset dnsdbchase($nick,ip)
    return -1
  }
  return [lindex [split $dnsdbchase($nick,ip)] 1]
}



#dnsdb:host
#[dnsdb:host <nick>], returns the host or -1 if not yet looked up
proc dnsdb:host { nick } {
  global dnsdb
  set nick [string tolower $nick]
  if { ![info exists dnsdb($nick,host)] } { return -1 }
  if { ![onchan $nick] || [onchansplit $nick] } {
    unset dnsdb($nick,host)
    if { [info exists dnsdb($nick,ip)] } { unset dnsdb($nick,ip) }
  } else {
    return $dnsdb($nick,host)
  }
}



#dnsdbchase:host
#[dnsdbchase:host <nick>], returns the host or -1 if not known
proc dnsdbchase:host { nick } {
  global dnsdbchase
  set nick [string tolower $nick]
  if { ![info exists dnsdbchase($nick,host)] } { return -1 }
  if { [expr [unixtime] - [lindex [split $dnsdbchase($nick,host)] 0]] > "86400" } {
    unset dnsdbchase($nick,host)
    return -1
  }
  return [lindex [split $dnsdbchase($nick,host)] 1]
}



#connect
bind evnt -|- init-server dnsdb:connect
proc dnsdb:connect { type } {
  global dnsdb
  if { [info exists dnsdb] } { unset dnsdb }
}



#checkall
proc dnsdb:checkall { } {
  global dnsdb
  foreach name [array names dnsdb] {
    if { [string match *,ip $name] || [string match *,host $name] } {
      set nick [lindex [split $name ,] 0]
      if { ![onchan $nick] || [onchansplit $nick] } { unset dnsdb($name) }
    } elseif { ![validchan $name] } {
      unset dnsdb($name)
    }
  }
}

