]> git.proxmox.com Git - pmg-api.git/blobdiff - PMG/API2/Quarantine.pm
add optional list parameter to quarusers api call
[pmg-api.git] / PMG / API2 / Quarantine.pm
index 49d9fe335c3c72d06a113d47aa0473ac4da644da..158247b14dc7303eab38b3738188189599675554 100644 (file)
@@ -8,6 +8,7 @@ use Data::Dumper;
 use Encode;
 
 use Mail::Header;
+use Mail::SpamAssassin;
 
 use PVE::SafeSyslog;
 use PVE::Exception qw(raise_param_exc raise_perm_exc);
@@ -28,16 +29,27 @@ use base qw(PVE::RESTHandler);
 
 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;
 };
@@ -45,14 +57,18 @@ my $verify_optional_pmail = sub {
 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});
@@ -119,7 +135,7 @@ my $parse_header_info = sub {
 
     $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};
 
@@ -127,6 +143,7 @@ my $parse_header_info = sub {
 
     if ($qtype eq 'V') {
        $res->{virusname} = $ref->{info};
+       $res->{spamlevel} = 0;
     } elsif ($qtype eq 'S') {
        $res->{spamlevel} = $ref->{spamlevel} // 0;
     }
@@ -167,7 +184,9 @@ __PACKAGE__->register_method ({
            { name => 'content' },
            { name => 'spam' },
            { name => 'spamusers' },
+           { name => 'spamstatus' },
            { name => 'virus' },
+           { name => 'virusstatus' },
            { name => 'quarusers' },
        ];
 
@@ -194,8 +213,6 @@ my $read_or_modify_user_bw_list = sub {
     return $res;
 };
 
-my $address_pattern = '[a-zA-Z0-9\+\-\_\*\.\@]+';
-
 __PACKAGE__->register_method ({
     name => 'whitelist',
     path => 'whitelist',
@@ -236,19 +253,17 @@ __PACKAGE__->register_method ({
        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;
     }});
@@ -264,19 +279,17 @@ __PACKAGE__->register_method ({
        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;
     }});
@@ -321,19 +334,17 @@ __PACKAGE__->register_method ({
        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;
     }});
@@ -349,19 +360,17 @@ __PACKAGE__->register_method ({
        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;
     }});
@@ -375,18 +384,8 @@ __PACKAGE__->register_method ({
     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 => {
@@ -430,6 +429,46 @@ __PACKAGE__->register_method ({
        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',
@@ -438,7 +477,14 @@ __PACKAGE__->register_method ({
     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',
@@ -462,10 +508,14 @@ __PACKAGE__->register_method ({
 
        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} };
@@ -483,18 +533,8 @@ __PACKAGE__->register_method ({
     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,
        },
     },
@@ -585,18 +625,8 @@ __PACKAGE__->register_method ({
     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 => {
@@ -674,6 +704,44 @@ __PACKAGE__->register_method ({
        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',
@@ -686,11 +754,11 @@ __PACKAGE__->register_method ({
            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,
@@ -759,22 +827,25 @@ __PACKAGE__->register_method ({
        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;
 
@@ -786,16 +857,20 @@ __PACKAGE__->register_method ({
            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});
@@ -837,10 +912,9 @@ __PACKAGE__->register_method ({
        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.',
@@ -857,34 +931,37 @@ __PACKAGE__->register_method ({
        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;