# this plugin checks the peers directory for config
# file most closely matching the client IP address
# and loads it if found.
#
# Note that init() borrows some internals from Qpsmtpd.pm - I
# didn't see a suitable public interface.

sub init {
   my $self = shift;
   my $qp = shift;
   my $plugins_list_file = shift || 'peers/0';
   my @plugins = $qp->config($plugins_list_file);
   my $dir = $qp->plugin_dir;

   for my $plugin_line (@plugins) {
     my ($plugin, @args) = split ' ', $plugin_line;

     my $plugin_name = $plugin;
     $plugin =~ s/:\d+$//;       # after this point, only used for filename

     # Escape everything into valid perl identifiers
     $plugin_name =~ s/([^A-Za-z0-9_\/])/sprintf("_%2x",unpack("C",$1))/eg;

     # second pass cares for slashes and words starting with a digit
     $plugin_name =~ s{
 		      (/+)       # directory
 		      (\d?)      # package's first character
 		     }[
 		       "::" . (length $2 ? sprintf("_%2x",unpack("C",$2)) : "")
 		      ]egx;

     my $package = "Qpsmtpd::Plugin::$plugin_name";

     # don't reload plugins if they are already loaded
     unless ( defined &{"${package}::plugin_name"} ) {
       Qpsmtpd::Plugin->compile($plugin_name,
         $package, "$dir/$plugin", $self->{_test_mode});
       $self->log(LOGDEBUG, "Compiling $plugin")
         unless $plugin =~ /logging/;
     }
   }

   return 1;
}

sub _peer_plugins {
   my $qp = shift;
   my $config = shift;
   my @plugins = $qp->config($config);
   $qp->log(LOGNOTICE, "loading plugins @plugins from $config");

   return $qp->_load_plugins($qp->plugin_dir, @plugins);
}

sub hook_connect {
   my ($self, $transaction) = @_;
   my $qp = $self->qp;
   my $connection = $qp->connection;

   my $client_ip = $qp->connection->remote_ip;
   while ($client_ip) {
     if (-f "config/peers/$client_ip") {
       _peer_plugins($qp, "peers/$client_ip");
       return (DECLINED);
     }
     $client_ip =~ s/\.?\d+$//; # strip off another 8 bits
   }
   if (-f "config/peers/0") {
     _peer_plugins($qp, "peers/0");
     return (DECLINED);
   }
   return (DENY);
}
