Author: vetinari
Date: Thu Sep 20 10:18:17 2007
New Revision: 791
Added:
contrib/vetinari/config_ini
Log:
config_ini: new plugin for -forkserver and -prefork,
reads an .ini file with the qpsmtpd config, re-read only if changed on disk
Added: contrib/vetinari/config_ini
==============================================================================
--- (empty file)
+++ contrib/vetinari/config_ini Thu Sep 20 10:18:17 2007
@@ -0,0 +1,137 @@
+#! perl
+
+=head1 NAME
+
+config_ini - (another) example plugin how to use the "config" hook
+
+=head1 DESCRIPTION
+
+B<config_ini> reads a config.ini and returns the section for the requested
+config to qpsmtpd, if found.
+
+It only reads the config if it has changed on disk, instead of reading every
+small file each time it's requested. Reading of the config is done in the
+C<pre-connection> hook, so it will only work with qpsmtpd flavours supporting
+this hook (C<-forkserver>, C<-prefork>).
+
+This (like any config hook plugin) plugin should be
+the first plugin in the F<config/plugins> file.
+
+The B<config_ini> plugin can be given an (optional) argument: the name of the
+F<config.ini> file, default is C</etc/qpsmtpd/config.ini>.
+
+The F<config.ini> is standard ini format, comments start with C<#>. Example:
+
+ [me]
+ my.host.name
+ [IP]
+ 0
+ [badhelo]
+ aol.com
+ yahoo.com
+
+ [badrcptto_patterns]
+ # Format is pattern\s+Response
+ # Don't forget to anchor the pattern if required
+ ! Sorry, bang paths not accepted here
+ @.*@ Sorry, multiple at signs not accepted here
+ % Sorry, percent hack not accepted here
+ [logging]
+ logging/warn 9
+ [loglevel]
+ # Log levels
+ # LOGDEBUG = 7
+ # LOGINFO = 6
+ # LOGNOTICE = 5
+ # LOGWARN = 4
+ # LOGERROR = 3
+ # LOGCRIT = 2
+ # LOGALERT = 1
+ # LOGEMERG = 0
+ 4
+ [require_resolvable_fromhost]
+ 1
+ # EOF
+
+=cut
+
+my %config = ();
+
+sub register {
+ my ($self,$qp,@args) = @_;
+ unless (@args) {
+ @args = ("/etc/qpsmtpd/config.ini");
+ $self->log(LOGDEBUG, "Using default file /etc/qpsmtpd/config.ini");
+ }
+
+ die "too many arguments to config_ini plugin"
+ if (@args > 1);
+
+ $self->{_config_ini_file} = $args[0];
+
+ ($self->{_config_ini_time},%config) = $self->read_ini();
+ die "failed to read config file $args[0]"
+ unless $self->{_config_ini_time};
+}
+
+sub read_ini {
+ my $self = shift;
+ my $file = $self->{_config_ini_file};
+ my %conf = ();
+
+ open CFG, $file
+ or $self->log(LOGWARN, "Failed to open $file: $!"), return (0, ());
+ my ($time) = (stat(CFG))[9] || 0;
+ my $section = undef;
+
+ while (<CFG>) {
+ # skip comments and empty lines:
+ next if /^\s*#/;
+ next if /^\s*$/;
+ chomp;
+ if (/^\s*\[([^\]]+)\]\s*$/) {
+ $section = lc $1;
+ } else {
+ next unless defined $section;
+ push @{$conf{$section}}, $_;
+ }
+ }
+ close CFG;
+ return ($time, %conf);
+}
+
+sub hook_pre_connection {
+ my $self = shift;
+ my ($time) = (stat($self->{_config_ini_file}))[9];
+ my %tmp = ();
+ if ($time > $self->{_config_ini_time}) {
+ $self->log(
+ LOGINFO,
+ "$time > " . $self->{_config_ini_time} . ", re-reading "
+ . $self->{_config_ini_file}
+ );
+
+ ($time, %tmp) = $self->read_ini();
+
+ # if ($time && (keys %tmp >= keys %config)) {
+ if ($time && keys(%tmp)) {
+ %config = %tmp;
+ $self->{_config_ini_time} = $time;
+ }
+ else {
+ $self->log(LOGWARN, "no values in config found, ignoring");
+ }
+ }
+ return (DECLINED);
+}
+
+sub hook_config {
+ my ($self,$txn,$value) = @_;
+ $value = lc $value;
+ # $self->log(LOGDEBUG, "config_ini: '$value'");
+ return (OK, @{$config{$value}})
+ if exists $config{$value};
+ return (DECLINED);
+}
+
+# vim: ts=4 sw=4 expandtab syn=perl