diff --git a/plugins/help b/plugins/help new file mode 100644 index 0000000..373f7b0 --- /dev/null +++ b/plugins/help @@ -0,0 +1,145 @@ +# +# +# + +=head1 NAME + +help - default help plugin for qpsmtpd + +=head1 DESCRIPTION + +The B plugin gives the answers for the help command. It can be configured +to return C<502 Not implemented>. + +Without any arguments, the C 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 command is not implemented + +=item help_dir /path/to/help/files/ + +When a client requests help for C the file F 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 sub directory. If the client calls C +the contents of HELPFILE are dumped to him. + +=back + +=head1 NOTES + +The hard coded F 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 = ; + }; + close HELP; + return $help; +} + +# vim: ts=4 sw=4 expandtab syn=perl