#!/usr/bin/tclsh
################################################################################
#  
#  TCL scripts by Ofloo all rights reserved.
# 
#  HomePage: http://ofloo.net/
#  CVS: http://cvs.ofloo.net/
#  Email: support[at]ofloo.net
#  
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#   
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#  GNU General Public License for more details.
#   
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#   
################################################################################

#
# Easy install 
#
# 1st you down load it from the webserver.. to your shell
# 2nd you type "tar -jxvf filename" in your shell
# 3th you copy it to your script dir
# 4th you edit your eggdrop.conf file and add "source scripts/ip-to-country.tcl"
# 5th edit the settings below to your preference, now rehash your bot and you're done.
#

namespace eval ip2c {
  
  variable trigger "!ip2c" ;# channel trigger
  variable channel "#bluecat,#channel2,#channel3" ;# define your list of channels seperated by a ','
  variable flag "-" ;# this flag decides who gets to use your trigger
  variable ismode "0" ;# 0 public, 1: user needs to be voiced, 2:user needs halfops, 3: user needs ops

  #
  # cookies to use in msg templates.
  #
  #  %n% nick
  #  %c% channel
  #  %h% handle
  #  %k% short value ex: BE
  #  %l% long value ex: BEL
  #  %f% Full value ex: Belguim
  #  %i% input (nick,host,ip, .. !ip2c <input>)
  #
  
  #
  # templates
  #
  
  variable ip2cip "PRIVMSG %c% :Ip2c lookup for \(\002%i%\002\) is \(\002%f%\002\)." ;# lookup ipaddr
  variable ip2cnick "PRIVMSG %c% :Ip2c lookup for \(\002%i%\002\) is \(\002%f%\002\)." ;# lookup nickname
  variable ip2chost "PRIVMSG %c% :Ip2c lookup for \(\002%i%\002\) is \(\002%f%\002\)." ;# lookup hostname

  variable invalid "NOTICE %n% :Error usage: $trigger <nick|host|ip>." 
  variable unknown "PRIVMSG %c% :There are no results for \(\002%i%\002\)."
  variable dnserror "PRIVMSG %c% :Error couldn't associate an valid ip with \(\002%i%\002\)." 
  variable notonchan "PRIVMSG %c% :Error \(\002%i%\002\) is not on \(\002%c%\002\)." ;# user is not on channel

  #
  # Do not edit below if you do not know what it is you are doing.
  #
  
  variable version "0.7"
  variable longversion "1121868771"

  proc ip2c_pub {nick host hand chan arg} {
    variable invalid; variable ip2cip; variable unknown; variable notonchan
    if {[ischan $chan] && [ismode $nick $chan]} {
      if {[llength $arg] && ([llength $arg] < 2)} {
        if {[isip $arg]} {
          if {[catch {socket -async ip2c.ofloo.net 80} s]} {
            putlog "Error couldn't connect to webserver plz inform the webmaster at http://www.ofloo.net/."
            putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $unknown] -next
          } else {
          	fileevent $s writable [list [namespace current]::async_callback_ip $s $arg $nick $hand $chan $arg]
          }
        } elseif {[ishost $arg]} {
          dnslookup $arg [namespace current]::dns_callback_host $nick $hand $chan $arg
        } elseif {[onchan $arg $chan]} {
          dnslookup [lindex [split [getchanhost $arg] \x40] end] [namespace current]::dns_callback_nick $nick $hand $chan $arg
        } elseif {![onchan $arg $chan]} {
          putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $notonchan] -next
        } else {
          putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $invalid] -next
        }
      } else {
      	putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $invalid] -next
      }
    }
  }

  proc dns_callback_nick {ip host status nick hand chan arg} {
   variable dnserror; variable unknown
    if {$status} {
      if {[catch {socket -async ip2c.ofloo.net 80} s]} {
        putlog "Error couldn't connect to webserver plz inform the webmaster at http://www.ofloo.net/."
        putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $unknown] -next
      } else {
       	fileevent $s writable [list [namespace current]::async_callback_nick $s $ip $nick $hand $chan $arg]
      }
    } else {
    	putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $dnserror] -next
    }
  }

  proc dns_callback_host {ip host status nick hand chan arg} {
    variable dnserror; variable unknown
    if {$status} {
      if {[catch {socket -async ip2c.ofloo.net 80} s]} {
        putlog "Error couldn't connect to webserver plz inform the webmaster at http://www.ofloo.net/."
        putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $unknown] -next
      } else {
       	fileevent $s writable [list [namespace current]::async_callback_host $s $ip $nick $hand $chan $arg]
      }
    } else {
    	putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $dnserror] -next
    }
  }

  proc async_callback_host {s ip nick hand chan arg} {
    variable ip2chost; variable unknown; variable version
    if {[string equal {} [fconfigure $s -error]]} {
      flush $s
    	puts $s "GET /[ip2longip $ip] HTTP/1.1"
      puts $s "Host: ip2c.ofloo.net"
      puts $s "Connection: Close"
      puts $s "User-Agent: Ip-to-Country lookup script version $version\n"
      flush $s
      while {![eof $s]} {
        gets $s x
        if {[regexp -nocase {<resolve[\x20]{0,100}c02="([a-z]{2})"[\x20]{0,100}c03="([a-z]{3})"[\x20]{0,100}full="(.*?)"[\x20]{0,100}/>} $x -> k l f]} {
          putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% $k %l% $l %f% [wFormat $f]] $ip2chost] -next
          break
        }
      }
      close $s
      if {![info exists k]} {
        putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $unknown] -next
      }
    } else {
    	putlog "Error couldn't connect to webserver plz inform the webmaster at http://www.ofloo.net/."
    }
  }

  proc async_callback_nick {s ip nick hand chan arg} {
    variable ip2cnick; variable unknown; variable version
    if {[string equal {} [fconfigure $s -error]]} {
      flush $s
    	puts $s "GET /[ip2longip $ip] HTTP/1.1"
      puts $s "Host: ip2c.ofloo.net"
      puts $s "Connection: Close"
      puts $s "User-Agent: Ip-to-Country lookup script version $version\n"
      flush $s
      while {![eof $s]} {
        gets $s x
        if {[regexp -nocase {<resolve[\x20]{0,100}c02="([a-z]{2})"[\x20]{0,100}c03="([a-z]{3})"[\x20]{0,100}full="(.*?)"[\x20]{0,100}/>} $x -> k l f]} {
          putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% $k %l% $l %f% [wFormat $f]] $ip2cnick] -next
          break
        }
      }
      close $s
      if {![info exists k]} {
        putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $unknown] -next
      }
    } else {
    	putlog "Error couldn't connect to webserver plz inform the webmaster at http://www.ofloo.net/."
    }
  }

  proc async_callback_ip {s ip nick hand chan arg} {
    variable ip2cip; variable unknown; variable version
    if {[string equal {} [fconfigure $s -error]]} {
      flush $s
    	puts $s "GET /[ip2longip $arg] HTTP/1.1"
      puts $s "Host: ip2c.ofloo.net"
      puts $s "Connection: Close"
      puts $s "User-Agent: Ip-to-Country lookup script version $version\n"
      flush $s
      while {![eof $s]} {
        gets $s x
        if {[regexp -nocase {<resolve[\x20]{0,100}c02="([a-z]{2})"[\x20]{0,100}c03="([a-z]{3})"[\x20]{0,100}full="(.*?)"[\x20]{0,100}/>} $x -> k l f]} {
          putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% $k %l% $l %f% [wFormat $f]] $ip2cip] -next
          break
        }
      }
      close $s
      if {![info exists k]} {
        putserv [string map [list %n% $nick %h% $hand %i% $arg %c% $chan %k% {} %l% {} %f% {}] $unknown] -next
      }
    } else {
    	putlog "Error couldn't connect to webserver plz inform the webmaster at http://www.ofloo.net/."
    }
  }

  proc wFormat {arg} {
    foreach {w} [string tolower $arg] {
      if {[info exists word]} {unset word}
      foreach x [split $w {}] {
        if {[info exists word]} {
          append word $x
        } else {
    	    append word [string toupper $x]
        }
      }
      lappend str $word
    }
    return $str
  }

  proc longip2ip {long} {
    return [join [scan [format %.8x $long] %2x%2x%2x%2x] \x2e]
  }
  proc ip2longip {ip} {
    return [format %u 0x[eval format %.2x%.2x%.2x%.2x [split $ip \x2e]]]
  }


  proc isip {ip} {
    if {[regexp {^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$} $ip -> a b c d]} {
      if {($a <= 255) && ($b <= 255) && ($c <= 255) && ($d <= 255)} {
        return 1
      }
    }
    return 0
  }

  proc ishost {host} {
    if {[regexp -nocase {[a-z\-]{1,100}\.[a-z]{2,4}$} $host]} {
      return 1
    }
    return 0
  }

  proc ischan {chan} {
    variable channel
    foreach {x} [split $channel \x2c] {
      if {[string equal -nocase $x $chan]} {
        return 1
      }
    }
    return 0
  }

  proc ismode {nick chan} {
    variable ismode
    switch  -exact $ismode {
      "0" {
        return 1
      }
      "1" {
        if {[isvoice $nick $chan] || [ishalfop $nick $chan] || [isop $nick $chan]} {
          return 1 
        }
      }
      "2" {
        if {[ishalfop $nick $chan] || [isop $nick $chan]} {
          return 1 
        }
      }
      "3" {
        if {[isop $nick $chan]} {
          return 1 
        }
      }
    }
    return 0
  }

  bind pub $flag $trigger [namespace current]::ip2c_pub

################################################################################
  putlog "Loaded \002Ip-to-Country.tcl\002 version \002$version\002 by \002Ofloo\002 by http://solidservices.ro"

}
