#!/usr/bin/perl -w

#
# A utility for listing the values for a specific key from a
# squidGuardRobot DB file
#
# By Pl Baltzersen 1999-2000 (pal.baltzersen@ost.eltele.no)
#
# The current version may be found anytime at:
# http://ftp.ost.eltele.no/pub/www/proxy/squidGuard/contrib/squidGuardRobot/
#

# By accepting this notice, you agree to be bound by the following
# agreements:
# 
# This software product, squidGuardRobot, is copyrighted (C) 2000 by
# ElTele st AS, Oslo, Norway, with all rights reserved.
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License (version 2) as
# published by the Free Software Foundation.  It 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 (GPL) for more details.
# 
# You should have received a copy of the GNU General Public License
# (GPL) along with this program.

use strict;
use DB_File;
use Getopt::Std;
use POSIX qw(strftime);

my $progname = $0; $progname =~ s/.*\///;

sub usage($) {
  my $exit = shift;
  print STDERR "Usage: $progname file.db key\n";
  exit($exit);
}

sub mirror($) {
  scalar(reverse(shift));
}

sub linkmatch($$) {
  my $search = shift;
  my $found = shift;
  #debug("linkmatch(%s,%s)", $search, $found);
  $search = lc($search);
  $found = lc($found);
  $search =~ s@/((index|default)\.(s?html?|asp))$@@;
  $found =~ s@/((index|default)\.(s?html?|asp))$@@;
  if ($search eq $found
      || $search . "/" eq $found
      || $search eq $found . "/") {
    return(0);
  } else {
    return($search cmp $found);
  }
}

sub domainmatch($$) {
  my $search = shift;
  my $found = shift;
  #debug("domainmatch(%s,%s)", $search, $found);
  $search = lc($search);
  $found = lc($found);
  if ($search eq $found) {
    return(0);
  } else {
    $found = mirror(".$found");
    $search = mirror($search);
    $search = substr($search,0,length($found));
    #debug("domainmatch(%s,%s)", mirror($search), mirror($found));
    return($search cmp $found);
  }
}

sub urlmatch($$) {
  my $search = shift;
  my $found = shift;
  #debug("urlmatch(%s,%s)", $search, $found);
  $search = lc($search) . "/";
  $found = lc($found) . "/";
  if ($search eq $found) {
    return(0);
  } else {
    $search = substr($search,0,length($found));
    return($search cmp $found);
  }
}

sub exceptionmatch($$) {
  my $search = shift;
  my $found = shift;
  #debug("exceptionmatch(%s,%s)", $search, $found);
  $search = lc($search);
  $found = lc($found);
  if ($search eq $found) {
    return(0);
  } else {
    $search =~ s@/([^/]+\.(s?html?|cgi|php\d?|asp|jpe?g|gif|ra?m|mpe?g?|mov|movie|qt|avi|dif|dvd?|mpv2|mp3))?$@@;
    return($search cmp $found);
  }
}

sub date($) {
  my $time = shift;
  strftime("%Y.%m.%d %T", localtime($time));
}

sub strtime($) {
  my $time = shift;
  if (int($time/86400)) {
    sprintf("%d days and %d:%02d:%02d", int($time/86400), $time%86400/3600, $time/60%60, $time%60);
  } else {
    sprintf("%d:%02d:%02d", $time%86400/3600, $time/60%60, $time%60);
  }
}

my %isdate = (
	      found => 1,
	      last => 1,
	     );

my %istime = (
	      ttl => 1,
	     );

my ($f, %db, $db, $status, $key, $found, $value, $url, $domain, $exception, %opts);
getopts("h", \%opts) || usage(1);
if (defined($opts{h})) {
  usage(0);
}
usage(1) unless(scalar(@ARGV) == 2);

$f = shift || "";
$key = $found = shift;
$value = 0;

die("$f: $!\n") unless(-f $f);
$domain++ if($f =~ /(domain|redirectors)/);
$url++ if($f =~ /(url|include)/);
$exception++ if($f =~ /exception/);
if ($domain) {
  $DB_BTREE->{compare} = \&domainmatch;
} elsif ($url) {
  $DB_BTREE->{compare} = \&urlmatch;
} elsif ($exception) {
  $DB_BTREE->{compare} = \&exceptionmatch;
} else {
  $DB_BTREE->{compare} = \&linkmatch;
}
$db = tie(%db, "DB_File", $f, O_RDONLY, 0664, $DB_BTREE) || die("$f: $!\n");
if (($domain
     && ($status = $db->seq($found,$value,R_CURSOR)) == 0
     && ($status = domainmatch($key,$found)) == 0)
    ||
    (!$status
     && $url
     && ($status = $db->seq($found,$value,R_CURSOR)) == 0
     && ($status = urlmatch($key,$found)) == 0)
    ||
    (!$status
     && $exception
     && ($status = $db->seq($found,$value,R_CURSOR)) == 0
     && ($status = exceptionmatch($key,$found)) == 0)
    ||
    (!$status
     && $db->seq($found,$value,R_CURSOR) == 0
     && linkmatch($key,$found) == 0)
   ) {
  my %data = split(/[=;]/,$value);
  print "$found:\n";
  foreach(sort(keys(%data))) {
    if ($isdate{$_}) {
      printf "    %-16s%-10d (%s)\n", "$_: ", $data{$_}, date(abs($data{$_}));
    } elsif ($istime{$_}) {
      printf "    %-16s%-10d (%s)\n", "$_: ", $data{$_}, strtime(abs($data{$_}));
    } else {
      printf "    %-16s$data{$_}\n", "$_: ";
    }
  }
} else {
  print "$key: Not found\n";
  $status++;
}
undef($db);
untie(%db);
exit($status || 0);
