#!/usr/bin/perl -w

#
# A utility for removing keys 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\.s?html?$@@;
  $found =~ s@/index\.s?html?$@@;
  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);
  }
}

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

$f = shift || "";

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_RDWR, 0664, $DB_BTREE) || die("$f: $!\n");
foreach $key (@ARGV) {
  if ($hash) {
    $exit += $status = delete($db{$key});
    print "$key: ", $status == 0 ? "Deleted\n" : "Not deleted\n";
  } elsif ($force) {
    $exit += $status = $db->del($key,R_CURSOR);
    print "$key: ", $status == 0 ? "Deleted\n" : "Not deleted\n";
  } else {
    $found = $key;
    $value = 0;
    if ($db->seq($found,$value,R_CURSOR) == 0 && $key eq $found) {
      $status = $db->del_dup($found,$value);
      print "$key: ", $status == 0 ? "Deleted\n" : "Not deleted\n";
      $db->sync();
    } else {
      print "$key: Not found\n";
      $exit++;
    }
  }
}
undef($db);
untie(%db);
exit($exit || 0);
