";
foreach my $msg (@{ $result->{messages} }) {
print "
Message: $msg
";
}
print br;
}
}
}
sub _show_error {
my $self = shift;
my $error = shift;
print header,
start_html(-title=>'Rspamd control', -script=>[{-type=>'JAVASCRIPT', -src=>'http://www.google.com/jsapi'},
{-type=>'JAVASCRIPT', -code=>'google.load("jquery", "1");'}]),
h1('Results for rspamd command'),
"
Error occured: $error
",
'Back to manage',
end_html;
}
sub _show_control_result {
my $self = shift;
my $host = shift;
my $res = shift;
if ($res->{error_code} == 0) {
print "
$res->{error}
";
}
else {
print "
Error occured: $res->{error}
";
}
}
sub _show_results {
my $self = shift;
my $rspamd = shift;
my $res = shift;
if (defined ($res->{error})) {
$self->_print_error($res->{error});
return;
}
print header,
start_html(-title=>'Rspamd control', -script=>[{-type=>'JAVASCRIPT', -src=>'http://www.google.com/jsapi'},
{-type=>'JAVASCRIPT', -code=>'google.load("jquery", "1");'}]),
h1('Results for rspamd command: ' . $rspamd->{command});
while (my ($host, $result) = each (%{ $res })) {
print h2('Results for host: ' . $host);
if ($rspamd->{control}) {
$self->_show_control_result ($host, $result);
}
else {
$self->_show_rspamc_result ($host, $result);
}
print hr;
}
print 'Back to manage';
print end_html;
}
sub _handle_form {
my $self = shift;
my $cgi = shift;
my @servers = $cgi->param('servers');
if (!@servers || scalar(@servers) == 0) {
@servers = @{ $cfg{'hosts'} };
}
my $rspamd = Mail::Rspamd::Client->new({hosts => \@servers, timeout=>$cfg{timeout}, password=>$cfg{password}});
my $cmd = $cgi->param('command');
if (!$cmd) {
return undef;
}
my $results;
if($cmd eq 'symbols' || $cmd eq 'check') {
my $msg = $self->_get_message($cgi);
return undef unless $msg;
$results = $rspamd->$cmd($msg);
}
elsif ($cmd eq 'learn') {
my $statfile = $cgi->param('statfile');
return undef unless $statfile;
my $msg = $self->_get_message($cgi);
return undef unless $msg;
$rspamd->{'statfile'} = $statfile;
if (my $weight = $cgi->param('weight')) {
$rspamd->{'weight'} = int($weight);
}
$results = $rspamd->learn($msg);
}
elsif ($cmd eq 'fuzzy_add' || $cmd eq 'fuzzy_del') {
my $msg = $self->_get_message($cgi);
return undef unless $msg;
if (my $weight = $cgi->param('weight')) {
$rspamd->{'weight'} = int($weight);
}
$results = $rspamd->$cmd($msg);
}
elsif ($cmd eq 'stat' || $cmd eq 'uptime') {
$results = $rspamd->$cmd();
}
$self->_show_results($rspamd, $results);
}
sub _handle_request {
my $self = shift;
my $cgi = shift;
my $path = $cgi->path_info();
unless ($path) {
print "CGI environment missing\n";
return undef;
}
print "HTTP/1.0 200 OK\r\n";
if ($cgi->request_method() eq 'POST') {
if (!$self->_handle_form($cgi)) {
$self->_show_error("invalid command");
}
}
else {
if ($path =~ '^/ajax$') {
$self->_handle_ping();
}
else {
$self->_show_html();
}
}
}
sub _run_standalone {
my $self = shift;
my $listen = IO::Socket::INET->new(
Listen => 5,
LocalAddr => $self->{addr},
LocalPort => $self->{port},
Proto => 'tcp',
ReuseAddr => 1
);
unless ($listen) {
warn "unable to listen on port $self->{port}: $!\n";
return undef;
};
print STDERR "waiting for connection on port $self->{port}\n";
while (1) {
my $s = $listen->accept();
open(STDOUT, ">&=".fileno($s));
open(STDIN, "<&=".fileno($s));
my ($req, $content);
delete $ENV{CONTENT_LENGTH};
{
local ($/) = "\r\n";
while () {
$req .= $_;
chomp;
last unless /\S/;
if (/^GET\s*(\S+)/) {
$ENV{REQUEST_METHOD} = 'GET';
my ($pi, $qs) = split /\?/, $1, 2;
$ENV{'PATH_INFO'} = $pi;
$ENV{'QUERY_STRING'} = $qs;
} elsif (/^POST\s*(\S+)/) {
$ENV{REQUEST_METHOD} = 'POST';
my ($pi, $qs) = split /\?/, $1, 2;
$ENV{'PATH_INFO'} = $pi;
$ENV{'QUERY_STRING'} = $qs;
} elsif (/^Content-Type:\s*(.*)/) {
$ENV{CONTENT_TYPE} = $1;
} elsif (/^Content-Length:\s*(.*)/) {
$ENV{CONTENT_LENGTH} = $1;
}
}
}
$ENV{SERVER_PORT} = $self->{port};
$ENV{SERVER_NAME} = $self->{addr};
if (my $size = $ENV{CONTENT_LENGTH}) {
$content = '';
while (length($content) < $size) {
my $nr = read(STDIN, $content, $size-length($content),
length($content));
warn "read error" unless $nr;
}
}
close(STDIN); # n.b.: does not close socket
tie *STDIN, 'IO::String', $content;
undef @CGI::QUERY_PARAM;
my $q = new CGI();
$self->_handle_request($q);
untie *STDIN;
close(STDOUT);
close($s);
}
}
sub run {
my $self = shift;
if ($self->{'standalone'} != 0) {
$self->_run_standalone();
}
else {
my $q = new CGI();
$self->_handle_request($q);
}
}
}
# Parse arguments
my ($port, $standalone, $cfg, $host);
while (my $arg = shift @ARGV) {
if ($arg =~ /^-port$/i) {
$port = shift @ARGV;
}
elsif ($arg =~ /^-standalone$/i) {
$standalone = 1;
}
elsif ($arg =~ /^-cfg$/i) {
$cfg = shift @ARGV;
}
elsif ($arg =~ /^-host$/i) {
$host = shift @ARGV;
}
else {
print STDERR <new({port=>$port, standalone=>$standalone, config=>$cfg, addr=>$host})->run();