#!/usr/pkg/bin/ruby18 -Ku
# $Id: zc.rb,v 1.2 2004/09/07 10:07:09 sdalu Exp $

# 
# CONTACT     : http://www.dnsdoctor.org/
# AUTHOR      : Stephane D'Alu <sdalu@sdalu.com>
#
# CREATED     : 2002/07/18 10:29:53
# REVISION    : $Revision: 1.2 $ 
# DATE        : $Date: 2004/09/07 10:07:09 $
#
# CONTRIBUTORS: (see also CREDITS file)
#
#
# LICENSE     : GPL v2
# COPYRIGHT   : AFNIC (c) 2003
#
# This file is part of DNSdoctor.
#
# DNSdoctor 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.
# 
# DNSdoctor 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 DNSdoctor; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#


## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
##
## WARN: when editing this file on installed DNSdoctor, you should
##       keep in mind that some DNSdoctor variant (cgi, ...) are 
##       more or less strongly connected with this file by:
##       - a copy     : only THIS file will be modified
##       - a hardlink : depending of your editor behaviour when
##                      saving the file, all the files will hold
##                      the modification OR only this file will.
##       - a symlink  : no problem should occured (except if on Windows)
##
## !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


## --> CUSTOMIZATION <-- #############################################
# 
# You shouldn't really need to change these values:
#  - This is normally automatically done when performing a: make install
#  - Setting the environment variable DDOC_INSTALL_PATH should be enough
#     for testing the code
#

## Installation path
DDOC_INSTALL_PATH	= "/usr/pkg/libexec/dnsdoctor"

## Directories
DDOC_DIR		= "#{DDOC_INSTALL_PATH}/dnsdoctor"
DDOC_LIB		= "#{DDOC_INSTALL_PATH}/lib"

DDOC_CONFIG_DIR		= ENV['DDOC_CONFIG_DIR']       || "/usr/pkg/etc/dnsdoctor"
DDOC_LOCALIZATION_DIR	= ENV['DDOC_LOCALIZATION_DIR'] || "/usr/pkg/libexec/dnsdoctor/locale"
DDOC_TEST_DIR		= ENV['DDOC_TEST_DIR']         || "/usr/pkg/libexec/dnsdoctor/test"

## Configuration
DDOC_CONFIG_FILE	= ENV['DDOC_CONFIG_FILE'] || 'dnsdoctor.conf'

## Lang
DDOC_LANG_FILE		= 'dnsdoctor.%s'
DDOC_LANG_DEFAULT	= 'en'		# can have an enconding: en.ascii

## Message catalog fallback
DDOC_MSGCAT_FALLBACK	= 'en'		# don't specifie an encoding here

## Input methods
DDOC_DEFAULT_INPUT	= 'cli'

DDOC_CGI_ENV_KEYS	= [ 'GATEWAY_INTERFACE', 'SERVER_ADDR' ]
DDOC_CGI_EXT		= 'cgi'

DDOC_GTK_ENV_KEYS	= [] #[ 'DISPLAY' ]

## Publisher
DDOC_HTML_PATH		= ENV['DDOC_HTML_PATH'] || "/dnsdoctor"


## Contact / Details
DDOC_LICENSE		= 'GPL v2'
DDOC_COPYRIGHT		= "Stephane D'Alu (c) 2004\nAFNIC (c) 2003"
DDOC_CONTACT		= 'dnsdoctor-dev@ml.dnsdoctor.org'
DDOC_MAINTAINER		= 'Stephane D\'Alu <sdalu@sdalu.com>'
DDOC_WEB		= 'http://www.dnsdoctor.org/'

## Internal
DDOC_XML_PARSER		= ENV['DDOC_XML_PARSER'] 
DDOC_IP_STACK		= ENV['DDOC_IP_STACK'] || '46'

## --> END OF CUSTOMIZATION <-- ######################################


#
# Identification
#
DDOC_CVS_NAME	= %q$Name: DDOC-1_0_1 $
DDOC_NAME	= 'DNSdoctor'
DDOC_VERSION	= (Proc::new { 
		       n = DDOC_CVS_NAME.split[1]
		       n = /^DDOC-(.*)/.match(n) unless n.nil?
		       n = n[1]                  unless n.nil?
		       n = n.gsub(/_/, '.')      unless n.nil?
		       
		       n || '<unreleased>'
		   }).call
PROGNAME	= File.basename($0)


#
# Constants
#
EXIT_OK		=  0	# Everything went fine, no fatal error, domain ok
EXIT_FAILED	=  1	# The program completed but the result is negative
EXIT_TIMEOUT	=  2	# The program completed but the result is negative
			#  due to timeout.
EXIT_ABORTED	=  3	# The user aborted the program before completion
EXIT_ERROR      =  4	# An error unrelated to the result occured
EXIT_USAGE	=  9	# The user didn't bother reading the man page


#
# Sanity check
#
m = /^(\d+)\.(\d+)\.(\d+)/.match(RUBY_VERSION)
if (m[1].to_i <= 1) && (m[2].to_i < 8) && (m[3].to_i < 1)
    $stderr.puts "#{PROGNAME}: ruby version 1.8.1 at least is required."
    exit EXIT_ERROR
end


#
# Run at safe level 1
#  A greater safe level is unfortunately not possible due to some 
#  low level operations in the NResolv library
#
$SAFE = 1


#
# Ensure '.' is not one of the possible path (too much trouble)
# Add dnsdoctor directories to ruby path
#
$LOAD_PATH.delete_if { |path| path == '.' }
$LOAD_PATH << DDOC_DIR << DDOC_LIB


#
# Version / Name / Contact
#
$ddoc_version		||= DDOC_VERSION
$ddoc_name		||= DDOC_NAME
$ddoc_contact		||= DDOC_CONTACT
$ddoc_web		||= DDOC_WEB

#
# Config directory
# 
$ddoc_config_dir	||= DDOC_CONFIG_DIR
$ddoc_config_file	||= DDOC_CONFIG_FILE

#
# Custom
#
$ddoc_custom		||= 'dnsdoctor-custom'

#
# Internal
#
$ddoc_xml_parser	||= DDOC_XML_PARSER

# Resolver configuration
$nresolv_rootserver_hintfile	= "#{$ddoc_config_dir}/rootservers"
$nresolv_dbg			= 0x0000


#
# Requierement
#
# Standard Ruby libraries
require 'socket'

# External libraries
require 'nresolv'

# Modification to standard/core ruby classes
require 'ext/array'
require 'ext/file'
require 'ext/myxml'

# DNSdoctor component
require 'dbg'
require 'locale'
require 'msgcat'
require 'console'
require 'zonecheck'


#
# Debugger object
#  (earlier initialization, can also be set via input interface)
#
$dbg       = DBG::new
$dbg.level = ENV['DDOC_DEBUG'] if ENV['DDOC_DEBUG']


#
# XML parser
#
ENV['XML_CATALOG_FILES'] = "#{DDOC_DIR}/data/catalog.xml"

$dbg.msg(DBG::INIT) {
    shrinked_path = File.shrink_path(ENV['XML_CATALOG_FILES'], ':')
    "Using XML_CATALOG_FILES=#{shrinked_path}"
}
$dbg.msg(DBG::INIT) { "Using XML parser: #{MyXML::Implementation}" }



#
# IPv4/IPv6 stack detection
#  WARN: doesn't implies that we have also the connectivity
#
$ipv4_stack = !(DDOC_IP_STACK =~ /4/).nil?
$ipv6_stack = !(DDOC_IP_STACK =~ /6/).nil?
$ipv4_stack = $ipv6_stack = true if !$ipv4_stack && !$ipv6_stack

$ipv4_stack &&= begin
		    UDPSocket::new(Socket::AF_INET).close
		    true
		rescue NameError,       # if Socket::AF_INET doesn't exist
			SystemCallError # for the Errno::EAFNOSUPPORT error
		    false
		end
$ipv6_stack &&= begin
		    UDPSocket::new(Socket::AF_INET6).close
		    true
		rescue NameError,       # if Socket::AF_INET6 doesn't exist
			SystemCallError # for the Errno::EAFNOSUPPORT error
		    false
		end


#
# Internationalisation
#  WARN: default locale is mandatory as no human messages are
#        present in the code (except for debugging purpose)
#
begin
    # Initialize locale
    $locale = Locale::new
    $locale.lang = DDOC_LANG_DEFAULT if $locale.lang.nil?
    
    # Initialize the console
    $console = Console::new
    
    # Initialize the message catalog
    $mc = MsgCat::new(DDOC_LOCALIZATION_DIR, DDOC_MSGCAT_FALLBACK)

    # Add watcher for notification of locale changes
    #  ... and force update
    $locale.watch('lang', proc { 
		      $mc.language = $locale.language
		      $mc.country  = $locale.country
		      $mc.reload } )
    $locale.watch('encoding', proc { 
		      $console.encoding = $locale.encoding } )
    $locale.notify('lang', 'encoding')

    # Read msgcat
    $mc.read(DDOC_LANG_FILE)

rescue => e
    raise if $dbg.enabled?(DBG::DONT_RESCUE)
    $stderr.puts "ERROR: #{e.to_s}"
    exit EXIT_ERROR
end


#
# Load eventual custom version
#
begin 
    require $ddoc_custom
rescue LoadError => e
    $dbg.msg(DBG::INIT, "Unable to require '#{$ddoc_custom}' (#{e})")
end


#
# Adjustement due to dnsdoctor-custom
#
begin
    hintfile = "#{$ddoc_config_dir}/rootservers"
    if $nresol_rootserver_hintfile != hintfile
	NResolv::DNS::RootServer.current = NResolv::DNS::RootServer.from_hintfile(hintfile)
    end
rescue YAML::ParseError, SystemCallError => e
    $dbg.msg(DBG::INIT, 
	    "Unable to read/parse rootserver hint file (#{e})")
end


#
# Check it now!
#
exit ZoneCheck::new::start ? EXIT_OK : EXIT_FAILED
