1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
#
#
#
=head1 NAME
help - default help plugin for qpsmtpd
=head1 DESCRIPTION
The B<help> plugin gives the answers for the help command. It can be configured
to return C<502 Not implemented>.
Without any arguments, the C<help_dir> is set to F<./help/>.
=head1 OPTIONS
=over 4
=item not_implemented (1|0)
If this option is set (and the next argument is true), the plugin answers,
that the B<HELP> command is not implemented
=item help_dir /path/to/help/files/
When a client requests help for C<COMMAND> the file F</path/to/help/files/
. lc(COMMAND)> is dumped to the client if it exists.
=item COMMAND HELPFILE
Any other argument pair is treated as command / help file pair. The file is
expexted in the F<help/> sub directory. If the client calls C<HELP COMMAND>
the contents of HELPFILE are dumped to him.
=back
=head1 NOTES
The hard coded F<help/> path should be changed.
=cut
my %config = ();
sub register {
my ($self,$qp,%args) = @_;
my ($file, $cmd);
unless (%args) {
$config{help_dir} = './help/';
}
foreach (keys %args) {
/^(\w+)$/ or
$self->log(LOGWARN, "Invalid argument for the 'help' plugin $_"),
next;
$cmd = $1;
if ($cmd eq 'not_implemented') {
$config{'not_implemented'} = $args{'not_implemented'};
}
elsif ($cmd eq 'help_dir') {
$file = $args{$cmd};
$file =~ m#^([\w\.\-/]+)$#
or $self->log(LOGERROR,
"Invalid charachters in filename for command $cmd"),
next;
$config{'help_dir'} = $1;
}
else {
$file = $args{$cmd};
$file =~ m#^([\w\.\-/]+)$#
or $self->log(LOGERROR,
"Invalid charachters in filename for command $cmd"),
next;
$file = $1;
if ($file =~ m#/#) {
-e $file
or $self->log(LOGWARN, "No help file for command '$cmd'"),
next;
}
else {
$file = "help/$file";
if (-e "help/$file") { ## FIXME: path
$file = "help/$file";
}
else {
$self->log(LOGWARN, "No help file for command '$cmd'");
next;
}
}
$config{lc $cmd} = $file;
}
}
return DECLINED;
}
sub hook_help {
my ($self, $transaction, @args) = @_;
my ($help, $cmd);
if ($config{not_implemented}) {
$self->qp->respond(502, "Not implemented.");
return DONE;
}
return OK, "Try 'HELP COMMAND' for getting help on COMMAND"
unless $args[0];
$cmd = lc $args[0];
unless ($cmd =~ /^(\w+)$/) { # else someone could request
# "HELP ../../../../../../../../etc/passwd"
$self->qp->respond(502, "Invalid command name");
return DONE;
}
$cmd = $1;
if (exists $config{$cmd}) {
$help = read_helpfile($config{$cmd}, $cmd)
or $self->log(LOGERROR, "failed to open help file for $cmd: $!"),
return OK, "No help available for SMTP command: $cmd";
}
elsif (exists $config{'help_dir'} && -e $config{'help_dir'}."/$cmd") {
$help = read_helpfile($config{help_dir}."/$cmd", $cmd)
or $self->log(LOGERROR, "failed to open help file for $cmd: $!"),
return OK, "No help available for SMTP command: $cmd";
}
$help = "No help available for SMTP command: $cmd" # empty file
unless $help;
return OK, split(/\n/, $help);
}
sub read_helpfile {
my ($file,$cmd) = @_;
my $help;
open HELP, $file
or return undef;
{
local $/ = undef;
$help = <HELP>;
};
close HELP;
return $help;
}
# vim: ts=4 sw=4 expandtab syn=perl
|