home *** CD-ROM | disk | FTP | other *** search
/ ftp.f-secure.com / 2014.06.ftp.f-secure.com.tar / ftp.f-secure.com / support / hotfix / fsis / IS-SpamControl.fsfix / iufssc / lib / Mail / SpamAssassin / AICache.pm next >
Text File  |  2006-11-29  |  4KB  |  180 lines

  1. # <@LICENSE>
  2. # Licensed to the Apache Software Foundation (ASF) under one or more
  3. # contributor license agreements.  See the NOTICE file distributed with
  4. # this work for additional information regarding copyright ownership.
  5. # The ASF licenses this file to you under the Apache License, Version 2.0
  6. # (the "License"); you may not use this file except in compliance with
  7. # the License.  You may obtain a copy of the License at:
  8. #     http://www.apache.org/licenses/LICENSE-2.0
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # </@LICENSE>
  15.  
  16. =head1 NAME
  17.  
  18. Mail::SpamAssassin::AICache - provide access to cached information for
  19. ArchiveIterator
  20.  
  21. =head1 SYNOPSIS
  22.  
  23. =head1 DESCRIPTION
  24.  
  25. This module allows ArchiveIterator to use cached atime information instead of
  26. having to read every message separately.
  27.  
  28. =head1 PUBLIC METHODS
  29.  
  30. =over 4
  31.  
  32. =cut
  33.  
  34. package Mail::SpamAssassin::AICache;
  35.  
  36. use File::Spec;
  37. use File::Path;
  38. use File::Basename;
  39.  
  40. use strict;
  41. use warnings;
  42.  
  43. =item new()
  44.  
  45. Generates a new cache object.
  46.  
  47. =cut
  48.  
  49. sub new {
  50.   my $class = shift;
  51.   $class = ref($class) || $class;
  52.  
  53.   my $self = shift;
  54.   if (!defined $self) { $self = {}; }
  55.  
  56.   $self->{cache} = {};
  57.   $self->{dirty} = 0;
  58.   $self->{prefix} ||= '/';
  59.  
  60.   my $use_cache = 1;
  61.  
  62.   # be sure to use rel2abs() here, since otherwise relative paths
  63.   # are broken by the prefix stuff
  64.   if ($self->{type} eq 'dir') {
  65.     $self->{cache_file} = File::Spec->catdir(
  66.                 $self->{prefix},
  67.                 File::Spec->rel2abs($self->{path}),
  68.                 '.spamassassin_cache');
  69.  
  70.     $self->{cache_mtime} = (stat($self->{cache_file}))[9] || 0;
  71.   }
  72.   else {
  73.     my @split = File::Spec->splitpath($self->{path});
  74.     $self->{cache_file} = File::Spec->catdir(
  75.                 $self->{prefix},
  76.                 File::Spec->rel2abs($split[1]),
  77.                 join('_', '.spamassassin_cache', $self->{type}, $split[2]));
  78.  
  79.     $self->{cache_mtime} = (stat($self->{cache_file}))[9] || 0;
  80.  
  81.     # for mbox and mbx, verify whether mtime on cache file is >= mtime of
  82.     # messages file.  if it is, use it, otherwise don't.
  83.     if ((stat($self->{path}))[9] > $self->{cache_mtime}) {
  84.       $use_cache = 0;
  85.     }
  86.   }
  87.   $self->{cache_file} = File::Spec->canonpath($self->{cache_file});
  88.  
  89.   # go ahead and read in the cache information
  90.   if ($use_cache && open(CACHE, $self->{cache_file})) {
  91.     while(defined($_=<CACHE>)) {
  92.       my($k,$v) = split(/\t/, $_);
  93.       next unless (defined $k && defined $v);
  94.       $self->{cache}->{$k} = $v;
  95.     }
  96.     close(CACHE);
  97.   }
  98.  
  99.   bless($self,$class);
  100.   $self;
  101. }
  102.  
  103. sub count {
  104.   my ($self) = @_;
  105.   return keys %{$self->{cache}};
  106. }
  107.  
  108. sub check {
  109.   my ($self, $name) = @_;
  110.  
  111.   return $self->{cache} unless $name;
  112.  
  113.   return if ($self->{type} eq 'dir' && (stat($name))[9] > $self->{cache_mtime});
  114.  
  115.   $name = $self->canon($name);
  116.   return $self->{cache}->{$name};
  117. }
  118.  
  119. sub update {
  120.   my ($self, $name, $date) = @_;
  121.  
  122.   return unless $name;
  123.   $name = $self->canon($name);
  124.  
  125.   # if information is different than cached version, set dirty and update
  126.   if (!exists $self->{cache}->{$name} || $self->{cache}->{$name} != $date) {
  127.     $self->{cache}->{$name} = $date;
  128.     $self->{dirty} = 1;
  129.   }
  130. }
  131.  
  132. sub finish {
  133.   my ($self) = @_;
  134.  
  135.   # Cache is dirty, so write out new file
  136.   if ($self->{dirty})
  137.   {
  138.     # create enclosing dir tree, if required
  139.     eval {
  140.       mkpath(dirname($self->{cache_file}));
  141.     };
  142.     if ($@) {
  143.       warn "Can't mkpath for AI cache file (".$self->{cache_file}."): $@ $!";
  144.     }
  145.  
  146.     if (open(CACHE, ">" . $self->{cache_file})) {
  147.       while(my($k,$v) = each %{$self->{cache}}) {
  148.     print CACHE "$k\t$v\n";
  149.       }
  150.       close(CACHE);
  151.     }
  152.     else {
  153.       warn "Can't write AI cache file (".$self->{cache_file}."): $!";
  154.     }
  155.   }
  156.  
  157.   return undef;
  158. }
  159.  
  160. sub canon {
  161.   my ($self, $name) = @_;
  162.  
  163.   if ($self->{type} eq 'dir') {
  164.     # strip off dirs, just look at filename
  165.     $name = (File::Spec->splitpath($name))[2];
  166.   }
  167.   else {
  168.     # we may get in a "/path/mbox.offset", so trim to just offset as necessary
  169.     $name =~ s/^.+\.(\d+)$/$1/;
  170.   }
  171.   return $name;
  172. }
  173.  
  174. # ---------------------------------------------------------------------------
  175.  
  176. 1;
  177. __END__
  178.