<commit_before>package Qpsmtpd;
use strict;

#use warnings;
use vars qw($TraceLevel $Spool_dir $Size_threshold);

use Sys::Hostname;
use Qpsmtpd::Constants;
use Qpsmtpd::Address;

our $VERSION = "0.95";

my $git;

if (-e ".git") {
    local $ENV{PATH} = "/usr/bin:/usr/local/bin:/opt/local/bin/";
    $git = `git describe`;
    $git && chomp $git;
}

our $hooks = {};
my %defaults = (
                me      => hostname,
                timeout => 1200,
               );
my $_config_cache = {};
our %config_dir_memo;

our $LOGGING_LOADED = 0;

sub _restart {
    my $self = shift;
    my %args = @_;
    if ($args{restart}) {

        # reset all global vars to defaults
        $self->clear_config_cache;
        $hooks           = {};
        $LOGGING_LOADED  = 0;
        %config_dir_memo = ();
        $TraceLevel      = LOGWARN;
        $Spool_dir       = undef;
        $Size_threshold  = undef;
    }
}

sub version { $VERSION . ($git ? "/$git" : "") }

sub TRACE_LEVEL { $TraceLevel };    # leave for plugin compatibility

sub hooks { $hooks; }

sub load_logging {
    my $self = shift;

    # avoid triggering log activity
    return if ($LOGGING_LOADED || $hooks->{'logging'});

    my $configdir  = $self->config_dir("logging");
    my $configfile = "$configdir/logging";
    my @loggers    = $self->_config_from_file($configfile, 'logging');

    $configdir  = $self->config_dir('plugin_dirs');
    $configfile = "$configdir/plugin_dirs";
    my @plugin_dirs = $self->_config_from_file($configfile, 'plugin_dirs');
    unless (@plugin_dirs) {
        my ($name) = ($0 =~ m!(.*?)/([^/]+)$!);
        @plugin_dirs = ("$name/plugins");
    }

    my @loaded;
    for my $logger (@loggers) {
        push @loaded, $self->_load_plugin($logger, @plugin_dirs);
    }

    foreach my $logger (@loaded) {
        $self->log(LOGINFO, "Loaded $logger");
    }

    $configdir  = $self->config_dir("loglevel");
    $configfile = "$configdir/loglevel";
    $TraceLevel = $self->_config_from_file($configfile, 'loglevel');

    unless (defined($TraceLevel) and $TraceLevel =~ /^\d+$/) {
        $TraceLevel = LOGWARN;    # Default if no loglevel file found.
    }

    $LOGGING_LOADED = 1;

    return @loggers;
}

sub trace_level { return $TraceLevel; }

sub init_logger {                 # needed for compatibility purposes
    shift->trace_level();
}

sub log {
    my ($self, $trace, @log) = @_;
    $self->varlog($trace, join(" ", @log));
}

sub varlog {
    my ($self, $trace) = (shift, shift);
    my ($hook, $plugin, @log);
    if ($#_ == 0) {               # log itself
        (@log) = @_;
    }
    elsif ($#_ == 1) {            # plus the hook
        ($hook, @log) = @_;
    }
    else {                        # called from plugin
        ($hook, $plugin, @log) = @_;
    }

    $self->load_logging;          # in case we don't have this loaded yet

    my ($rc) =
      $self->run_hooks_no_respond("logging", $trace, $hook, $plugin, @log)
      or return;

    return if $rc == DECLINED || $rc == OK;    # plugin success
    return if $trace > $TraceLevel;

    # no logging plugins registered, fall back to STDERR
    my $prefix =
        defined $plugin && defined $hook ? " ($hook) $plugin:"
      : defined $plugin ? " $plugin:"
      : defined $hook   ? " ($hook) running plugin:"
      :                   '';

    warn join(' ', $$ . $prefix, @log), "\n";
}

sub clear_config_cache {
    $_config_cache = {};
}

#
# method to get the configuration.  It just calls get_qmail_config by
# default, but it could be overwritten to look configuration up in a
# database or whatever.
#
sub config {
    my ($self, $c, $type) = @_;

    $self->log(LOGDEBUG, "in config($c)");

    # first run the hooks
    my ($rc, @config);
    if (ref $type && $type->can('address')) {
        ($rc, @config) = $self->run_hooks_no_respond('user_config', $type, $c);
    };
    if (defined $rc && $rc == OK) {
        return wantarray ? @config : $config[0];
    };
    ($rc, @config) = $self->run_hooks_no_respond('config', $c);
    $self->log(LOGDEBUG,
                   "config($c): hook returned ("
                 . join(',', map { defined $_ ? $_ : 'undef' } ($rc, @config))
                 . ")"
              );
    if (defined $rc && $rc == OK) {
        return wantarray ? @config : $config[0];
    };

    # then get_qmail_config
    @config = $self->get_qmail_config($c, $type);
    return wantarray ? @config : $config[0] if @config;

    # then the default, if any
    if (exists $defaults{$c}) {
        return wantarray ? ($defaults{$c}) : $defaults{$c};
    };
    return;
}

sub config_dir {
    my ($self, $config) = @_;
    if (exists $config_dir_memo{$config}) {
        return $config_dir_memo{$config};
    }
    my $configdir = ($ENV{QMAIL} || '/var/qmail') . '/control';
    my ($path) = ($ENV{PROCESS} ? $ENV{PROCESS} : $0) =~ m!(.*?)/([^/]+)$!;
    $configdir = "$path/config" if -e "$path/config/$config";
    if (exists $ENV{QPSMTPD_CONFIG}) {<commit_msg>move extra $rc test into block<commit_after>package Qpsmtpd;
use strict;

#use warnings;
use vars qw($TraceLevel $Spool_dir $Size_threshold);

use Sys::Hostname;
use Qpsmtpd::Constants;
use Qpsmtpd::Address;

our $VERSION = "0.95";

my $git;

if (-e ".git") {
    local $ENV{PATH} = "/usr/bin:/usr/local/bin:/opt/local/bin/";
    $git = `git describe`;
    $git && chomp $git;
}

our $hooks = {};
my %defaults = (
                me      => hostname,
                timeout => 1200,
               );
my $_config_cache = {};
our %config_dir_memo;

our $LOGGING_LOADED = 0;

sub _restart {
    my $self = shift;
    my %args = @_;
    if ($args{restart}) {

        # reset all global vars to defaults
        $self->clear_config_cache;
        $hooks           = {};
        $LOGGING_LOADED  = 0;
        %config_dir_memo = ();
        $TraceLevel      = LOGWARN;
        $Spool_dir       = undef;
        $Size_threshold  = undef;
    }
}

sub version { $VERSION . ($git ? "/$git" : "") }

sub TRACE_LEVEL { $TraceLevel };    # leave for plugin compatibility

sub hooks { $hooks; }

sub load_logging {
    my $self = shift;

    # avoid triggering log activity
    return if ($LOGGING_LOADED || $hooks->{'logging'});

    my $configdir  = $self->config_dir("logging");
    my $configfile = "$configdir/logging";
    my @loggers    = $self->_config_from_file($configfile, 'logging');

    $configdir  = $self->config_dir('plugin_dirs');
    $configfile = "$configdir/plugin_dirs";
    my @plugin_dirs = $self->_config_from_file($configfile, 'plugin_dirs');
    unless (@plugin_dirs) {
        my ($name) = ($0 =~ m!(.*?)/([^/]+)$!);
        @plugin_dirs = ("$name/plugins");
    }

    my @loaded;
    for my $logger (@loggers) {
        push @loaded, $self->_load_plugin($logger, @plugin_dirs);
    }

    foreach my $logger (@loaded) {
        $self->log(LOGINFO, "Loaded $logger");
    }

    $configdir  = $self->config_dir("loglevel");
    $configfile = "$configdir/loglevel";
    $TraceLevel = $self->_config_from_file($configfile, 'loglevel');

    unless (defined($TraceLevel) and $TraceLevel =~ /^\d+$/) {
        $TraceLevel = LOGWARN;    # Default if no loglevel file found.
    }

    $LOGGING_LOADED = 1;

    return @loggers;
}

sub trace_level { return $TraceLevel; }

sub init_logger {                 # needed for compatibility purposes
    shift->trace_level();
}

sub log {
    my ($self, $trace, @log) = @_;
    $self->varlog($trace, join(" ", @log));
}

sub varlog {
    my ($self, $trace) = (shift, shift);
    my ($hook, $plugin, @log);
    if ($#_ == 0) {               # log itself
        (@log) = @_;
    }
    elsif ($#_ == 1) {            # plus the hook
        ($hook, @log) = @_;
    }
    else {                        # called from plugin
        ($hook, $plugin, @log) = @_;
    }

    $self->load_logging;          # in case we don't have this loaded yet

    my ($rc) =
      $self->run_hooks_no_respond("logging", $trace, $hook, $plugin, @log)
      or return;

    return if $rc == DECLINED || $rc == OK;    # plugin success
    return if $trace > $TraceLevel;

    # no logging plugins registered, fall back to STDERR
    my $prefix =
        defined $plugin && defined $hook ? " ($hook) $plugin:"
      : defined $plugin ? " $plugin:"
      : defined $hook   ? " ($hook) running plugin:"
      :                   '';

    warn join(' ', $$ . $prefix, @log), "\n";
}

sub clear_config_cache {
    $_config_cache = {};
}

#
# method to get the configuration.  It just calls get_qmail_config by
# default, but it could be overwritten to look configuration up in a
# database or whatever.
#
sub config {
    my ($self, $c, $type) = @_;

    $self->log(LOGDEBUG, "in config($c)");

    # first run the user_config hooks
    my ($rc, @config);
    if (ref $type && $type->can('address')) {
        ($rc, @config) = $self->run_hooks_no_respond('user_config', $type, $c);
        if (defined $rc && $rc == OK) {
            return wantarray ? @config : $config[0];
        };
    };

    # then run the config hooks
    ($rc, @config) = $self->run_hooks_no_respond('config', $c);
    $self->log(LOGDEBUG,
                   "config($c): hook returned ("
                 . join(',', map { defined $_ ? $_ : 'undef' } ($rc, @config))
                 . ")"
              );
    if (defined $rc && $rc == OK) {
        return wantarray ? @config : $config[0];
    };

    # then get_qmail_config
    @config = $self->get_qmail_config($c, $type);
    return wantarray ? @config : $config[0] if @config;

    # then the default, if any
    if (exists $defaults{$c}) {
        return wantarray ? ($defaults{$c}) : $defaults{$c};
    };
    return;
}

sub config_dir {
    my ($self, $config) = @_;
    if (exists $config_dir_memo{$config}) {
        return $config_dir_memo{$config};
    }
    my $configdir = ($ENV{QMAIL} || '/var/qmail') . '/control';
    my ($path) = ($ENV{PROCESS} ? $ENV{PROCESS} : $0) =~ m!(.*?)/([^/]+)$!;
    $configdir = "$path/config" if -e "$path/config/$config";
    if (exists $ENV{QPSMTPD_CONFIG}) {
{'fraction_non_alphanumeric': 0.173203264981087, 'fraction_numerical': 0.0033844316145729644, 'mean_word_length': 2.3942567567567568, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4461329', 'n_tokens_mistral': 3459, 'n_tokens_neox': 3379, 'n_words': 845}