use Encode;
use Mail::Header;
+use Mail::SpamAssassin;
use PVE::SafeSyslog;
use PVE::Exception qw(raise_param_exc raise_perm_exc);
my $spamdesc;
+my $extract_pmail = sub {
+ my ($authuser, $role) = @_;
+
+ if ($authuser =~ m/^(.+)\@quarantine$/) {
+ return $1;
+ }
+ raise_param_exc({ pmail => "got unexpected authuser '$authuser' with role '$role'"});
+};
+
my $verify_optional_pmail = sub {
- my ($authuser, $role, $pmail) = @_;
+ my ($authuser, $role, $pmail_param) = @_;
+ my $pmail;
if ($role eq 'quser') {
+ $pmail = $extract_pmail->($authuser, $role);
raise_param_exc({ pmail => "parameter not allwed with role '$role'"})
- if defined($pmail);
- $pmail = $authuser;
+ if defined($pmail_param) && ($pmail ne $pmail_param);
} else {
raise_param_exc({ pmail => "parameter required with role '$role'"})
- if !defined($pmail);
+ if !defined($pmail_param);
+ $pmail = $pmail_param;
}
return $pmail;
};
sub decode_spaminfo {
my ($info) = @_;
- $spamdesc = PMG::Utils::load_sa_descriptions() if !$spamdesc;
+ my $saversion = Mail::SpamAssassin->VERSION;
+
+ my $salocaldir = "/var/lib/spamassassin/$saversion/updates_spamassassin_org";
+
+ $spamdesc = PMG::Utils::load_sa_descriptions([$salocaldir]) if !$spamdesc;
my $res = [];
foreach my $test (split (',', $info)) {
my ($name, $score) = split (':', $test);
- my $info = { name => $name, score => $score, desc => '-' };
+ my $info = { name => $name, score => $score + 0, desc => '-' };
if (my $si = $spamdesc->{$name}) {
$info->{desc} = $si->{desc};
$info->{url} = $si->{url} if defined($si->{url});
$res->{envelope_sender} = $ref->{sender};
$res->{receiver} = $ref->{receiver} // $ref->{pmail};
- $res->{id} = 'C' . $ref->{cid} . 'R' . $ref->{rid};
+ $res->{id} = 'C' . $ref->{cid} . 'R' . $ref->{rid} . 'T' . $ref->{ticketid};
$res->{time} = $ref->{time};
$res->{bytes} = $ref->{bytes};
if ($qtype eq 'V') {
$res->{virusname} = $ref->{info};
+ $res->{spamlevel} = 0;
} elsif ($qtype eq 'S') {
$res->{spamlevel} = $ref->{spamlevel} // 0;
}
{ name => 'content' },
{ name => 'spam' },
{ name => 'spamusers' },
+ { name => 'spamstatus' },
{ name => 'virus' },
+ { name => 'virusstatus' },
{ name => 'quarusers' },
];
return $res;
};
-my $address_pattern = '[a-zA-Z0-9\+\-\_\*\.\@]+';
-
__PACKAGE__->register_method ({
name => 'whitelist',
path => 'whitelist',
additionalProperties => 0,
properties => {
pmail => $pmail_param_type,
- address => {
+ address => get_standard_option('pmg-whiteblacklist-entry-list', {
description => "The address you want to add.",
- type => "string",
- pattern => $address_pattern,
- maxLength => 512,
- },
+ }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- $read_or_modify_user_bw_list->('WL', $param, [ $param->{address} ]);
+ my $addresses = [split(',', $param->{address})];
+ $read_or_modify_user_bw_list->('WL', $param, $addresses);
return undef;
}});
additionalProperties => 0,
properties => {
pmail => $pmail_param_type,
- address => {
+ address => get_standard_option('pmg-whiteblacklist-entry-list', {
description => "The address you want to remove.",
- type => "string",
- pattern => $address_pattern,
- maxLength => 512,
- },
+ }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- $read_or_modify_user_bw_list->('WL', $param, [ $param->{address} ], 1);
+ my $addresses = [split(',', $param->{address})];
+ $read_or_modify_user_bw_list->('WL', $param, $addresses, 1);
return undef;
}});
additionalProperties => 0,
properties => {
pmail => $pmail_param_type,
- address => {
+ address => get_standard_option('pmg-whiteblacklist-entry-list', {
description => "The address you want to add.",
- type => "string",
- pattern => $address_pattern,
- maxLength => 512,
- },
+ }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- $read_or_modify_user_bw_list->('BL', $param, [ $param->{address} ]);
+ my $addresses = [split(',', $param->{address})];
+ $read_or_modify_user_bw_list->('BL', $param, $addresses);
return undef;
}});
additionalProperties => 0,
properties => {
pmail => $pmail_param_type,
- address => {
+ address => get_standard_option('pmg-whiteblacklist-entry-list', {
description => "The address you want to remove.",
- type => "string",
- pattern => $address_pattern,
- maxLength => 512,
- },
+ }),
},
},
returns => { type => 'null' },
code => sub {
my ($param) = @_;
- $read_or_modify_user_bw_list->('BL', $param, [ $param->{address} ], 1);
+ my $addresses = [split(',', $param->{address})];
+ $read_or_modify_user_bw_list->('BL', $param, $addresses, 1);
return undef;
}});
parameters => {
additionalProperties => 0,
properties => {
- starttime => {
- description => "Only consider entries newer than 'starttime' (unix epoch). Default is 'now - 1day'.",
- type => 'integer',
- minimum => 0,
- optional => 1,
- },
- endtime => {
- description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
- type => 'integer',
- minimum => 1,
- optional => 1,
- },
+ starttime => get_standard_option('pmg-starttime'),
+ endtime => get_standard_option('pmg-endtime'),
},
},
returns => {
return $res;
}});
+__PACKAGE__->register_method ({
+ name => 'spamstatus',
+ path => 'spamstatus',
+ method => 'GET',
+ permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+ description => "Get Spam Quarantine Status",
+ parameters => {
+ additionalProperties => 0,
+ properties => {},
+ },
+ returns => {
+ type => "object",
+ properties => {
+ count => {
+ description => 'Number of stored mails.',
+ type => 'integer',
+ },
+ mbytes => {
+ description => "Estimated disk space usage in MByte.",
+ type => 'number',
+ },
+ avgbytes => {
+ description => "Average size of stored mails in bytes.",
+ type => 'number',
+ },
+ avgspam => {
+ description => "Average spam level.",
+ type => 'number',
+ },
+ },
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $dbh = PMG::DBTools::open_ruledb();
+ my $ref = PMG::DBTools::get_quarantine_count($dbh, 'S');
+
+ return $ref;
+ }});
+
__PACKAGE__->register_method ({
name => 'quarusers',
path => 'quarusers',
description => "Get a list of users with whitelist/blacklist setttings.",
parameters => {
additionalProperties => 0,
- properties => {},
+ properties => {
+ list => {
+ type => 'string',
+ description => 'If set, limits the result to the given list.',
+ enum => ['BL', 'WL'],
+ optional => 1,
+ },
+ },
},
returns => {
type => 'array',
my $dbh = PMG::DBTools::open_ruledb();
- my $sth = $dbh->prepare(
- "SELECT DISTINCT pmail FROM UserPrefs ORDER BY pmail");
-
- $sth->execute();
+ my $sth;
+ if ($param->{list}) {
+ $sth = $dbh->prepare("SELECT DISTINCT pmail FROM UserPrefs WHERE name = ? ORDER BY pmail");
+ $sth->execute($param->{list});
+ } else {
+ $sth = $dbh->prepare("SELECT DISTINCT pmail FROM UserPrefs ORDER BY pmail");
+ $sth->execute();
+ }
while (my $ref = $sth->fetchrow_hashref()) {
push @$res, { mail => $ref->{pmail} };
parameters => {
additionalProperties => 0,
properties => {
- starttime => {
- description => "Only consider entries newer than 'starttime' (unix epoch). This is set to 'now - 1day' by default.",
- type => 'integer',
- minimum => 0,
- optional => 1,
- },
- endtime => {
- description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
- type => 'integer',
- minimum => 1,
- optional => 1,
- },
+ starttime => get_standard_option('pmg-starttime'),
+ endtime => get_standard_option('pmg-endtime'),
pmail => $pmail_param_type,
},
},
parameters => {
additionalProperties => 0,
properties => {
- starttime => {
- description => "Only consider entries newer than 'starttime' (unix epoch). This is set to 'now - 1day' by default.",
- type => 'integer',
- minimum => 0,
- optional => 1,
- },
- endtime => {
- description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
- type => 'integer',
- minimum => 1,
- optional => 1,
- },
+ starttime => get_standard_option('pmg-starttime'),
+ endtime => get_standard_option('pmg-endtime'),
},
},
returns => {
return $res;
}});
+__PACKAGE__->register_method ({
+ name => 'virusstatus',
+ path => 'virusstatus',
+ method => 'GET',
+ permissions => { check => [ 'admin', 'qmanager', 'audit'] },
+ description => "Get Virus Quarantine Status",
+ parameters => {
+ additionalProperties => 0,
+ properties => {},
+ },
+ returns => {
+ type => "object",
+ properties => {
+ count => {
+ description => 'Number of stored mails.',
+ type => 'integer',
+ },
+ mbytes => {
+ description => "Estimated disk space usage in MByte.",
+ type => 'number',
+ },
+ avgbytes => {
+ description => "Average size of stored mails in bytes.",
+ type => 'number',
+ },
+ },
+ },
+ code => sub {
+ my ($param) = @_;
+
+ my $dbh = PMG::DBTools::open_ruledb();
+ my $ref = PMG::DBTools::get_quarantine_count($dbh, 'V');
+
+ delete $ref->{avgspam};
+
+ return $ref;
+ }});
+
__PACKAGE__->register_method ({
name => 'content',
path => 'content',
id => {
description => 'Unique ID',
type => 'string',
- pattern => 'C\d+R\d+',
- maxLength => 40,
+ pattern => 'C\d+R\d+T\d+',
+ maxLength => 60,
},
raw => {
- description => "Display 'raw' eml data. This is only used with the 'htmlmail' formatter.",
+ description => "Display 'raw' eml data. Deactivates size limit.",
type => 'boolean',
optional => 1,
default => 0,
my $role = $rpcenv->get_role();
my $format = $rpcenv->get_format();
- my ($cid, $rid) = $param->{id} =~ m/^C(\d+)R(\d+)$/;
+ my $raw = $param->{raw} // 0;
+
+ my ($cid, $rid, $tid) = $param->{id} =~ m/^C(\d+)R(\d+)T(\d+)$/;
$cid = int($cid);
$rid = int($rid);
+ $tid = int($tid);
my $dbh = PMG::DBTools::open_ruledb();
- my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid);
+ my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid, $tid);
if ($role eq 'quser') {
- raise_perm_exc("mail does not belong to user '$authuser'")
- if $authuser ne $ref->{pmail};
+ my $quar_username = $ref->{pmail} . '@quarantine';
+ raise_perm_exc("mail does not belong to user '$authuser' ($ref->{pmail})")
+ if $authuser ne $quar_username;
}
my $res = $parse_header_info->($ref);
-
my $filename = $ref->{file};
my $spooldir = $PMG::MailQueue::spooldir;
my $viewimages = $cfg->get('spamquar', 'viewimages');
my $allowhref = $cfg->get('spamquar', 'allowhrefs');
- $res->{content} = PMG::HTMLMail::email_to_html($path, $param->{raw}, $viewimages, $allowhref);
+ $res->{content} = PMG::HTMLMail::email_to_html($path, $raw, $viewimages, $allowhref);
# to make result verification happy
$res->{file} = '';
$res->{header} = '';
+ $res->{spamlevel} = 0;
$res->{spaminfo} = [];
} else {
# include additional details
- my ($header, $content) = PMG::HTMLMail::read_raw_email($path, 4096);
+ # we want to get the whole email in raw mode
+ my $maxbytes = (!$raw)? 4096 : undef;
+
+ my ($header, $content) = PMG::HTMLMail::read_raw_email($path, $maxbytes);
$res->{file} = $ref->{file};
$res->{spaminfo} = decode_spaminfo($ref->{info});
additionalProperties => 0,
properties => {
id => {
- description => 'Unique ID',
+ description => 'Unique IDs, seperate with ;',
type => 'string',
- pattern => 'C\d+R\d+',
- maxLength => 40,
+ pattern => 'C\d+R\d+T\d+(;C\d+R\d+T\d+)*',
},
action => {
description => 'Action - specify what you want to do with the mail.',
my $authuser = $rpcenv->get_user();
my $role = $rpcenv->get_role();
my $action = $param->{action};
-
- my ($cid, $rid) = $param->{id} =~ m/^C(\d+)R(\d+)$/;
- $cid = int($cid);
- $rid = int($rid);
+ my @idlist = split(';', $param->{id});
my $dbh = PMG::DBTools::open_ruledb();
- my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid);
-
- if ($role eq 'quser') {
- raise_perm_exc("mail does not belong to user '$authuser'")
- if $authuser ne $ref->{pmail};
- }
-
- my $sender = $get_real_sender->($ref);
- my $username = $ref->{pmail};
-
- if ($action eq 'whitelist') {
- PMG::Quarantine::add_to_blackwhite($dbh, $username, 'WL', [ $sender ]);
- } elsif ($action eq 'blacklist') {
- PMG::Quarantine::add_to_blackwhite($dbh, $username, 'BL', [ $sender ]);
- } elsif ($action eq 'deliver') {
- my $targets = [ $ref->{pmail} ];
- PMG::Quarantine::deliver_quarantined_mail($dbh, $ref, $targets);
- } elsif ($action eq 'delete') {
- PMG::Quarantine::delete_quarantined_mail($dbh, $ref);
- } else {
- die "internal error"; # should not be reached
+ for my $id (@idlist) {
+ my ($cid, $rid, $tid) = $id =~ m/^C(\d+)R(\d+)T(\d+)$/;
+ $cid = int($cid);
+ $rid = int($rid);
+ $tid = int($tid);
+
+ my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid, $tid);
+
+ if ($role eq 'quser') {
+ my $quar_username = $ref->{pmail} . '@quarantine';
+ raise_perm_exc("mail does not belong to user '$authuser' ($ref->{pmail})")
+ if $authuser ne $quar_username;
+ }
+
+ my $sender = $get_real_sender->($ref);
+
+ if ($action eq 'whitelist') {
+ PMG::Quarantine::add_to_blackwhite($dbh, $ref->{pmail}, 'WL', [ $sender ]);
+ } elsif ($action eq 'blacklist') {
+ PMG::Quarantine::add_to_blackwhite($dbh, $ref->{pmail}, 'BL', [ $sender ]);
+ } elsif ($action eq 'deliver') {
+ PMG::Quarantine::deliver_quarantined_mail($dbh, $ref, $ref->{receiver} // $ref->{pmail});
+ } elsif ($action eq 'delete') {
+ PMG::Quarantine::delete_quarantined_mail($dbh, $ref);
+ } else {
+ die "internal error"; # should not be reached
+ }
}
return undef;