From ba46c304bdffdce0b6019a47f6759ce6abbeef90 Mon Sep 17 00:00:00 2001 From: Stefan Ritter Date: Tue, 16 Aug 2011 10:51:41 +0200 Subject: Initial commit --- whoisd.tcl | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 whoisd.tcl (limited to 'whoisd.tcl') diff --git a/whoisd.tcl b/whoisd.tcl new file mode 100644 index 0000000..5047f0a --- /dev/null +++ b/whoisd.tcl @@ -0,0 +1,232 @@ +# whoisd.tcl -- 1.1 +# +# The whois command checks if a given domain is available or taken. +# The tld command returns which country sponsors the given tld. +# This script uses live servers so it is never outdated, unlike other scripts. +# +# I have tried a lot of existing domain whois scripts, none of them did what I wanted. +# So I decided to write my own, based on a similar script I wrote for mIRC. +# +# It is purposly made to be simple so it did not require much maintenance. +# +# Copyright (c) 2010 HM2K +# +# Name: domain whois and tld country code lookup (!whois and !tld) +# Author: HM2K +# License: http://www.freebsd.org/copyright/freebsd-license.html +# Link: http://www.hm2k.com/projects/eggtcl +# Tags: whois, lookup, domains, tld, country +# Updated: 29-Jul-2010 +# +###Usage +# !whois is the default public channel trigger for the whois function +# .whoisd is the default dcc command trigger the whois function +# !tld is the default public channel trigger for the tld function +# .tld is the default dcc trigger for the tld function +# +###Example +# > !whois hm2k.com +# whois: hm2k.com is taken! +# > !whois example-lame-domain.com +# whois: example-lame-domain.com is available! +# > !tld uk +# whois: Country for uk is United Kingdom +# +###Credits +# Thanks #eggtcl @ EFnet for some pointers +# +###Revisions +# 1.1 - iana changed their whois response; the whole script was revamped +# 1.0.3 - better documentation; fixed trigger; fixed timeouts; fixed available match +# 1.0.2 - further imrovements were made +# 1.0.1 - first public release + + +### Settings +set whoisd(cmd_dcc_domain) "whoisd"; #the dcc command - eg: whoisd +set whoisd(cmd_dcc_tld) "tld"; #the dcc tld command - eg: tld +set whoisd(cmd_pub_domain) "!whois"; #the pub command - eg: !whoisd +set whoisd(cmd_pub_tld) "!tld"; #the pub tld command - eg: !tld +set whoisd(data_country) "";#place holder for country data +set whoisd(data_type) "domain"; #default data type +set whoisd(debug) 1; #turn debug on or off +set whoisd(error_connect) "Error: Connection to %s:%s failed."; #Connection failed +set whoisd(error_connect_lost) "Error: Connection to server has been lost."; +set whoisd(error_invalid) "Error: Invalid %s."; #Invalid domain/tld error +set whoisd(flag) "-|-"; #flag required to use the script +set whoisd(nomatch_domain) "No match|not found|Invalid query|does not exist|no data found|status: avail|domain is available|(null)|no entries found|not registered|no objects found|domain name is not|Status:.*AVAILABLE"; #Replies from Whois Servers that match as "Available"... #TODO: split into new lines, join again later +set whoisd(nomatch_tld) "This query returned 0 objects."; #Error returned for invalid tld +set whoisd(notice_connect) "Connecting to... %s:%s (%s)"; #Connecting notice +set whoisd(output_country) "Country for %s is %s"; +set whoisd(output_found) "%s is available!"; +set whoisd(output_nomatch) "%s is taken!"; +set whoisd(output_timeout) "Connection to %s:%s timed out within %s seconds."; +set whoisd(port) 43; #The default whois server port - should not change +set whoisd(prefix) "whois:"; #prefix on output +set whoisd(regex_country) {address.*?:\s*(.+)$}; +set whoisd(regex_server) {whois.*?:\s*(.+)$}; +set whoisd(regex_valid_domain) {^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$}; #Regular expression used for validating domains +set whoisd(regex_valid_tld) {^\.?[a-z]+$}; +set whoisd(rplmode) 1; #reply mode (1:chan privmsg, 2:chan notice, 3:nick privmsg, 4:nick notice) +set whoisd(server) "whois.iana.org"; #The main whois server - should not change +set whoisd(timeout) 15; #server timeout in seconds - servers are quick, keep low +set whoisd(usage) "Usage: %s <%s>"; #Usage +set whoisd(ver) "1.1"; # version + + +### Package Definition +package require eggdrop 1.6; #see http://geteggdrop.com/ +package require Tcl 8.2.3; #see http://tinyurl.com/6kvu2n + + +### Binds +bind dcc $whoisd(flag) $whoisd(cmd_dcc_domain) whoisd:dcc_domain; +bind pub $whoisd(flag) $whoisd(cmd_pub_domain) whoisd:pub_domain; +bind dcc $whoisd(flag) $whoisd(cmd_dcc_tld) whoisd:dcc_tld; +bind pub $whoisd(flag) $whoisd(cmd_pub_tld) whoisd:pub_tld; + + +### Procedures +proc whoisd:validate {cmd word} { + if {[string compare $word ""] == 0} { + return [format $::whoisd(usage) $cmd $::whoisd(data_type)]; + } + if {![regexp $::whoisd(regex_valid) $word]} { + return [format $::whoisd(error_invalid) $::whoisd(data_type)]; + } + return; +} +proc whoisd:dcc_domain {hand idx text} { + set ::whoisd(data_type) "domain"; + set ::whoisd(cmd_dcc) $::whoisd(cmd_dcc_domain); + set ::whoisd(regex_valid) $::whoisd(regex_valid_domain); + return [whoisd:dcc $hand $idx $text]; +} +proc whoisd:pub_domain {nick uhost hand chan text} { + set ::whoisd(data_type) "domain"; + set ::whoisd(cmd_pub) $::whoisd(cmd_pub_domain); + set ::whoisd(regex_valid) $::whoisd(regex_valid_domain); + return [whoisd:pub $nick $uhost $hand $chan $text]; +} +proc whoisd:dcc_tld {hand idx text} { + set ::whoisd(data_type) "tld"; + set ::whoisd(cmd_dcc) $::whoisd(cmd_dcc_tld); + set ::whoisd(regex_valid) $::whoisd(regex_valid_tld); + return [whoisd:dcc $hand $idx $text]; +} +proc whoisd:pub_tld {nick uhost hand chan text} { + set ::whoisd(data_type) "tld"; + set ::whoisd(cmd_pub) $::whoisd(cmd_pub_tld); + set ::whoisd(regex_valid) $::whoisd(regex_valid_tld); + return [whoisd:pub $nick $uhost $hand $chan $text]; +} +proc whoisd:dcc {hand idx text} { + set word [lrange [split $text] 0 0]; + if {[set invalid [whoisd:validate ".$::whoisd(cmd_dcc)" $word]] != ""} { + whoisd:out 0 $idx {} $invalid; + return; + } + whoisd:connect 0 $idx {} $::whoisd(server) $::whoisd(port) $word; +} +proc whoisd:pub {nick uhost hand chan text} { + set word [lrange [split $text] 0 0]; + if {[set invalid [whoisd:validate $::whoisd(cmd_pub) $word]] != ""} { + whoisd:out 4 {} $nick $invalid; + return; + } + whoisd:connect $::whoisd(rplmode) $chan $nick $::whoisd(server) $::whoisd(port) $word; +} + + +proc whoisd:out {type dest nick text} { + if {[string length [string trim $text]] < 1} { return; } + switch -- $type { + "0" { putdcc $dest "$::whoisd(prefix) $text"; } + "1" { putserv "PRIVMSG $dest :$::whoisd(prefix) $text"; } + "2" { putserv "NOTICE $dest :$::whoisd(prefix) $text"; } + "3" { putserv "PRIVMSG $nick :$::whoisd(prefix) $text"; } + "4" { putserv "NOTICE $nick :$::whoisd(prefix) $text"; } + "5" { putlog "$::whoisd(prefix) $text"; } + } +} +proc whoisd:connect {type dest nick server port word} { + putlog [format $::whoisd(notice_connect) $server $port $word]; + if {[catch {socket -async $server $port} sock]} { + whoisd:out $type $dest $nick [format $::whoisd(error_connect) $server $port]; + return; + } + #TODO: too long; must be split + fileevent $sock writable [list whoisd:write $type $dest $nick $word $sock $server $port [utimer $::whoisd(timeout) [list whoisd:timeout $type $dest $nick $server $port $sock $word]]]; +} +proc whoisd:write {type dest nick word sock server port timerid} { + if {[set error [fconfigure $sock -error]] != ""} { + whoisd:out $type $dest $nick [format $::whoisd(error_connect) $server $port]; + whoisd:die $sock $timerid; + return; + } + set word [string trim $word .]; + if {$server == $::whoisd(server)} { + set lookup [lrange [split $word "."] end end]; + } else { + set lookup $word; + } + puts $sock "$lookup\n"; + flush $sock; + fconfigure $sock -blocking 0; + fileevent $sock readable [list whoisd:read $type $dest $nick $word $sock $server $port $timerid]; + fileevent $sock writable {}; +} +proc whoisd:read {type dest nick word sock server port timerid} { + while {![set error [catch {gets $sock output} read]] && $read > 0} { + if {!$type} { whoisd:out $type $dest $nick $output; } + if {$server == $::whoisd(server)} { + if {[regexp $::whoisd(nomatch_tld) $output]} { + set output [format $::whoisd(error_invalid) "tld"]; + whoisd:out $type $dest $nick $output; + whoisd:die $sock $timerid; + } + if {$::whoisd(data_type) == "tld"} { + if {[regexp $::whoisd(regex_country) $output -> country]} { + set ::whoisd(data_country) $country; + } + } elseif {[regexp -nocase -- $::whoisd(regex_server) $output -> server]} { + whoisd:connect $type $dest $nick $server $port $word; + whoisd:die $sock $timerid; + } + } else { + if {[regexp -nocase -- $::whoisd(nomatch_domain) $output]} { + set output [format $::whoisd(output_found) $word]; + whoisd:out $type $dest $nick $output; + whoisd:die $sock $timerid; + } + } + if {$error} { + whoisd:out $type $dest $nick $::whoisd(error_connect_lost); + whoisd:die $sock $timerid; + } + } +} +proc whoisd:die {sock timerid} { + catch { killutimer $timerid } + catch { close $sock } +} +proc whoisd:timeout {type dest nick server port sock word} { + catch { close $sock } + if {$server != $::whoisd(server)} { + set output [format $::whoisd(output_nomatch) $word]; + whoisd:out $type $dest $nick $output; + return; + } elseif {$::whoisd(data_country) != ""} { + set output [format $::whoisd(output_country) $word $::whoisd(data_country)]; + } else { + set output [format $::whoisd(output_timeout) $server $port $::whoisd(timeout)]; + } + whoisd:out $type $dest $nick $output; +} + + +### Loaded +putlog "whoisd.tcl $whoisd(ver) loaded"; + + +#EOF -- cgit v1.2.3