# rconf.pl - read configuration file
#
# Copyright (c) 1993, 1994, 1995, 1996, 1997  The TERENA Association
# Copyright (c) 1998                              RIPE NCC
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies and that
# both that copyright notice and this permission notice appear in
# supporting documentation, and that the name of the author not be
# used in advertising or publicity pertaining to distribution of the
# software without specific, written prior permission.
#
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
# ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
# AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#
# $Id: rconf.pl,v 2.22 2000/02/17 17:15:07 marek Exp $
#
#	$RCSfile: rconf.pl,v $
#	$Revision: 2.22 $
#	$Author: marek $
#	$Date: 2000/02/17 17:15:07 $
#
#       This routine reads all parameters from the configuration file
#       into scalars or associative arrays of the same name (uppercase).
#       Multi line texts are stored as scalar strings with embdded "\n"s.
#       Note the special variable names for the OBJ configuration.
#
#       Arguments:
#
#       $confname       name of the configuration file

require "defines.pl";
require "defaults.pl";		# file containing some default configuration
				# definitions.
require "syslog.pl";
require "misc.pl";

require "read_attr.pl";
require "read_objs.pl";

sub rconf {
    local($confname) = @_;

    #
    # set the program name correctly

    if ($0=~ /\//) {
       ($PROGRAMNAME)= $0 =~ /\/([^\/]*)$/;
    }
    else {
       $PROGRAMNAME=$0;
    }
    $0=$PROGRAMNAME;
    
    #
    # needed in several routines...
    
    ($DATE,$TIME)=&getYYYYMMDDandHHMMSS(); 
    
    #
    # set a safe umask
    
    umask(022);

    rconfreadfile($confname);

    rconfprocess();
}

sub rconfreadfile {
    my($confname) = @_;
    my($i);
    my($newconf);
    local *CONF;
    
    open(CONF, $confname) || &fatalerror("rconf: cannot open config \"$confname\", $!");

    # print STDERR "Reading configuration from $confname\n";

    while (<CONF>) {
	
	study $_;

	next if (/^\#/);
	next if (/^\s*$/);

	# print STDERR "++++ $_";
		
	last if (/^ENDCONF/);

	if (/^INCLUDE\s+(\S+)/) {
	    $newconf=$1;
	    if($newconf !~ m|/|)
		{
		$newconf=substr($confname,0,rindex($confname,"/")+1) . $newconf;
		}
	    &rconfreadfile($newconf);	    
	    next;
	}


        if (/^COUNTRY\s+(..)\s+(..)/) { 
	    $COUNTRY{$1}=$1; $COUNTRY{$2}=$1; 
	    next;
	}

        if (s/^OBJ\s+(\S\S)\s+(\S+)\s+//) {
           
           my $type=$1;
           my $field=$2;
           
           s/\s+/ /g;
           s/ $//;
           
           if ($field eq "ATSQ") {
              if ($OBJATSQ{$type}) {
                 $OBJATSQ{$type}=join(" ", $OBJATSQ{$type}, $_);
              }
              else {
                 $OBJATSQ{$type}=$_;
              }
           }
           elsif ($field eq "MAND") {
              if ($OBJMAND{$type}) {
                 $OBJMAND{$type}=join(" ", $OBJMAND{$type}, $_);
              }
              else {
                 $OBJMAND{$type}=$_;
              }
           }
           elsif ($field eq "MULT") {
              if ($OBJMULT{$type}) {
                 $OBJMULT{$type}=join(" ", $OBJMULT{$type}, $_);
              }
              else {
                 $OBJMULT{$type}=$_;
              }
           }
           elsif ($field eq "KEYS") {
              if ($KEYS{$type}) {
                 $KEYS{$type}=join(" ", $KEYS{$type}, $_);
              }
              else {
                 $KEYS{$type}=$_;
              }
           }
           
           elsif ($field eq "UNIQ") {
              if ($UNIQ{$type}) {
                 $UNIQ{$type}=join(" ", $UNIQ{$type}, $_);
              }
              else {
                 $UNIQ{$type}=$_;
              }
           }
           elsif ($field eq "REC") {
              if ($RECUR{$type}) {
                 $RECUR{$type}=join(" ", $RECUR{$type}, $_);
              }
              else {
                 $RECUR{$type}=$_;
              }
           }
           elsif ($field eq "OBS") {
              if ($OBS{$type}) {
                 $OBS{$type}=join(" ", $OBS{$type}, $_);
              }
              else {
                 $OBS{$type}=$_;
              }
           }

	   elsif ($field eq "INV") {
	      if ($INV{$type}) {
		 $INV{$type}=join(" ", $INV{$type}, $_);
	      }
	      else {
		 $INV{$type}=$_;
	      }
           }
           elsif ($field eq "GEN") {
             if ($GEN{$type}) {
                $GEN{$type}=join(" ", $GEN{$type}, $_);
             }
             else {
                $GEN{$type}=$_;
             }
	   }
           
           # print STDERR "-",$KEYS{$type}, "-\n";
           
           next;

        }
        
	if (/^ATTR\s+(..)\s+(\S+)  (\s+([^\s\#]+))? (\s+([^\s\#]+))?/x) { 
#             |       |     ||     |   ||           |   ||           
#             ATTR    tc    |tech-c|   |pn,ro       |   |nic
#                     $1    $2     $3  $4           $5  $6
#
	   $ATTR{$1}=$1; $ATTR{$2}=$1; $ATTL{$1}=$2;
	    
	   $MAXATTRIBUTELENGTH=length($2) if (length($2)>$MAXATTRIBUTELENGTH);
	    
	   if ($4) {
	      my($tag) = $1;
	       
	      $POINTSTO{$tag} = $4;
	      $POINTSTO{$tag} =~ s/\s+$//;
	      $POINTSTO{$tag} =~ s/\,/ /g;
	   }
	   if ($6) {
	       my($tag) = $1;
	    
	       if ($6 eq 'nic') {
		   $POINTSTONIC{$tag} = 1;
	       }
	       else {
		   $POINTSTOMT{$tag} = 1;
	       }
	   }

	   next;
	   
	}
	
	# the following 4 options allow a LIST of IP's 
	# to be specified on a line
	
	if (/^GETUPDATESFROM\s+(.*)/) { 
	    push(@GETUPDATESFROM, split(/\s+/, $1)); next; 
	}
	if (/^DENYWHOISACCESS\s+(.*)/) { 
	    push(@DENYWHOISACCESS, split(/\s+/, $1)); next;
	}
	if (/^WHOISUPDFROM\s+(.*)/) { 
	    push(@WHOISUPDFROM, split(/\s+/, $1)); next; 
	}
	if (/^AUTHORIZEDFORREFERRAL\s+(.*)/) { 
	    push(@AUTHORIZEDFORREFERRAL, split(/\s+/, $1)); next; 
	}

        
	if (/^BINDADDR\s+(\d+\.\d+\.\d+\.\d+)\s*$/) { $BINDADDR = $1; next; }
	if (/^BINDPORT\s+(\d+)\s*$/) { $BINDPORT = $1; next; }
	if (/^MAILTXT\s+(.*)/) { $MAILTXT.=$1."\n"; next;}
	if (/^ACKSIG\s+(.*)/) { $ACKSIG=$ACKSIG.$1."\n"; next;}
	if (/^RIGHTS\s+(.*)/) { $RIGHTS.=$1."\n"; next; }
	if (/^REPLYBANNER\s+(.*)/) { $REPLYBANNER.=$1."\n"; next; }
	if (/^NOMATCH\s+(.*)/) { $NOMATCH.=$1."\n"; next; }
	if (/^FWTE?XT\s+(.*)/) { $FWTXT.=$1."\n"; next;}
	if (/^FWMAILTXT\s+(.*)/) { $FWMAILTXT.=$1."\n"; next;}
	if (/^FWNETWORKTXT\s+(.*)/) { $FWNETWORKTXT.=$1."\n"; next;}
	if (/^MTFWTE?XT\s+(.*)/) { $MTFWTXT.=$1."\n"; next;}
	if (/^NOTITXT\s+(.*)/) { $NOTITXT.=$1."\n";next;}
	if (/^NOTIMAILTXT\s+(.*)/) { $NOTIMAILTXT.=$1."\n";next;}
	if (/^NOTINETWORKTXT\s+(.*)/) { $NOTINETWORKTXT.=$1."\n";next;}
	if (/^CONGRAT\s+(.*)/) { $CONGRAT=$CONGRAT.$1."\n"; next;}
	if (/^ACKERR\s+(.*)/) { $ACKERR=$ACKERR.$1."\n"; next;}
	if (/^NHEADER\s+(.*)/) { $NHEADER.=$1."\n";next;}
	if (/^MHEADER\s+(.*)/) { $MHEADER.=$1."\n"; next;}
	if (/^FWHEADER\s+(.*)/) { $FWHEADER.=$1."\n"; next;}
	if (/^MTFWHEADER\s+(.*)/) { $MTFWHEADER.=$1."\n"; next;}
	if (/^ACKOK\s+(.*)/) { $ACKOK=$ACKOK.$1."\n"; next;}

	if (/^FHEADER\s+(.*)/) { $FHEADER.=$1."\n"; next;}
	if (/^SUCCESSTXT\s+(.*)/) { $SUCCESSTXT.=$1."\n"; next;}
	if (/^FAILURETXT\s+(.*)/) { $FAILURETXT.=$1."\n"; next;}
	if (/^HELPHEADER\s+(.*)/) { $HELPHEADER.=$1."\n"; next;}
	
	if (/^ATTA\s+(..)\s+(\S*)/)  { $ATTR{$2}=$1; next;}
	if (/^REFERRALTXT\s+(.*)/)   { $REFERRALTXT.=$1."\n"; next;}
	if (/^DENYACCESSTXT\s+(.*)/) { $DENYACCESSTXT.=$1."\n"; next;}
	if (/^REFERRALERRORTXT\s+(.*)/) { $REFERRALERRORTXT.=$1."\n"; next;}
	if (/^REFERRALLOOPERRORTXT\s+(.*)/) 
	    { $REFERRALLOOPERRORTXT.=$1."\n"; next;}
	if (/^REFERRALTIMEOUTTXT\s+(.*)/) 
	    { $REFERRALTIMEOUTTXT.=$1."\n"; next;}
	if (/^REFERRALTRUNCTXT\s+(.*)/) 
	    { $REFERRALTRUNCTXT.=$1."\n"; next;}
	if (/^REFERRALENDTXT\s+(.*)/)
	    { $REFERRALENDTXT.=$1."\n"; next;}
	if (/^REFERRALTIMEOUT\s+(\d+)/) {$REFERRALTIMEOUT = $1; next}
	if (/^REFERRALMAXLINES\s+(\d+)/) {$REFERRALMAXLINES = $1; next}
	if (/^DENYREFERRALTXT\s+(.*)/)   { $DENYREFERRALTXT.=$1."\n"; next;}
	if (/^DENYACCESSTHRUREFERRALTXT\s+(.*)/)   { $DENYACCESSTHRUREFERRALTXT.=$1."\n"; next;}

	if (/^QUERYLOOPLIMIT\s+(\d+)/) { $QUERYLOOPLIMIT = $1; next;}
	if (/^QUERYLOOPTXT\s+(.*)/)   { $QUERYLOOPTXT.=$1."\n"; next;}

	if (/^WHOISDSTAT\s+(.*)/) { $WHOISDSTAT = $1; next;}
	
	# we substract 10 to compensate for the extra bytes
	# needed at the end of key, value and additional value
	# plus comma and some bytes more to stay at the safe site ;-)
	if (/^OVERFLOWSIZE\s+(\d+)/) { $OVERFLOWSIZE=$1-10; next; }

	if (/^DBCACHESIZE\s+(\d+)/) { $DBCACHESIZE=$1; next; }
	if (/^MAXLISTLENGTH\s+(\d+)/) { $MAXLISTLENGTH=$1; next; }
	if (/^MAXSTRINGCOMPONENTS\s+(\d+)/) { $MAXSTRINGCOMPONENTS=$1; next; }
	
	if (/^TESTMODE\s+(\d+)/) {$TESTMODE=$1; next;}
	if (/^KEEPOPEN\s+(\d+)/) {$KEEPOPEN=$1; next;}
	if (/^NROFNAMES\s+(\d+)/) {$NROFNAMES=$1; next;}
	if (/^OVERRIDECRYPTEDPW\s+(\S+)/) { $OVERRIDECRYPTEDPW=$1; next; }

	if (/^DUPLICATEPERSONCHECK\s+(\S+)/) { 
	    $DUPLICATEPERSONCHECK=$1;
	    next;
	}
	
	# should check value - NOTIFY or ACK
	if (/^SUPPRESSMESS\s+(\S+)/) { $SUPPRESSMESS = $1; next; }

	if (/^DEFMAIL\s+(\S+)/) { $DEFMAIL=$1; next;}
	if (/^HUMAILBOX\s+(\S+)/) {$HUMAILBOX=$1; next;}
	if (/^AUTOBOX\s+(\S+)/) {$AUTOBOX=$1; next;}
	if (/^TMPDIR\s+(\S+)/) { $TMPDIR=$1; next;}
	
	if (/^MAILCMD\s+(.*)/) { $MAILCMD=$1; next;}

        if (/^PGPV\s+(.*)/) { $PGPV=$1; next;}
        if (/^PGPK\s+(.*)/) { $PGPK=$1; next;}
	if (/^PGPPATH\s+(.*)/) { $PGPPATH=$1; next;}

	if (/^CANUPD\s+(.+)$/) {
	   foreach (split(/ /, $1)) {
	      $CANUPD{$_}=1 if ($_);
	   }
	   next;
	}

        if (/^ALLOCMNT\s+(.+)$/) {
	   foreach (split(/\s+/, $1)) {
	      $ALLOCMNT{$_}=1;
	   }
    	   next;
        }

	# CROSSNOTIFYSOURCES <source> <list of sources to search for conflicts>
	# $::CROSSNOTIFYSOURCES - hash indexed on source name
	#                      - values are refs to arrays of source names
	if (/^CROSSNOTIFYSOURCES\s+/) {
	  use strict;

	  my(@sources) = split;
	  next unless @sources > 2;

	  shift @sources;   # skip keyword

	  my($key) = shift @sources;
	  $::CROSSNOTIFYSOURCES{$key} = \@sources;
	  next;
	}

	# '\s+' will greedily match all whitespace so we want everything
	# after the match - ie $'
	if (/^CN_SUBJECT_ADD\s+/) { $::CN_ADD{SUBJECT} .= $'; next; }
	if (/^CN_EXPLAIN_ADD\s+/) { $::CN_ADD{EXPLAIN} .= $'; next; }
	if (/^CN_OVERLAP_ADD\s+/) { $::CN_ADD{OVERLAP} .= $'; next; }
	if (/^CN_SUBJECT_DEL\s+/) { $::CN_DEL{SUBJECT} .= $'; next; }
	if (/^CN_EXPLAIN_DEL\s+/) { $::CN_DEL{EXPLAIN} .= $'; next; }
	if (/^CN_OVERLAP_DEL\s+/) { $::CN_DEL{OVERLAP} .= $'; next; }

	if (/^CNO_SUBJECT_ADD\s+/) { $::CNO_ADD{SUBJECT} .= $'; next; }
	if (/^CNO_EXPLAIN_ADD\s+/) { $::CNO_ADD{EXPLAIN} .= $'; next; }
	if (/^CNO_OVERLAP_ADD\s+/) { $::CNO_ADD{OVERLAP} .= $'; next; }
	if (/^CNO_SUBJECT_DEL\s+/) { $::CNO_DEL{SUBJECT} .= $'; next; }
	if (/^CNO_EXPLAIN_DEL\s+/) { $::CNO_DEL{EXPLAIN} .= $'; next; }
	if (/^CNO_OVERLAP_DEL\s+/) { $::CNO_DEL{OVERLAP} .= $'; next; }

#	if (/^CNO_SUBJECT_ADD\s+(\S+)/) { $::CNO_SUBJECT_ADD .= $1; next; }
#	if (/^CNO_SUBJECT_DEL\s+(\S+)/) { $::CNO_SUBJECT_DEL .= $1; next; }
#	if (/^CNO_EXPLAIN_ADD\s+(\S+)/) { $::CNO_EXPLAIN_ADD .= $1; next; }
#	if (/^CNO_EXPLAIN_DEL\s+(\S+)/) { $::CNO_EXPLAIN_DEL .= $1; next; }
#	if (/^CNO_OVERLAP_ADD\s+(\S+)/) { $::CNO_OVERLAP_ADD .= $1; next; }
#	if (/^CNO_OVERLAP_DEL\s+(\S+)/) { $::CNO_OVERLAP_DEL .= $1; next; }

	if (/^DEFLOOK\s+(\S.*)/) { $DEFLOOK.=" ".$1; $DEFLOOK=~ s/\s+/ /g; $DEFLOOK=~ s/^ //; $DEFLOOK=~ s/ $//; next; }
	if (/^ALLLOOK\s+(\S.*)/) { print STDERR "ALLLOOK variable is now auto-generated from the DBFILE variable"; next }
	
	if (/^DBFILE\s+(\S+)\s+(\S+)(\s+\S.*)?\s*$/) { 
	   
	   local($source)=$1;
	   $DBFILE{$source}=$2;
	   $NICPOSTFIX{$source}=$source;
	                                           
	   if ($3=~ /^\s*(\S+)(\s+\S+)?\s*$/) {
	                                           
	      if ($1 eq "SPLIT") {
	      
	         $SPLIT{$source}=1;
	      
	         if ($2) {
                    $NICPOSTFIX{$source}=$2;
                    $NICPOSTFIX{$source}=~ s/^\s+//;
                 }
              
              }
              else {
              
                 $NICPOSTFIX{$source}=$1;
              
                 $SPLIT{$source}=1 if ($2=~ /^\s+SPLIT$/);
              
              }
              
              if ($SPLIT{$source}) {
                 $SPLIT{$DBFILE{$source}}=1;
                 $SPLIT{$DBFILE{$source}.$CLASSLESSEXT}=1;
              }
              
           }

           if ($ALLLOOK) {
	      $ALLLOOK.=" ".$source;
	   }
	   else {
	      $ALLLOOK=$source;
	   }
	   
           next;
           
        }

        if (/^PIDFILE\s+(\S+)/) { $PIDFILE = $1; next; }
	
	if (/^AUTODBMHELP\s+(\S+)/) { $AUTODBMHELP=$1; next; }

	if (/^WHOISHELP\s+(\S+)/) { $WHOISHELP=$1; next; }

	if (/^ATTDESC\s+(\S+)/) {$ATTDESC=$1; next; }
	if (/^OBJDESC\s+(\S+)/) {$OBJDESC=$1; next }

	if (/^QRYLOGFLAGS\s+?(\S+)?/) { $QRYLOGFLAGS=($1 eq '') ? 1 : $1; next; }
	if (/^QRYLOG\s+(\S+)/) { $LOGFILE{"QRYLOG"}=$1; next; }
	if (/^QRY2LOG\s+(\S+)/) { 
		&fatalerror("The config option QRY2LOG is no longer available \n");
	}
	if (/^ERRLOG\s+(\S+)/) { $LOGFILE{"ERRLOG"}=$1; next; }
	if (/^AUDITLOG\s+(\S+)/) { $LOGFILE{"AUDITLOG"}=$1; next; }
	if (/^UPDLOG\s+(\S+)/) { $LOGFILE{"UPDLOG"}=$1; next; }
	if (/^ACKLOG\s+(\S+)/) { $LOGFILE{"ACKLOG"}=$1; next; }
	if (/^LOCKDIR\s+(\S+)/) { $LOCKDIR=$1."/"; next; }
	if (/^SERIALDIR\s+(\S+)/) { $LOGFILE{"SERIALDIR"}=$1."/"; next; }
	if (/^OLDSERIALDIR\s+(\S+)/) { $LOGFILE{"OLDSERIALDIR"}=$1."/"; next; }
	if (/^SERIALINCOMINGDIR\s+(\S+)/) { $LOGFILE{"SERIALINCOMINGDIR"}=$1."/"; next; }
	if (/^CLEANLOCK\s+(\S+)/) {$CLEANLOCK = $1; next; }
	if (/^UPDATELOCK\s+(\S+)/) {$UPDATELOCK = $1; next; }
	if (/^RENICECMD\s+(\S+)/) {$RENICECMD = $1; next; }

#	if (/^CLIENTFILTER\s+(\S+)/) {cf_add_entry($1); next;}
#	if (/^DYNAMICFILTER\s+(\d+)\s+(\d+)(.*)/) {
#	  $DYNAMICFILTERSIZE=$1;
#	  $DYNAMICFILTERLEVEL=$2;
#	  $DYNAMICFILTER++ unless ($3 =~ /\s*no/i);
#	  next;
#	}

	if (/^UID\s+(\S+)/) { 
	
	   $UID=$1;
	   
	   if ($UID=~ /^\d+$/) {
	      ($UID, $GID)=(getpwuid($UID))[2..3];
	   }
	   else {
	      ($UID, $GID)=(getpwnam($UID))[2..3];
	   }
	   
	   next;
	   
	}
	
	&fatalerror("Unknown config option: $_\n");
	
    }
    close(CONF);


}


sub rconfprocess{
    
    local($j,@tmp);
    local(%ALLPOINTSTO)=();
    local(%ALLPOINTSTONICATTR)=();
    local(%ALLPOINTSTOMTATTR)=();
    local(%ALLPOINTSTOATTR)=();
    local(%ALLKEYS)=();
    local(%OBJPOINTSTOTMP);
    local(%OBJPOINTSTOATTRTMP);
    local(%OBJPOINTSTONICATTRTMP);
    local(%OBJPOINTSTOMTATTRTMP);
    local(%OBJKEYSTMP);
    local(%ALLOBJORDEREDTMP);
    
    foreach $i (keys %OBJATSQ) {
     
#       $ALLNICPOINTSTO.=" ".$i if ($POINTSTO{$i}=~ /\b(ro|pn)\b/);
#       $ALLMTPOINTSTO.=" ".$i if ($POINTSTO{$i}=~ /\b(mt)\b/);
       
       #
       # NIC handle DBS'es
       
       push(@NICHANDLEDBS, $i) if ($OBJATSQ{$i}=~ /\b(nh)\b/);  
       
       #
       # CLASSLESS DBS'es
       
       if ($POINTSTO{$i} eq "CLASSLESS") {
          $CLASSLESSDBS{$i}=1;
          delete($POINTSTO{$i});
          # print STDERR "classless: $i\n";
       }
       
       #
       # Which object points to which other objects ?!?
       
       %OBJPOINTSTOTMP=();
       %OBJPOINTSTOATTRTMP=();
       %OBJPOINTSTONICATTRTMP=();
       %OBJPOINTSTOMTATTRTMP=();				   
       %OBJKEYSTMP=();

       @tmp=grep(!$OBJATSQ{$_}, split(/ /, $KEYS{$i}));
       
       if (@tmp) {
          @KEYS{@tmp}=(1) x @tmp;
          @OBJKEYSTMP{@tmp}=(1) x @tmp;
          @ALLKEYS{@tmp}=(1) x @tmp;
       }

       if ($KEYS{$i}) {
          $OBJKEYSTMP{$i}=1;
          $ALLKEYS{$i}=1;
       }
       
       foreach $j (split(/ /, $OBJATSQ{$i})) {
          
          next if (!$POINTSTO{$j});
          
          $OBJKEYSTMP{$j}=1;
          $ALLPOINTSTOATTR{$j}=1;
          $ALLPOINTSTONICATTR{$j}=1 if ($POINTSTONIC{$j});
          $ALLPOINTSTOMTATTR{$j}=1 if ($POINTSTOMT{$j});
          $OBJPOINTSTOATTRTMP{$j}=1;
	  $OBJPOINTSTONICATTRTMP{$j} = 1 if ($POINTSTONIC{$j});
	  $OBJPOINTSTOMTATTRTMP{$j} = 1 if ($POINTSTOMT{$j});
           
          @tmp=split(/ /, $POINTSTO{$j});
             
          @OBJPOINTSTOTMP{@tmp}=(1) x @tmp;
          @ALLPOINTSTO{@tmp}=(1) x @tmp;

       }
             
       $OBJPOINTSTO{$i}=join(" ", keys %OBJPOINTSTOTMP);
       $OBJPOINTSTOATTR{$i}=join(" ", keys %OBJPOINTSTOATTRTMP);
       $OBJPOINTSTONICATTR{$i}=join(" ", keys %OBJPOINTSTONICATTRTMP);
       $OBJPOINTSTOMTATTR{$i}=join(" ", keys %OBJPOINTSTOMTATTRTMP);
       $OBJPOINTSTONICMTATTR{$i}=$OBJPOINTSTONICATTR{$i}." ".$OBJPOINTSTOMTATTR{$i};
       $OBJKEYS{$i}=join(" ", keys %OBJKEYSTMP);
       
       # print STDERR "keys ($i): $OBJKEYS{$i}\npoints to ($i): $OBJPOINTSTO{$i}\n";
       
    }
    
#    $ALLNICPOINTSTO=~ s/^ //;
#    $ALLMTPOINTSTO=~ s/^ //;
 
    $ALLPOINTSTONIC   = 'pn ro';
    $ALLPOINTSTOMT    = 'mt';
    $ALLPOINTSTONICMT = $ALLPOINTSTONIC . " " . $ALLPOINTSTOMT;
   
    $ALLPOINTSTO = join(" ", keys %ALLPOINTSTO);
    $ALLPOINTSTOATTR = join(" ", keys %ALLPOINTSTOATTR);
    $ALLPOINTSTONICATTR = join(" ", keys %ALLPOINTSTONICATTR);
    $ALLPOINTSTOMTATTR = join(" ", keys %ALLPOINTSTOMTATTR);
    $ALLPOINTSTONICMTATTR = $ALLPOINTSTONICATTR . " " . $ALLPOINTSTOMTATTR;
    $ALLKEYS=join(" ", keys %ALLOBJKEYS);
    
    %ALLOBJORDEREDTMP = %OBJATSQ;
    foreach (split(/ /, $ALLPOINTSTONICMT)) {
	delete($ALLOBJORDEREDTMP{$_});
    }
    @ALLOBJORDERED = sort keys %ALLOBJORDEREDTMP;
    push(@ALLOBJORDERED, split(/ /, $ALLPOINTSTONICMT));
    $ALLOBJORDERED = join(" ", @ALLOBJORDERED);

    if (%CLASSLESSDBS) {
       
       local($db);
       foreach $db (keys %DBFILE) {
       
          $CLASSLESSDBS{$db}=1 if ((!$SPLIT{$_}) || (grep(($db eq $_) && ($CLASSLESSDBS{$_}), values %DBFILE)));
       
       }
       
       #
       # for generating the keys when the type is unknown.
       $CLASSLESSDBS{""}=1;
       
    }
    
    # print STDERR "all keys: $ALLKEYS\nall pointsto: $ALLPOINTSTO\n";
    
    $CLEANLOCK=$LOCKDIR.$CLEANLOCK.".";
    $UPDATELOCK=$LOCKDIR.$UPDATELOCK;
    
    ##
    ## check if everything is in place
    ##				  
    
    # check mandatory variables have been defined
    {
      use strict;

      # list of variable names to check
      my @mandatory = qw( OVERFLOWSIZE DBCACHESIZE );
      my $varname;

      # foreach variable name
      foreach $varname (@mandatory) {
	no strict qw( refs ); 	# See 'Symbolic references' in perlref(1)

	# $$varname is value of variable with name '$varname'
	defined $$varname ||
	  &fatalerror("Option [$varname] not defined in config file");
      }
    }

    # check mandatory directories exist
    {
      use strict;

      # list of variable names to check
      my @mandatory = qw( TMPDIR LOCKDIR );
      my $varname;

      # foreach variable name
      foreach $varname (@mandatory) {
	no strict qw( refs ); 	# See 'Symbolic references' in perlref(1)

	# $dir becomes value of the variable *named* $varname 
	my $dir = $$varname;

	(-d $dir) ||
	  &fatalerror("directory (option $varname): $dir doesn't exist");
      }
    }

    # check mandatory files exist
    {
      (-f $AUTODBMHELP) ||
	&fatalerror("file (option AUTODBMHELP): [$AUTODBMHELP] doesn't exist");

      (-f $WHOISHELP) ||
	&fatalerror("file (option WHOISHELP): [$WHOISHELP] doesn't exist");
    }


    # if optional directories are defined check they exist 
    {
      use strict;
      my $name;
      my @optional = qw( UPDLOG ACKLOG SERIALDIR
			 OLDSERIALDIR SERIALINCOMINGDIR );

      foreach $name (@optional) {
	if (defined $::LOGFILE{$name}  && ! -d $::LOGFILE{$name}) {
	  &fatalerror(
	     "directory (option $name): $::LOGFILE{$name} doesn't exist"
		      );
	}
      }
    }

    # check if we have PGP
    $have_pgp = defined($PGPK) && defined($PGPV);

    if ($have_pgp) { 
      fatalerror("PGPK binary $PGPK is not executable") unless -x $PGPK;
      fatalerror("PGPV binary $PGPV is not executable") unless -x $PGPV;
      fatalerror("PGPPATH directory $PGPPATH does not exist") 
	  unless -d $PGPPATH;
      $ENV{"PGPPATH"} = $PGPPATH;
    }

    &ReplaceGlobalVars(*RIGHTS);

    # 
    # read the attributes description file

    &read_attr($ATTDESC);

    #
    # read the objects description file

    &read_objs($OBJDESC);

    return 1;
}

1;
