#!/local/bin/perl
#          ^^^^perl5 :-)
# 
#
# Written by: Ove Ruben R Olsen (ruben@uib.no) 
#
# Based on an idea by:    kmk@cc.tut.fi
# English translation by: espena@ifi.uio.no
#
# Read the manual page for further info.
#
# Thanks to Espen for some good ideas and heavy bug reporting.
#
# Usage: stat -h  
#
################################################################################
#
# Copyright (c) Ove Ruben R Olsen (Gnarfer from hell)
#
# Permission to use, copy, 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.
# This also apply your own incarnations of any or all of this code.
# If you use portions of this code, you MUST include a apropriate notice
# where you "stole" it from.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
#
# Email:  Ruben@uib.no 
#
#
# This work is free software, but if you find it usefull I would appreciate
# if you donated aprox 10 USD to your country's cancer research.
#
#
# This work is entierly dedicated to Kari L|nningen
#
################################################################################
# Alter this lines to suit your site.
#

$logfile = "/local/irc/userlog" ;		# Your userlogfil.
$ddfil = "/local/irc/ircstat.idf" ;	# Your domain description file.


#
# There is no need going beyond this line unless you are very eager to
# debug and destroy this work :-)
################################################################################
################################################################################

$linjer  = 250 ;
$hcount = $ucount  = 1000 ;
$min     = 60 ;  
$hmin    = 0 ;
$bit     = 0 ;
$stille  = 0 ;
$huge    = 0 ;
$skipdi  = "" ;
$status  = 'tudi' ;
$sok     = '' ;
$eks     = '' ;
$trans   = '' ;
$fast    = 0 ;
$DUMP    = 0 ;
$Date    = " Sun Jan 29 20:41:09 GMT 1995";
$Version = "2.85-207" ;
$ZCAT    = "zcat" ;
$GZIP    = "gzip -cd";
# Og noen av disse burde erstattes med $#blah osv i koden.
$aatte = $fire = $fem  = 0 ;
$seks = $syv  = 1 ;
$firstdate = 991231235959;   # 31.12.1999 23:59:59
$date = 0 ;
$UseGrp = 0;
$Slow = 0 ;
$Para = "";
%mnd = ( 'Jan', "01" , 'Feb', "02" , 'Mar', "03" , 'Apr', "04" ,
	 'May', "05" , 'Jun', "06" , 'Jul', "07" , 'Aug', "08" ,
	 'Sep', "09" , 'Oct', "10" , 'Nov', "11" , 'Dec', "12" ) ;

while ($i = shift) {
  $bit = 1 ,next if ("-b" eq $i)  ;  
  $huge = 1 ,next if ("-H" eq $i)  ;  
  $stille = 1, next if ("-s" eq $i) ;
  $fast = 1, next if ("-f" eq $i) ;
  $skipdi = "a", next if ("-sd" eq $i);
  $skipdi = "u", next if ("-sud" eq $i);
  $Para = shift, next if ("-P" eq $i);
  $ddfil = shift, next if ("-D" eq $i) ;
  $DUMP = 1, next if ($i =~/-DUMP/i) ;
  $linjer = shift, next if ("-n" eq $i ) ;
  $eks = shift, next if ("-u" eq $i) ;
  $sok .= 'V', next if ("-V" eq $i) ;
  $status = shift, next if ("-r" eq $i) ;
  $UseGrp = 1, next if ("-g" eq $i) ;
  $UseGrp = 2, next if ("-G" eq $i) ;
  $trans = shift, next if ("-t" eq $i) ;
  $Slow = 1, next if ("-S" eq $i);
  $sok = 'I', next if ("-I" eq $i);
  $sok = 'X', next if ("-X" eq $i);
  push (@logfil,$i), next if ($i !~ /^\-/) ;
  push (@logfil,shift(ARGV)), next if ("-l" eq $i)  ;

  if ("-e" eq $i) {
    $estreng = shift ;
    $sok .= 'e' ;
    next ;

  } elsif ("-c" eq $i) {
     $a = shift ;
     if ($a =~ /^\d+$/) {
        $ucount = $a ; 
	next ;
     }
     if ($a !~ /^ud$|^du$/i) {
       $a = shift ;
       print STDERR "-c can take u or d as arguments - IGNORING.\n";
       next ;
     }
     if ($a =~ /u/ ) {
       $ucount = shift ;
     } elsif ($a =~ /d/ ) {
       $hcount = shift ;
     }
     next ; 
  
  } elsif ("-d" eq $i) {
     $a = shift ;
     if ($a =~ /^\d+/) {
        $min = $a ; 
	next ;
     }
     if ($a !~ /^ud$|^du$/i) {
       $a = shift ;
       print STDERR "-d can take u/d/du or ud as arguments - IGNORING.\n";
       next ;
     }
     if ($a =~ /^ud$|^du$/i) { $min = $hmin = shift ; next ; }
     if ($a =~ /u/ ) { 
       $min = shift ;
     } elsif ($a =~ /d/ ) {
       $hmin = shift ;
     }
     next ; 


  } elsif ("-m" eq $i) {
    $a = shift ;
    if ($a =~ /^-/) {
      unshift(@ARGV,$a) ;
      $a = 0 ;
    } 
    $estreng = (localtime(time))[4] + 1 - $a ;
    $a = 1 if ($a < 0); $a = 12 if ($a > 12);
    foreach (keys %mnd) { $estreng = $_, last if ($estreng == $mnd{$_}); }
    $sok .= 'e';
    next ;

  } elsif ("-v" eq $i) {
    $vstreng = shift ;
    $sok .= 'v' ;
    next ;


  } elsif ( ("-p" eq $i) || ("-x" eq $i) ){
    $a = shift ;
    if ($a eq "m") {
      $a  = shift ;
      $e  = shift ;
      $fra = join ("",$a,$e,"01") ;
      $til = join ("",$a,$e,"31") ;
    } else {
      unshift(@ARGV,$a) ;
      for $e (1..2) {
	$a = shift ;
	($1,$2,$3) = split (/\./,$a);
	@_[$e] = join ("",$3,$2,$1);
      }
      $fra = @_[1] ;
      $til = @_[2];
    }
    $sok .= 'p' if ("-p" eq $i) ;
    $sok = 'x' if ("-x" eq $i) ;
    next ;

  } elsif ($i =~ /^-o$|^-O$/) {
    $Ofil = shift ;
    die "\n$Ofil does allready exist.\n" if (($i eq "-o") && (-e  $Ofil)) ;
    open(OUTPUT,"> $Ofil") || die "\nCannot open $Ofil\n";
    select (OUTPUT); $| = 1 ;
    next;

  } elsif ("-i" eq $i) {
    push (@logfil,shift(ARGV)) ;
    $ofil = shift ;
    die "$ofil does allready exist.\n" if (-e  $ofil) ;
    open(OFIL,">>$ofil") || die "\nCannot open $ofil\n";
    $sok = 'i' ;
    next ;


  } elsif ("-h" eq $i) {
    print (STDERR <<SLUTT);

Usage: stat [options] [logfile] ... [logfile]
 Options:
   -b                 Use bitbucket on unknown domains.
   -c [du] <count>    Display only c number of users under User/Domain 
		      Information. -c <count> equals -c u <count>.
   -d [du] <delta>    Group users/domains with delta seconds connect time or 
		      less. -d <delta> equals -d u <delta>.
   -D <IDFile>        Uses IDFile as an alternative Ircstat Description file.
   -DUMP              Dump the created &LOG procedure. Debug-only.
   -e <string>        Report with matching string occurences.
   -f                 Uses fast-parsing.
   -g                 Use grouped domains.
   -G                 As -g but put users into grouped domains also.
   -h                 This help.
   -H                 Uses DBMs for assoc arrays.
   -i <ifile> <ofile> Extract correct formated lines in ifile, append to ofile.
   -I                 Integrity check of the userlogfile.
   -l <logfile>       Uses logfile instead of default logfile.
   -m [n]             Stat this month. If n is present, stat (this month - n).
   -o <outputfile>    Uses outputfile instead of sending the results to stdout.
		      Will check if outputfile exist.
   -O <outputfile>    Sames as -o, but with no checking.
   -n <count>         Show progress for every n counted lines.

SLUTT
    print STDERR "Press Enter to continue" ; $a = <> ;
    print (STDERR <<SLUTT);
   
   -P  a | d          Paranoid ident parsing. Always, Different.
   -p <date1> <date2> Report for dates between date1 and date2.
      m <year> <mnt>  Report for month 'mnt' and year.
   -r tdDuUi          Report type: Total, Domain, Users, Introduction.
   -s                 Run silently.
   -sd                Skip domaininfo.
   -sud               Skip unknown domaininfo.
   -t du              Translations. Domains, users.
   -u tu              Use user exceptions: Total, Users.
   -v <string>        Report with NON matching string occurences.
   -V                 Return the version of this program.        
   -x <date1> <date2> Extract dates between date1 and date2 to stdout.
      m <year> <mnt>  Report for month 'mnt' and year.
   -X                 Extract correctly formated lines from the input.

 Logfiles:
   Logfiles is for the lazy ones who do not want to use the -l option.

SLUTT
  exit ;
  }
}

# Create the sub LOG routine
#
while (<DATA>) {
  push (@LOGSUB,$_) if (/^FE/); 
  push (@LOGSUB,$_) if ( (/^FN/) && ($fast == 0) ); 
  push (@LOGSUB,$_) if ( (/^FA/) && ($fast == 1) ); 
  push (@LOGSUB,$_) if ( (/^SE/) && ($sok =~ /e/ ) );
  push (@LOGSUB,$_) if ( (/^SV/) && ($sok =~ /v/ ) );
  if ( (/^SI/) && ($sok eq "i" ) ) {
    push (@LOGSUB,$_) ;
    last if (/ENDE/);
  }

  push (@LOGSUB,$_), next if ( (/^SP/) && ($sok =~ /p/ ) );
  push (@LOGSUB,$_) if ( (/^SX|^SP/) && ($sok =~ /x/ ) );
  push (@LOGSUB,$_) if ( (/^PA/) && ($Para eq "a") ); 
  push (@LOGSUB,$_) if ( (/^PD/) && ($Para eq "d") ); 
  push (@LOGSUB,$_) if ( (/^ST/) && ($stille == 0) ); 
  push (@LOGSUB,$_) if ( (/^BI/) && ($bit == 1 ) ); 
  push (@LOGSUB,$_) if ( (/^BE/) && ($bit == 0 ) ); 
  push (@LOGSUB,$_) if ( (/^TD/) && ($trans =~ /d/) );
  push (@LOGSUB,$_) if ( (/^TU/) && ($trans =~ /u/) );
  push (@LOGSUB,$_) if ( (/^EK/) && ($eks =~ /t/) );
  push (@LOGSUB,$_) if ( (/^UK/) && ($UseGrp != 0) );
}
foreach (@LOGSUB) { ($p,$_ ) = unpack ("a3 a100",$_); }
$LOGSUB = join ("",@LOGSUB);
if ($DUMP) {
 open (DF,">DEBUG") || die "Ircstat DEBUG: ($!)\n";
 print DF "Vars:\nsok\t$sok\nPara\t$Para\nstille\t$stille\nbit\t$bit\n",
	  "trans\t$trans\neks\t$eks\nUse\t$UseGrp\n";
 print DF "-" x 70 ,"\n";
 print DF @LOGSUB;
 # print DF "-" x 70 ,"\n";
 # print DF $LOGSUB;
 close (DF);
}
eval $LOGSUB;

push (@logfil,$logfile) unless @logfil;

if (! $stille) {
   print STDERR "\nThis is IRCSTAT version $Version - $Date.\n",
         "Written by Ove Ruben R Olsen - Copyright (C) 1991-1995.\n\n" ; 
   exit if ($sok =~ /V/);
   print STDERR "Using:     $ddfil as IDF file.\n" ;
   foreach (@logfil) { print STDERR "           $_ as logfile.\n" ; }
   $Ofil = STDOUT unless $Ofil;
   print STDERR "           $Ofil as outputchannel.\n\n",
        "Status:    So:$sok St:$status T:$trans B:$bit U:$ucount:$hcount " ,
         "u:$eks D:$min:$hmin L:$linjer\n\n";
}

if ($sok =~ /I/) { 
  foreach (@logfil) { &Integritet($_) ; }
  exit ;
}

if ($sok =~ /X/) { 
  foreach (@logfil) { &Integritet($_) ; }
  exit ;
}

if ($fast) {
} else {
  open (FIL, $ddfil) || warn "\nCannot open IDF file $ddfil.\n";
  while (<FIL>) { &IDF() ; }
}


$seks -- ; $syv -- ;
if ( ! $stille) {
  if ($fast) {
     print STDERR "Using the FAST parsing. - Ignoring any IDFs.\n";
  } else {
     print STDERR "Read in: ", &SPCs($fire,3), 
	       "$fire Domain translations.\n" ,
               &SPCs($seks,12), "$seks Domain informations.\n" ,
               &SPCs($syv,12), "$syv User translations.\n" ,
               &SPCs($aatte,12), "$aatte User exceptions.\n" ,
               &SPCs($fem,12), "$fem User information lines.\n\n" ;
  }
}

if ($status eq "i" ) { while (<FIL>) { print $_ ; } exit ;}

if ($huge == 1) {
  dbmopen( %indiv,"/tmp/irc-indiv.$$",0700) || 
     die "IRCSTAT: dbmopen indiv.$$ (!$)\n";
  dbmopen( %indic,"/tmp/irc-indic.$$",0700) || 
     die "IRCSTAT: dbmopen indic.$$ (!$)\n";
  dbmopen( %domains,"/tmp/irc-domains.$$",0700) || 
     die "IRCSTAT: dbmopen domains.$$ (!$)\n";
  dbmopen( %domainc,"/tmp/irc-domainc.$$",0700) || 
     die "IRCSTAT: dbmopen domainc.$$ (!$)\n";
  dbmopen( %ParaUkj,"/tmp/irc-ParaUkj.$$",0700) || 
     die "IRCSTAT: dbmopen ParaUkj.$$ (!$)\n";
  dbmopen( %ParaLik,"/tmp/irc-ParaLik.$$",0700) || 
     die "IRCSTAT: dbmopen ParaLik.$$ (!$)\n";
}

foreach (@logfil) { &LOG ($_) ; }

&exit if ($sok =~ /x/) ;
&exit if ($sok eq 'i' ) ;

die "No data availible to make a report.\n"  if (! $total) ;



$virkC = $indivC = $domC = 0 ;
foreach ( keys %domains) { $domC ++ ; };
foreach ( keys %virkelig) { $virkC ++ ; };
foreach ( keys %indic) { 
  $indivC ++ ;   # Numer of users total.
  ($j,$ho) = split (/@/,$_,2);
  $individom{$ho} ++ ; # Numer of users inside a domain.
} ;

# Adding groupinfo
if ($UseGrp != 0 ) {
  # Fjernet da sub-grupper ble dobblet i supergruppen... uff...
  # Denne burde omskrives totalt en gang?
  # foreach (keys %subgrp) {
    # $s = $subgrp{$_};
    # $grps{$s} = join (" ",$grps{$s},$_);
    # print "DBB S $s KE $_ -> $grps{$s}\n";
  # }

  foreach (keys %grptime) {
    $domains{"\001$_"} = $grptime{$_} ;
    $domainc{"\001$_"} = $grpcount{$_} ;
    foreach $gr ( split(/\s+/,$grps{$_}) ) {
      # next if ($gr =~ /^\s+$|^$/);
      $SubDom{$gr} = $domains{$gr} ;
      $SubDomC{$gr} = $domainc{$gr} ;
      $SubDomI{$gr} = $individom{$gr};
      $individom{"\001$_"} += $individom{$gr};
      delete $domains{$gr} ;
      delete $domainc{$gr} ;
      delete $individom{$gr};
    }
  }

}


@_ = localtime(time); @_[4] ++ ;
chop ($a = `hostname`) ; 
# chop ($b = `domainname`)  ; 
# $a = "$a.$b" ;

$a =~ tr/a-z/A-Z/ ;

if ($status !~ /D|U/) {

  print   "\nSTATISTICS RUN ON SERVER $a @_[3]/@_[4] @_[5]" ,  
	  "  @_[2]:@_[1]:@_[0]\n";
  if ($status =~ /i/) { while (<FIL>) { print $_ ; } }
  print "\nLog started: $Fday ", &DateStr($firstdate),
        "\nLog ended:   $Lday ", &DateStr($date), "\n\n";
} 

if ($status =~ /t/) {

  print "\nTOTAL INFORMATION\n^^^^^^^^^^^^^^^^^\n";
  $a = $sessions ;       $b = $domC ;
  $c = $indivC ;     $d = $virkC ;
  foreach (values %ParaUkj) {$Ukjente += $_};
  foreach (values %ParaLik) {$Like += $_};
  foreach (values %ParaUlik) {$Ulike += $_};
  $Ukjente = $Ukjente / 2 ; $Like = $Like / 2 ; $Ulike = $Ulike / 2 ;
  print "Total served time:                  " , &skriv ($total)  ,
        "\nNumber of sessions:                 ",  &SPCs($a,4), $a ,
       "\nNumber of different domains:        ",  &SPCs($b,4), $b ,
       "\nNumber of different users:          ",  &SPCs($c,4), $c ,
       "\nNumber of different machines:       ",  &SPCs($d,4), $d ,
       "\n\nNumber of \"unknown\" ident replies:  ",
		     &SPCs($Ukjente,4), $Ukjente,
       "\nNumber of \"correct\" ident replies:  ", &SPCs($Like,4), $Like,
       "\nNumber of \"incorrect\" ident replies:", &SPCs($Ulike,4), $Ulike,
  "\n\n\n";



}  # Status = t 


if ($status =~ /d/i) {
  $delta = $hmin * 60 ;
  if ($status =~ /d/) {
  print  <<SLUTT;

DOMAIN INFORMATION
^^^^^^^^^^^^^^^^^^
(f) = indicates a far-away domain net-vice.
(n) = indicates a close domain net-vice.
Usr = Number of users from domain.
Log = Number of logins from domain.
Unk = Unknown identd replies.
Inc = Incorrect identd replies (eg. fakes).
Cor = Correct idented replies (username matches identd reply).

                                                                  Ident replies
Num Domain name                  Usr  Log    Connect time   Perc  Unk  Inc  Cor
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SLUTT
}

  $ds = $dc = $dt = $puk = $pul = $plk = $ind = $teller = 0 ;

  foreach ( sort { $domains{$b} <=> $domains{$a} ;} keys %domains ) {
    $teller ++ ;
    &exit if ($teller >= $hcount);
    if ($domains{$_} < $delta) {
      $total += $domains{$_} ;
      $ds += $domains{$_} ;
      $dc += $domainc{$_} ;
      $dt ++ ;
      $puk += $ParaUkj{$_} ;
      $pul += $ParaUlik{$_};
      $plk += $ParaLik{$_};
      $ind += $individom{$_} ;
      next ;
    }


    
    if ( ($_ =~ /^\001/) && ($UseGrp != 0)) {
      $host = $_; $host =~ tr/\001//d;
      &Hinfo();
      foreach $gr ( split(/\s+/,$grps{$host}) ) {
        next if ($gr =~ /^\s+$|^$/);
	&HinfoG ();
	$domains{$gr} = $SubDom{$gr} ;
      }
      next ;
    }
		      
    &Hinfo ();
  }
        printf("\n\n%3s %-28s%4s %4s %15s %6s %4s %4s %4s\n\n",
          $dt, "domains with < $hmin mins login", $ind , $dc , 
            &skriv($ds),&Precent($ds,$total) , $puk, $pul, $plk) if ($dt > 0);
 

  if ($skipdi eq "a")  {
    foreach ( sort { $domains{$b} <=> $domains{$a} ;} keys %domains ) {
      next if ( ($_ =~ /^\001/) && ($UseGrp != 0)) ;
      $a = $in{$_} || "- Not defined in the $ddfil file." ;
      next if (($a =~ /^- Not defined in/) && ($skipdi eq "u"));
      next if (($a =~ /^- No information/) && ($skipdi eq "u"));
      printf "%-21s %-s\n", $_,$a ; 
    }
  }

}   # status = d




if ($status =~ /u/i) {

  if ($status =~ /u/) {
  print   "\n\nINDIVIDUAL USER INFORMATION\n" .
	  "^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n\n";

  foreach (@ui) { print $_,"\n";  ; }

  print " 

Unk = Unknown identd replies.
Inc = Incorrect identd replies (eg. fakes).
Cor = Correct idented replies (username matches identd reply).

                                                               Ident replies
Num  Username                     Logins    Connection time    Unk  Inc  Cor 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
";
  }

  $a = $total = $teller = $j = 0 ;
  $delta = $min * 60 ;

  if ($UseGrp == 2) {
    foreach (keys %indiv) {
      ($user,$host) = split (/@/,$_);
      if ($subgrp{$host}) {
	$s = join ("@",$user,$subgrp{$host});
	$indiv{$s} += $indiv{$_} ;
	$indic{$s} += $indic{$_};
	delete $indiv{$_} ; delete $indic{$_} ;
      }
    }
  } 

  foreach ( sort { $indiv{$b} <=> $indiv{$a} ;} keys %indiv ) {
    $teller ++ ;
    next if (($ue{$_} == 1) && ($eks =~ /u/)) ;
    &exit if ($teller >= $ucount);
    

    if ($indiv{$_} < $delta) {
      $a += $indic{$_} ;
      $j ++ ;
      $total += $indiv{$_} ;
      next ;
    }

    if ($status =~ /u/) {
      printf ("%3s  %-28s %6s  %17s   %4s %4s %4s\n",
             $teller ,  $_, $indic{$_}, &skriv ($indiv{$_}),
            $ParaUkj{$_}, $ParaUlik{$_}, $ParaLik{$_});
    } 
    if ($status =~ /U/) {
      print join (":",$teller ,  $_, $indic{$_}, &skriv ($indiv{$_}),
            $ParaUkj{$_}, $ParaUlik{$_}, $ParaLik{$_});
    }
  }

  &exit unless $j ;
  &exit if ($status =~/U/) ;
  print   "\n" ;
  $delta = "users with less than $min min. logintime" ;
  print   &SPCs($j,2) ,$j , "  " ;
  print   $delta ,  &SPCs($delta,40) ;
  print   &SPCs($a,4) , $a , "  ",
  &skriv ($total);
  print   "\n" ;

}  # Status = u 

&exit ;   # Just in case ...


################################################################################
sub Hinfo {
    if ($status =~ /d/) {
      # $ParaUkj{$_}  = 0 if ($ParaUkj{$_} eq "" );
      # $ParaUlik{$_} = 0 if ( $ParaUlik{$_} eq "" );
      # $ParaLik{$_}  = 0 if ( $ParaLik{$_} eq ""  );
      if ( ($_ =~ /^\001/) && ($UseGrp != 0)) {
        printf("%3s %-28s", $teller, "$host (GRP)" );
      } else {
        printf("%3s %-28s", $teller, "$_ ($farnear{$_})" );
      }

  printf("%4s %4s %15s %6s %4s %4s %4s\n",
            $individom{$_} , $domainc{$_} ,
            &skriv($domains{$_}),&Precent($domains{$_},$total) ,
            $ParaUkj{$_}, $ParaUlik{$_}, $ParaLik{$_}
            )  ;
    } elsif ($status =~ /D/) {
      print join (":", $teller, $_ , $individom{$_} , $domainc{$_} ,
            &skriv($domains{$_}),&Precent($domains{$_},$total) ,
            $ParaUkj{$_}, $ParaUlik{$_}, $ParaLik{$_},"\n");
    }
}
################################################################################


sub HinfoG {  # Print a line at the hostinfo in groups
  if ($status =~ /d/) {
      printf ("    %-25s [ %4s %4s %15s %6s %4s %4s %4s]\n", 
	     "  $gr ($farnear{$gr})", $SubDomI{$gr}, $SubDomC{$gr}, 
	    &skriv($SubDom{$gr}), &Precent($SubDom{$gr},$domains{$_}), 
	    $ParaUkj{$gr}, $ParaUlik{$gr}, $ParaLik{$gr})  ;
  } elsif ($status =~ /D/) {
    print join (":",@_[0],"\n");
  }
}

################################################################################
sub exit {
  if ($huge == 1) {
    foreach ("ParaLik","ParaUkj","domainc","domains","indic","indiv") {
      unlink ("/tmp/irc-$_.$$.dir");
      unlink ("/tmp/irc-$_.$$.pag");
    }
  }
}

################################################################################
sub DateStr {
  # 99123186399 = 31.12.1999
  # Tue Jul  6 01:39:27 1993
  ($c,$a,$b,$dt,$dm,$ds) = unpack ("a2 a2 a2 a2 a2 a2",@_[0]);
  foreach (keys %mnd) {
    $a = $_, last if ($mnd{$_} eq $a); 
  }
  "$a $b $dt:$dm:$ds 19$c" ;
}


################################################################################
sub Precent {
  if (@_[1] == 0) {
    return "0.00";
  }
  $a = (@_[0] * 100) / @_[1] ;
  if ($a > 0.01) {
    ($a,$j) = split (/\./,$a) ;
    join (".",$a, unpack ("a2",$j)) ; 
  } else {
    "0.00" ;
  } 
}

################################################################################

# sub bynumber { $a <=> $b; } 
################################################################################

sub skriv {
    local ($a,$b,$c,$d) ;
    $a = @_[0] % 60;
    $b = (@_[0] % 3600) / 60;
    $c = (@_[0] % (24*3600)) / 3600;
    $d = @_[0] / (24 * 3600);
    sprintf   ("%3d + %02d:%02d:%02d", $d, $c, $b, $a);
}

################################################################################
sub SPCs {
  " " x ( @_[1] - length (@_[0] ) + 1 ) ;
}

################################################################################

sub IDF {
  next if ($_ =~ '^$');
  next if ($_ =~ '^#') ;
  # &intro (@_[0]) if ($_ =~ '^intro');
  last if ($_ =~ '^intro');
  chop;
  ($a,$b) = split (/ /,$_,2);

  # First level of confusion

  if ($a eq 'include') {
    if ($i == 1) {
      print STDERR "\nMax include level is 1.\n" unless $stille ; 
      next  ;
    }
    $i = 1 ;
    open (IFIL, $b) || warn "\nCannot include IDF file $b.\n";
    while (<IFIL>) {
      &IDF() ;
    }
    close (IFIL);
    $i = 0 ;

  } elsif ($a eq 'ui') {
    $fem ++ ;
    push (@ui,$b) ;
    next ;

  } elsif ($a eq 'dg') {
    $dgCount ++ ;
    @mld = split (/\s+/,$b);
    $grp = shift (@mld);
    $j = join (" ", @mld);
    # print "j $j -> @mld[0] -> @mld[1]\n";
    $grps{$grp} =  join (" ",$j,$grps{$grp}); # KEY: hovedgrp. INN: grupper
    # print "LESER $grp $grps{$grp}\n";
    $grptime{$grp} = 0 ;
    $grpcount{$grp} = 0 ;
    foreach $gr (@mld) {
      $subgrp{$gr} = $grp;
       # print "LESER-> $gr -> $subgrp{$gr}\n";
    }

    next;
  }

  # Next level of confusion...

  ($b,$c) = split (/\s+/,$b,2) ; 

  if ($a eq 'ue') {
    $ue{$b} = 1 ;
    $aatte ++ ;
    next ;

  } elsif ($a eq 'di') {
    $in{$b} = $c  ;
    $seks ++ ;
    next ;

  } elsif ($a eq 'fg') {
    $fg{$b} = $c ;
    $fgCount ++ ;
    $grptime{$c} = 0 ;
    $grpcount{$c} = 0 ;
    next;

  } elsif ($a eq 'ut') {
    $ut{$b} = $c  ;
    $syv ++ ;
    next ;

  } elsif ($a eq 'dt') {
    $dt[$fire] = $b ;
    ($c,$junk) = split (/\s+/,$c,2);
    $tr[$fire] = $c ;
    $junk = "far" if ($junk eq "");
    $farnear{$c} = unpack("a1",$junk);
    $fire ++ ;
    next ;
  }

  print STDERR "\nBullshit found while parsing IDF file @_[0] line $.\n" 
    unless $stille ; 
}

################################################################################
sub Integritet {
  $ofil = @_[0];
  if (! (-e $ofil && -R $ofil ))  {
     print STDERR "Cannot open userlog file: $ofil\n";
     return  ;
  }
  $ofil = "$ZCAT $ofil |" if ($ofile =~ /.Z$/);
  $ofil = "$GZIP $ofil |" if ($ofile =~ /.gz$|.z$/);
  open(FILEN, $ofil); 
  while (<FILEN>) {
    if (/^$/) { print "Open line: $ofil line $. \n" ; next ;}
    if (/^... ...\s*\d+ \d\d:\d\d:\d\d \d+ \(\s*\d+:\d\d:\d\d\): .+@.+$/) {
      print if ($sok =~ /X/) ;
      next ;
    }
    print "Bullshit in line $., file: $ofil  ->\n   $_\n" ;
  }
  print STDERR "$. lines checked in $ofil\n" ;

}

################################################################################


__END__
FE sub LOG {
FE   $ofil = @_[0];
FE   if (! (-e $ofil && -R $ofil ))  {
FE     print STDERR "Cannot open userlog file: $ofil\n";
FE     return  ;
FE  }
FE  $ofil = "$ZCAT $ofil |" if ($ofil =~ /.Z$/);
FE  $ofil = "$GZIP $ofil |" if ($ofil =~ /.gz$|.z$/);
FE  open(FILEN, $ofil) ; 
ST  print STDERR "Processing @_[0]: " unless $stille ;

FE  while (<FILEN>) {
FE    next if (/^$/) ;

SE    if ($sok =~ /e/ ) {
SE      next if ($_ !~ /$estreng/io) ;
SE    }

SV    if ($sok =~ /v/ ) {
SV      next if ($_ =~ /$vstreng/io) ;
SV    }

SI    if ($sok eq 'i') {
SI      print OFIL $_ ;
SI      next ;
SI    }   
SI  }
SI }  # ENDE

FE    chop;

FE    ($dd,$a,$b, $dt,$j,$dm,$j,$ds, $c,$j,$ti,$j,$mi,$j,$se,$j,$UatH) =
FE    unpack("a4 A4 a2 a3 a1 a2 a1 a2 a5 a2 a3 a1 a2 a1 a2 a3 A50",$_);
FE    #       dd a  b  dt    dm    ds c     ti    mi    se    Uat 
FE  
FE    ($UatH,$ident) = split (/\s+/,$UatH,2);
FE    $ident =~ tr/\[\]//d;

FE    #  a = month     dd = Day
FE    #  b = date      dt = Hour
FE    #  c = year      dm = Min
FE    #  j = junk      ds = Sec 

    
FE    $a = $mnd{$a} ;
FE    $b = "0$b"  if ($b < 10 ) ;
FE    $c -= 1900 ;
FE    $dt =~ tr/ //d;  # Changed s to tr
FE    $b =~ tr/ //d;   # Changed s to tr
FE    $j = "$c$a$b$dt$dm$ds";

FE    if ($j > $date) {
FE      $date = $j;
FE      $Lday = $dd ;
FE    }
FE    if ( $j < $firstdate ) {
FE      $firstdate = $j ;
FE      $Fday = $dd ;
FE    }


SP    if ($sok =~ /p|x/ ) {
SP      $tid = join ("",$c,$a,$b) ;
SP      next if ! ( ($tid >= $fra) && ($tid <= $til) ) ;

SX      if ($sok =~ /x/) {
SX        print $_, "\n" ;
SX        next ;
SX      }


SP     }


FE    $secs = ($ti * 3600) + ($mi * 60) + $se;
FE    $total += $secs;
FE    $sessions++;

FE    ($user,$ho) = split (/@/,$UatH,2) ;
FN    $real = $user ;
FE    # $user =~ s/^~//;        # Trim av eventuel ~ paa starten av brukernavn
FE    $user =~ tr/~//d; # tr skal vaere kjappere enn s. Tviler paa at det
FE                      # finnes brukerid med tilde i seg. Den tid, den
FE                      # sorg.

FE    $parateller = 3 if ($ident ne $user); 
FE    $parateller = 1 if ($ident eq "unknown"); 
FE    $parateller = 2 if ($ident eq $user); 
FE     # print "ID $ident -> $parateller\n";

PA      $user = $ident if ($ident ne "unknown"); 
PD      $user = $ident if ( ($ident ne "unknown") && ($ident ne $user)); 

FE    $us = $ho ;
FE    $virkelig{$us} += 1;


ST    print STDERR "$sessions " if ( $sessions % $linjer  ==  0 )  ;

FE    $host = '' ;

FA    # Fast parsing
FA    $ho =~ tr/A-Z/a-z/;
FA    if ($ho =~ /^(\d+.\d+.\d+).\d+/) {
FA       $host = $1;
FA    } else {
FA      if ($ho =~ /(\w+\.\w+\.\w+\.us)$/) {
FA        $host = $1 ;
FA      } elsif ($ho =~ /(\w+\.ac\.\w+)$/) {
FA        $host = $1 ;
FA      } elsif ($ho =~ /(\w+\.edu\.\w+)$/) {
FA        $host = $1 ;
FA      } elsif ($ho =~ /(\w+\.co\.\w+)$/) {
FA        $host = $1 ;
FA      } elsif ($ho =~ /(\w+\.com\.\w+)$/) {
FA        $host = $1 ;
FA      } else {
FA        ($host) = ($ho =~ /(\w+.\w+)$/) 
FA      }
FA    }


FN    # Dette er n|kkelen til hastighet:
FN    if (!($host=$domaintrans{$ho})) {
FN      for $s (0..$#dt)  {
FN            $host = $tr[$s], last if ($ho =~ /$dt[$s]/i) ;
FN      }
FN      $domaintrans{$ho}=$host;
FN    }


BI    if ($bit) {
BI      if ($host eq '') {
BI        $host = "BITBUCKET"  ;
BI        $user = "BITBUCKET" ;
BI      }
BI    } 

BE    $host = $ho if ($host eq '') ; 


FE    $host =~ tr/ //d ;

TD    $host = $ho if ($trans =~ /d/) ;

FE    $UatH = join ("@",$user,$host);

TU    if ($trans !~ /u/ ) {
TU      if ($ut{$UatH}) {
TU        $UatH = $ut{$UatH} ;
TU        ($user,$host) = split (/@/,$UatH);
TU      }
TU    }

EK    next if (($ue{$UatH} == 1) && ($eks =~ /t/)) ;


UK    if ($UseGrp != 0) {
UK      foreach $s (keys %fg) { 
UK        if ($host =~ /$s/)  {
UK          $subgrp{$host} = $fg{$s};
UK          last ;
UK        }
UK      }
UK    }



FE    $indiv{$UatH} += $secs ;
FE    $indic{$UatH} += 1;
    
FE    $domains{$host} += $secs;
FE    $domainc{$host} += 1 ;

FE    $ParaUkj{$UatH} ++ if ($parateller == 1) ;
FE    $ParaLik{$UatH} ++ if ($parateller == 2);
FE    $ParaUlik{$UatH} ++ if ($parateller == 3);
FE    $ParaUkj{$host} ++ if ($parateller == 1) ;
FE    $ParaLik{$host} ++ if ($parateller == 2);
FE    $ParaUlik{$host} ++ if ($parateller == 3);

UK    if ($UseGrp != 0) {
UK      if ($subgrp{$host}) {
UK        $gr = $subgrp{$host} ;
UK        $grptime{$gr} += $secs; 
UK        $grpcount{$gr} ++ ;
UK      }
UK    }


FE   }  # while <filen>
ST    print STDERR "\n"; 
FE }
