]> git.proxmox.com Git - pmg-api.git/commitdiff
rename pmgspamreport to pmgqm
authorDietmar Maurer <dietmar@proxmox.com>
Fri, 28 Apr 2017 05:36:15 +0000 (07:36 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Fri, 28 Apr 2017 05:36:15 +0000 (07:36 +0200)
Makefile
PMG/CLI/pmgqm.pm [new file with mode: 0755]
PMG/CLI/pmgspamreport.pm [deleted file]
bin/pmgqm [new file with mode: 0644]
bin/pmgspamreport [deleted file]
debian/pmgspamreport.service

index 291fd9ed2bffab5913bf90e8fe7abd7f9cc66f45..055914e58ac10ef4535d523de66842e1ba7b7e0e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ BASHCOMPLDIR=${DESTDIR}/usr/share/bash-completion/completions/
 REPOID=`./repoid.pl .git`
 
 SERVICES = pmgdaemon pmgproxy pmgtunnel pmgmirror
-CLITOOLS = pmgdb pmgconfig pmgperf pmgcm pmgspamreport
+CLITOOLS = pmgdb pmgconfig pmgperf pmgcm pmgqm
 CLISCRIPTS = pmg-smtp-filter pmgsh pmgpolicy
 CRONSCRIPTS = pmg-hourly pmg-daily pmgspamreport
 
diff --git a/PMG/CLI/pmgqm.pm b/PMG/CLI/pmgqm.pm
new file mode 100755 (executable)
index 0000000..01a1b90
--- /dev/null
@@ -0,0 +1,442 @@
+package PMG::CLI::pmgqm;
+
+use strict;
+use Data::Dumper;
+use Template;
+use MIME::Entity;
+use HTML::Entities;
+use Time::Local;
+use Clone 'clone';
+use Mail::Header;
+use POSIX qw(strftime);
+use File::Find;
+use File::stat;
+
+use PVE::SafeSyslog;
+use PVE::Tools;
+use PVE::INotify;
+use PVE::CLIHandler;
+
+use PMG::RESTEnvironment;
+use PMG::Utils;
+use PMG::Ticket;
+use PMG::DBTools;
+use PMG::RuleDB;
+use PMG::Config;
+use PMG::ClusterConfig;
+
+use base qw(PVE::CLIHandler);
+
+sub setup_environment {
+    PMG::RESTEnvironment->setup_default_cli_env();
+}
+
+sub domain_regex {
+    my ($domains) = @_;
+
+    my @ra;
+    foreach my $d (@$domains) {
+       # skip domains with non-DNS name characters
+       next if $d =~ m/[^A-Za-z0-9\-\.]/;
+       if ($d =~ m/^\.(.*)$/) {
+           my $dom = $1;
+           $dom =~ s/\./\\\./g;
+           push @ra, $dom;
+           push @ra, "\.\*\\.$dom";
+       } else {
+           $d =~ s/\./\\\./g;
+           push @ra, $d;
+       }
+    }
+
+    my $re = join ('|', @ra);
+
+    my $regex = qr/\@($re)$/i;
+
+    return $regex;
+}
+
+sub get_item_data {
+    my ($data, $ref) = @_;
+
+    my @lines = split ('\n', $ref->{header});
+    my $head = new Mail::Header(\@lines);
+
+    my $item = {};
+
+    $item->{id} = sprintf("C%dR%d", $ref->{cid}, $ref->{rid});
+    
+    $item->{subject} = PMG::Utils::rfc1522_to_html(
+       PVE::Tools::trim($head->get('subject')) || 'No Subject');
+
+    my @fromarray = split('\s*,\s*', $head->get('from') || $ref->{sender});
+    my $from = PMG::Utils::rfc1522_to_html(PVE::Tools::trim($fromarray[0]));
+    my $sender = PMG::Utils::rfc1522_to_html(PVE::Tools::trim($head->get('sender')));
+
+    if ($sender) {
+       $item->{sender} = $sender;
+       $item->{from} = sprintf ("%s on behalf of %s", $sender, $from);
+    } else {
+       $item->{from} = $from;
+    }
+
+    $item->{pmail} = $ref->{pmail};
+    $item->{receiver} = $ref->{receiver} || $ref->{pmail};
+
+    $item->{date} = strftime("%F", localtime($ref->{time}));
+    $item->{time} = strftime("%H:%M:%S", localtime($ref->{time}));
+    $item->{bytes} = $ref->{bytes};
+    $item->{spamlevel} = $ref->{spamlevel};
+    $item->{spaminfo} = $ref->{info};
+      
+    my $title = "Received: $item->{date} $item->{time}\n";
+    $title .= "From: $ref->{sender}\n";
+    $title .= "To: $ref->{receiver}\n" if $ref->{receiver};
+    $title .= sprintf("Size: %d KB\n", int (($ref->{bytes} + 1023) / 1024 ));
+    $title .= sprintf("Spam level: %d\n", $ref->{spamlevel}) if $ref->{qtype} eq 'S';
+    $title .= sprintf("Virus info: %s\n", encode_entities ($ref->{info})) if $ref->{qtype} eq 'V';
+    $title .= sprintf("File: %s", encode_entities($ref->{file}));
+
+    $item->{title} = $title;
+
+    my $basehref = "https://$data->{fqdn}:$data->{port}/userquar";
+
+    $item->{wlhref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&whitelist=1";
+    $item->{blhref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&blacklist=1";
+    $item->{deliverhref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&deliver=1";
+    $item->{deletehref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&delete=1";
+
+    return $item;
+}
+
+sub finalize_report {
+    my ($tt, $template, $data, $mailfrom, $receiver, $debug) = @_;
+
+    my $html = '';
+
+    $tt->process($template, $data, \$html) ||
+       die $tt->error() . "\n";
+
+    my $title;
+    if ($html =~ m|^\s*<title>(.*)</title>|m) {
+       $title = $1;
+    } else {
+       die "unable to extract template title\n";
+    }
+
+    my $top = MIME::Entity->build(
+       Type    => "multipart/related",
+       To      => $data->{pmail},
+       From    => $mailfrom,
+       Subject => PMG::Utils::bencode_header(decode_entities($title)));
+
+    $top->attach(
+       Data     => $html,
+       Type     => "text/html",
+       Encoding => $debug ? 'binary' : 'quoted-printable');
+
+    if ($debug) {
+       $top->print();
+       return;
+    }
+    # we use an empty envelope sender (we dont want to receive NDRs)
+    PMG::Utils::reinject_mail ($top, '', [$receiver], undef, $data->{fqdn});
+}
+
+__PACKAGE__->register_method ({
+    name => 'send',
+    path => 'send',
+    method => 'POST',
+    description => "Generate and send spam report emails.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           receiver => {
+               description => "Generate report for a single email address. If not specified, generate reports for all users.",
+               type => 'string', format => 'email',
+               optional => 1,          
+           },
+           timespan => {
+               description => "Select time span.",
+               type => 'string',
+               enum => ['today', 'yesterday', 'week'],
+               default => 'today',
+               optional => 1,
+           },
+           style => {
+               description => "Spam report style. Value 'none' just prints the spam counts and does not send any emails. Default value is read from spam quarantine configuration.",
+               type => 'string',
+               enum => ['none', 'short', 'verbose', 'custom'],
+               optional => 1,
+           },
+           redirect => {
+               description => "Redirect spam report email to this address.",
+               type => 'string', format => 'email',
+               optional => 1,
+           },
+           debug => {
+               description => "Debug mode. Print raw email to stdout instead of sending them.",
+               type => 'boolean',
+               optional => 1,
+               default => 0,
+           }
+       },
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       my $cinfo = PMG::ClusterConfig->new();
+       my $role = $cinfo->{local}->{type} // '-';
+
+       if (!(($role eq '-') || ($role eq 'master'))) {
+          die "local node is not master - not sending spam report\n";
+       } 
+
+       my $cfg = PMG::Config->new();
+
+       my $reportstyle = $param->{style} // $cfg->get('spamquar', 'reportstyle');
+
+       my $timespan = $param->{timespan} // 'today';
+
+       my (undef, undef, undef, $mday, $mon, $year) = localtime(time());       
+       my $daystart = timelocal(0, 0, 0, $mday, $mon, $year);
+       
+       my $start;
+       my $end;
+       
+       if ($timespan eq 'today') {
+           $start = $daystart;
+           $end = $start + 86400;
+       } elsif ($timespan eq 'yesterday') {
+           $end = $daystart;
+           $start = $end - 86400;
+       } elsif ($timespan eq 'week') {
+           $end = $daystart;
+           $start = $end - 7*86400;
+       } else {
+           die "internal error";
+       }
+
+       my $hostname = PVE::INotify::nodename();
+       
+       my $fqdn = $cfg->get('spamquar', 'hostname') // 
+           PVE::Tools::get_fqdn($hostname);
+       
+       my $port = 8006;
+       
+       my $global_data = {
+           protocol => 'https',
+           port => $port,
+           fqdn => $fqdn,
+           hostname => $hostname,
+           date => strftime("%F", localtime($end - 1)),
+           timespan => $timespan,
+           items => [],
+       };
+
+       my $mailfrom = $cfg->get ('spamquar', 'mailfrom') // 
+           "Proxmox Mail Gateway <postmaster>";
+       
+       my $dbh = PMG::DBTools::open_ruledb();
+
+       my $target = $param->{receiver};
+       my $redirect = $param->{redirect};
+       
+       if (defined($redirect) && !defined($target)) {
+           die "can't redirect mails for all users\n";
+       }
+       
+       my $domains = PVE::INotify::read_file('domains');
+       my $domainregex = domain_regex([keys %$domains]);
+
+       my $template;
+
+       if ($reportstyle ne 'none') {
+
+           $template = "spamreport-${reportstyle}.tt";
+           my $found = 0;
+           foreach my $path (@$PMG::Config::tt_include_path) {
+               if (-f "$path/$template") { $found = 1; last; }
+           }
+           if (!$found) {
+               warn "unable to find template '$template' - using default\n";
+               $template = "spamreport-verbose.tt";
+           }
+       }
+
+       my $sth = $dbh->prepare(
+           "SELECT * FROM CMailStore, CMSReceivers " . 
+           "WHERE time >= $start AND time < $end AND " . 
+           ($target ? "pmail = ? AND " : '') .
+           "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
+           "AND Status = 'N' " .
+           "ORDER BY pmail, time, receiver");
+           
+       if ($target) {
+           $sth->execute($target);
+       } else {
+           $sth->execute();
+       }
+
+       my $lastref;
+       my $mailcount = 0;
+       my $creceiver = '';
+       my $data;
+
+       my $tt = PMG::Config::get_template_toolkit();
+
+       my $finalize = sub {
+           
+           my $extern = ($domainregex && $creceiver !~ $domainregex);
+               
+           if ($template) {
+               if (!$extern) {
+                   $data->{mailcount} = $mailcount;
+                   my $sendto = $redirect ? $redirect : $creceiver;
+                   finalize_report($tt, $template, $data, $mailfrom, $sendto, $param->{debug});
+               }
+           } else {
+               my $hint = $extern ? " (external address)" : "";
+               printf ("%-5d %s$hint\n", $mailcount, $creceiver);
+           }
+       };
+       
+       while (my $ref = $sth->fetchrow_hashref()) {
+           if ($creceiver ne $ref->{pmail}) {
+
+               $finalize->() if $data;
+
+               $data = clone($global_data);
+               
+               $creceiver = $ref->{pmail};
+               $mailcount = 0;
+
+               $data->{pmail} = $creceiver;
+               $data->{ticket} = PMG::Ticket::assemble_quarantine_ticket($data->{pmail});
+               $data->{managehref} = "https://$fqdn:$port?ticket=$data->{ticket}";
+           }
+
+           if ($template) {
+               push @{$data->{items}}, get_item_data($data, $ref);
+           }
+           
+           $mailcount++;
+           $lastref = $ref;
+       }
+
+       $sth->finish();
+
+       $finalize->() if $data;
+
+       if (defined($target) && !$mailcount) {
+           print STDERR "no mails for '$target'\n";
+       }
+
+       return undef;
+    }});
+
+sub find_stale_files {
+    my ($path, $lifetime, $purge) = @_;
+
+    return if ! -d $path;
+
+    my (undef, undef, undef, $mday, $mon, $year) = localtime(time());
+    my $daystart = timelocal(0, 0, 0, $mday, $mon, $year);
+    my $expire = $daystart - $lifetime*86400;
+
+    my $wanted = sub {
+       my $name = $File::Find::name;
+       return if $name !~ m|^($path/.*)$|;
+       $name = $1; # untaint
+       my $stat = stat($name);
+       return if ! -f _;
+       return if $stat->mtime >= $expire;
+       if ($purge) {
+           if (unlink($name)) {
+               print "removed: $name\n";
+           }
+       } else {
+           print "$name\n";
+       }
+    };
+
+    find({ wanted => $wanted, no_chdir => 1 }, $path);
+}
+
+sub test_quarantine_files {
+    my ($spamlifetime, $viruslifetime, $purge) = @_;
+    
+    print STDERR "searching for stale files\n" if !$purge; 
+
+    my $spooldir = $PMG::MailQueue::spooldir;
+
+    find_stale_files ("$spooldir/spam", $spamlifetime, $purge);
+    foreach my $dir (<"/var/spool/pmg/cluster/*/spam">) {
+       next if $dir !~ m|^(/var/spool/pmg/cluster/\d+/spam)$|;
+       $dir = $1; # untaint
+       find_stale_files ($dir, $spamlifetime, $purge);
+    }
+
+    find_stale_files ("$spooldir/virus", $viruslifetime, $purge);
+    foreach my $dir (<"/var/spool/pmg/cluster/*/virus">) {
+       next if $dir !~ m|^(/var/spool/pmg/cluster/\d+/virus)$|;
+       $dir = $1; # untaint
+       find_stale_files ($dir, $viruslifetime, $purge);
+    }
+}
+
+__PACKAGE__->register_method ({
+    name => 'purge',
+    path => 'purge',
+    method => 'POST',
+    description => "Cleanup Quarantine database. Remove entries older than configured quarantine lifetime.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           check => {
+               description => "Only search for quarantine files older than configured quarantine lifetime. Just print found files, but does not remove them.",
+               type => 'boolean',
+               optional => 1,
+               default => 0,
+           }
+       }
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       my $cfg = PMG::Config->new();
+
+       my $spamlifetime = $cfg->get('spamquar', 'lifetime');
+       my $viruslifetime = $cfg->get ('virusquar', 'lifetime');
+
+       my $purge = !$param->{check};
+
+       if ($purge) {
+           print STDERR "purging database\n"; 
+
+           my $dbh = PMG::DBTools::open_ruledb();
+
+           if (my $count = PMG::DBTools::purge_quarantine_database($dbh, 'S', $spamlifetime)) {
+               print STDERR "removed $count spam quarantine files\n"; 
+           }
+
+           if (my $count = PMG::DBTools::purge_quarantine_database($dbh, 'V', $viruslifetime)) {
+               print STDERR "removed $count virus quarantine files\n"; 
+           }
+       }
+
+       test_quarantine_files($spamlifetime, $viruslifetime, $purge);
+
+       return undef;
+    }});
+
+
+our $cmddef = {
+    'purge' => [ __PACKAGE__, 'purge', []],
+    'send' => [ __PACKAGE__, 'send', []],
+};
+
+1;
diff --git a/PMG/CLI/pmgspamreport.pm b/PMG/CLI/pmgspamreport.pm
deleted file mode 100755 (executable)
index 43902ea..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-package PMG::CLI::pmgspamreport;
-
-use strict;
-use Data::Dumper;
-use Template;
-use MIME::Entity;
-use HTML::Entities;
-use Time::Local;
-use Clone 'clone';
-use Mail::Header;
-use POSIX qw(strftime);
-use File::Find;
-use File::stat;
-
-use PVE::SafeSyslog;
-use PVE::Tools;
-use PVE::INotify;
-use PVE::CLIHandler;
-
-use PMG::RESTEnvironment;
-use PMG::Utils;
-use PMG::Ticket;
-use PMG::DBTools;
-use PMG::RuleDB;
-use PMG::Config;
-use PMG::ClusterConfig;
-
-use base qw(PVE::CLIHandler);
-
-sub setup_environment {
-    PMG::RESTEnvironment->setup_default_cli_env();
-}
-
-sub domain_regex {
-    my ($domains) = @_;
-
-    my @ra;
-    foreach my $d (@$domains) {
-       # skip domains with non-DNS name characters
-       next if $d =~ m/[^A-Za-z0-9\-\.]/;
-       if ($d =~ m/^\.(.*)$/) {
-           my $dom = $1;
-           $dom =~ s/\./\\\./g;
-           push @ra, $dom;
-           push @ra, "\.\*\\.$dom";
-       } else {
-           $d =~ s/\./\\\./g;
-           push @ra, $d;
-       }
-    }
-
-    my $re = join ('|', @ra);
-
-    my $regex = qr/\@($re)$/i;
-
-    return $regex;
-}
-
-sub get_item_data {
-    my ($data, $ref) = @_;
-
-    my @lines = split ('\n', $ref->{header});
-    my $head = new Mail::Header(\@lines);
-
-    my $item = {};
-
-    $item->{id} = sprintf("C%dR%d", $ref->{cid}, $ref->{rid});
-    
-    $item->{subject} = PMG::Utils::rfc1522_to_html(
-       PVE::Tools::trim($head->get('subject')) || 'No Subject');
-
-    my @fromarray = split('\s*,\s*', $head->get('from') || $ref->{sender});
-    my $from = PMG::Utils::rfc1522_to_html(PVE::Tools::trim($fromarray[0]));
-    my $sender = PMG::Utils::rfc1522_to_html(PVE::Tools::trim($head->get('sender')));
-
-    if ($sender) {
-       $item->{sender} = $sender;
-       $item->{from} = sprintf ("%s on behalf of %s", $sender, $from);
-    } else {
-       $item->{from} = $from;
-    }
-
-    $item->{pmail} = $ref->{pmail};
-    $item->{receiver} = $ref->{receiver} || $ref->{pmail};
-
-    $item->{date} = strftime("%F", localtime($ref->{time}));
-    $item->{time} = strftime("%H:%M:%S", localtime($ref->{time}));
-    $item->{bytes} = $ref->{bytes};
-    $item->{spamlevel} = $ref->{spamlevel};
-    $item->{spaminfo} = $ref->{info};
-      
-    my $title = "Received: $item->{date} $item->{time}\n";
-    $title .= "From: $ref->{sender}\n";
-    $title .= "To: $ref->{receiver}\n" if $ref->{receiver};
-    $title .= sprintf("Size: %d KB\n", int (($ref->{bytes} + 1023) / 1024 ));
-    $title .= sprintf("Spam level: %d\n", $ref->{spamlevel}) if $ref->{qtype} eq 'S';
-    $title .= sprintf("Virus info: %s\n", encode_entities ($ref->{info})) if $ref->{qtype} eq 'V';
-    $title .= sprintf("File: %s", encode_entities($ref->{file}));
-
-    $item->{title} = $title;
-
-    my $basehref = "https://$data->{fqdn}:$data->{port}/userquar";
-
-    $item->{wlhref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&whitelist=1";
-    $item->{blhref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&blacklist=1";
-    $item->{deliverhref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&deliver=1";
-    $item->{deletehref} = "$basehref?ticket=$data->{ticket}&cselect=$item->{id}&delete=1";
-
-    return $item;
-}
-
-sub finalize_report {
-    my ($tt, $template, $data, $mailfrom, $receiver, $debug) = @_;
-
-    my $html = '';
-
-    $tt->process($template, $data, \$html) ||
-       die $tt->error() . "\n";
-
-    my $title;
-    if ($html =~ m|^\s*<title>(.*)</title>|m) {
-       $title = $1;
-    } else {
-       die "unable to extract template title\n";
-    }
-
-    my $top = MIME::Entity->build(
-       Type    => "multipart/related",
-       To      => $data->{pmail},
-       From    => $mailfrom,
-       Subject => PMG::Utils::bencode_header(decode_entities($title)));
-
-    $top->attach(
-       Data     => $html,
-       Type     => "text/html",
-       Encoding => $debug ? 'binary' : 'quoted-printable');
-
-    if ($debug) {
-       $top->print();
-       return;
-    }
-    # we use an empty envelope sender (we dont want to receive NDRs)
-    PMG::Utils::reinject_mail ($top, '', [$receiver], undef, $data->{fqdn});
-}
-
-__PACKAGE__->register_method ({
-    name => 'send',
-    path => 'send',
-    method => 'POST',
-    description => "Generate and send spam report emails.",
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           receiver => {
-               description => "Generate report for a single email address. If not specified, generate reports for all users.",
-               type => 'string', format => 'email',
-               optional => 1,          
-           },
-           timespan => {
-               description => "Select time span.",
-               type => 'string',
-               enum => ['today', 'yesterday', 'week'],
-               default => 'today',
-               optional => 1,
-           },
-           style => {
-               description => "Spam report style. Value 'none' just prints the spam counts and does not send any emails. Default value is read from spam quarantine configuration.",
-               type => 'string',
-               enum => ['none', 'short', 'verbose', 'custom'],
-               optional => 1,
-           },
-           redirect => {
-               description => "Redirect spam report email to this address.",
-               type => 'string', format => 'email',
-               optional => 1,
-           },
-           debug => {
-               description => "Debug mode. Print raw email to stdout instead of sending them.",
-               type => 'boolean',
-               optional => 1,
-               default => 0,
-           }
-       },
-    },
-    returns => { type => 'null'},
-    code => sub {
-       my ($param) = @_;
-
-       my $cinfo = PMG::ClusterConfig->new();
-       my $role = $cinfo->{local}->{type} // '-';
-
-       if (!(($role eq '-') || ($role eq 'master'))) {
-          die "local node is not master - not sending spam report\n";
-       } 
-
-       my $cfg = PMG::Config->new();
-
-       my $reportstyle = $param->{style} // $cfg->get('spamquar', 'reportstyle');
-
-       my $timespan = $param->{timespan} // 'today';
-
-       my (undef, undef, undef, $mday, $mon, $year) = localtime(time());       
-       my $daystart = timelocal(0, 0, 0, $mday, $mon, $year);
-       
-       my $start;
-       my $end;
-       
-       if ($timespan eq 'today') {
-           $start = $daystart;
-           $end = $start + 86400;
-       } elsif ($timespan eq 'yesterday') {
-           $end = $daystart;
-           $start = $end - 86400;
-       } elsif ($timespan eq 'week') {
-           $end = $daystart;
-           $start = $end - 7*86400;
-       } else {
-           die "internal error";
-       }
-
-       my $hostname = PVE::INotify::nodename();
-       
-       my $fqdn = $cfg->get('spamquar', 'hostname') // 
-           PVE::Tools::get_fqdn($hostname);
-       
-       my $port = 8006;
-       
-       my $global_data = {
-           protocol => 'https',
-           port => $port,
-           fqdn => $fqdn,
-           hostname => $hostname,
-           date => strftime("%F", localtime($end - 1)),
-           timespan => $timespan,
-           items => [],
-       };
-
-       my $mailfrom = $cfg->get ('spamquar', 'mailfrom') // 
-           "Proxmox Mail Gateway <postmaster>";
-       
-       my $dbh = PMG::DBTools::open_ruledb();
-
-       my $target = $param->{receiver};
-       my $redirect = $param->{redirect};
-       
-       if (defined($redirect) && !defined($target)) {
-           die "can't redirect mails for all users\n";
-       }
-       
-       my $domains = PVE::INotify::read_file('domains');
-       my $domainregex = domain_regex([keys %$domains]);
-
-       my $template;
-
-       if ($reportstyle ne 'none') {
-
-           $template = "spamreport-${reportstyle}.tt";
-           my $found = 0;
-           foreach my $path (@$PMG::Config::tt_include_path) {
-               if (-f "$path/$template") { $found = 1; last; }
-           }
-           if (!$found) {
-               warn "unable to find template '$template' - using default\n";
-               $template = "spamreport-verbose.tt";
-           }
-       }
-
-       my $sth = $dbh->prepare(
-           "SELECT * FROM CMailStore, CMSReceivers " . 
-           "WHERE time >= $start AND time < $end AND " . 
-           ($target ? "pmail = ? AND " : '') .
-           "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
-           "AND Status = 'N' " .
-           "ORDER BY pmail, time, receiver");
-           
-       if ($target) {
-           $sth->execute($target);
-       } else {
-           $sth->execute();
-       }
-
-       my $lastref;
-       my $mailcount = 0;
-       my $creceiver = '';
-       my $data;
-
-       my $tt = PMG::Config::get_template_toolkit();
-
-       my $finalize = sub {
-           
-           my $extern = ($domainregex && $creceiver !~ $domainregex);
-               
-           if ($template) {
-               if (!$extern) {
-                   $data->{mailcount} = $mailcount;
-                   my $sendto = $redirect ? $redirect : $creceiver;
-                   finalize_report($tt, $template, $data, $mailfrom, $sendto, $param->{debug});
-               }
-           } else {
-               my $hint = $extern ? " (external address)" : "";
-               printf ("%-5d %s$hint\n", $mailcount, $creceiver);
-           }
-       };
-       
-       while (my $ref = $sth->fetchrow_hashref()) {
-           if ($creceiver ne $ref->{pmail}) {
-
-               $finalize->() if $data;
-
-               $data = clone($global_data);
-               
-               $creceiver = $ref->{pmail};
-               $mailcount = 0;
-
-               $data->{pmail} = $creceiver;
-               $data->{ticket} = PMG::Ticket::assemble_quarantine_ticket($data->{pmail});
-               $data->{managehref} = "https://$fqdn:$port?ticket=$data->{ticket}";
-           }
-
-           if ($template) {
-               push @{$data->{items}}, get_item_data($data, $ref);
-           }
-           
-           $mailcount++;
-           $lastref = $ref;
-       }
-
-       $sth->finish();
-
-       $finalize->() if $data;
-
-       if (defined($target) && !$mailcount) {
-           print STDERR "no mails for '$target'\n";
-       }
-
-       return undef;
-    }});
-
-sub find_stale_files {
-    my ($path, $lifetime, $purge) = @_;
-
-    return if ! -d $path;
-
-    my (undef, undef, undef, $mday, $mon, $year) = localtime(time());
-    my $daystart = timelocal(0, 0, 0, $mday, $mon, $year);
-    my $expire = $daystart - $lifetime*86400;
-
-    my $wanted = sub {
-       my $name = $File::Find::name;
-       return if $name !~ m|^($path/.*)$|;
-       $name = $1; # untaint
-       my $stat = stat($name);
-       return if ! -f _;
-       return if $stat->mtime >= $expire;
-       if ($purge) {
-           if (unlink($name)) {
-               print "removed: $name\n";
-           }
-       } else {
-           print "$name\n";
-       }
-    };
-
-    find({ wanted => $wanted, no_chdir => 1 }, $path);
-}
-
-sub test_quarantine_files {
-    my ($spamlifetime, $viruslifetime, $purge) = @_;
-    
-    print STDERR "searching for stale files\n" if !$purge; 
-
-    my $spooldir = $PMG::MailQueue::spooldir;
-
-    find_stale_files ("$spooldir/spam", $spamlifetime, $purge);
-    foreach my $dir (<"/var/spool/pmg/cluster/*/spam">) {
-       next if $dir !~ m|^(/var/spool/pmg/cluster/\d+/spam)$|;
-       $dir = $1; # untaint
-       find_stale_files ($dir, $spamlifetime, $purge);
-    }
-
-    find_stale_files ("$spooldir/virus", $viruslifetime, $purge);
-    foreach my $dir (<"/var/spool/pmg/cluster/*/virus">) {
-       next if $dir !~ m|^(/var/spool/pmg/cluster/\d+/virus)$|;
-       $dir = $1; # untaint
-       find_stale_files ($dir, $viruslifetime, $purge);
-    }
-}
-
-__PACKAGE__->register_method ({
-    name => 'purge',
-    path => 'purge',
-    method => 'POST',
-    description => "Cleanup Quarantine database. Remove entries older than configured quarantine lifetime.",
-    parameters => {
-       additionalProperties => 0,
-       properties => {
-           check => {
-               description => "Only search for quarantine files older than configured quarantine lifetime. Just print found files, but does not remove them.",
-               type => 'boolean',
-               optional => 1,
-               default => 0,
-           }
-       }
-    },
-    returns => { type => 'null'},
-    code => sub {
-       my ($param) = @_;
-
-       my $cfg = PMG::Config->new();
-
-       my $spamlifetime = $cfg->get('spamquar', 'lifetime');
-       my $viruslifetime = $cfg->get ('virusquar', 'lifetime');
-
-       my $purge = !$param->{check};
-
-       if ($purge) {
-           print STDERR "purging database\n"; 
-
-           my $dbh = PMG::DBTools::open_ruledb();
-
-           if (my $count = PMG::DBTools::purge_quarantine_database($dbh, 'S', $spamlifetime)) {
-               print STDERR "removed $count spam quarantine files\n"; 
-           }
-
-           if (my $count = PMG::DBTools::purge_quarantine_database($dbh, 'V', $viruslifetime)) {
-               print STDERR "removed $count virus quarantine files\n"; 
-           }
-       }
-
-       test_quarantine_files($spamlifetime, $viruslifetime, $purge);
-
-       return undef;
-    }});
-
-
-our $cmddef = {
-    'purge' => [ __PACKAGE__, 'purge', []],
-    'send' => [ __PACKAGE__, 'send', []],
-};
-
-1;
diff --git a/bin/pmgqm b/bin/pmgqm
new file mode 100644 (file)
index 0000000..1ff24bb
--- /dev/null
+++ b/bin/pmgqm
@@ -0,0 +1,8 @@
+#!/usr/bin/perl -T
+
+use strict;
+use warnings;
+
+use PMG::CLI::pmgqm;
+
+PMG::CLI::pmgqm->run_cli_handler();
diff --git a/bin/pmgspamreport b/bin/pmgspamreport
deleted file mode 100644 (file)
index 0749375..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/perl -T
-
-use strict;
-use warnings;
-
-use PMG::CLI::pmgspamreport;
-
-PMG::CLI::pmgspamreport->run_cli_handler();
index 47a86787d625a6e9b67d703f6ae6605843d3f620..5b7c094846151a18ba7666288fce4d15d9bfa3fa 100644 (file)
@@ -1,9 +1,9 @@
 [Unit]
 Description=Send Daily Spam Report Mails
-ConditionPathExists=/usr/bin/pmgspamreport
+ConditionPathExists=/usr/bin/pmgqm
 
 [Service]
 Type=oneshot
-ExecStart=/usr/bin/pmgspamreport send --timespan yesterday
-ExecStartPost=/usr/bin/pmgspamreport purge
+ExecStart=/usr/bin/pmgqm send --timespan yesterday
+ExecStartPost=/usr/bin/pmgqm purge