]> git.proxmox.com Git - pmg-api.git/blame - PMG/API2/Quarantine.pm
add spamusers api call
[pmg-api.git] / PMG / API2 / Quarantine.pm
CommitLineData
b66faa68
DM
1package PMG::API2::Quarantine;
2
3use strict;
4use warnings;
5use Time::Local;
6use Time::Zone;
7use Data::Dumper;
34db0c3f 8use Encode;
b66faa68 9
34db0c3f 10use Mail::Header;
dae021a8 11
b66faa68 12use PVE::SafeSyslog;
6e8886d4 13use PVE::Exception qw(raise_param_exc raise_perm_exc);
b66faa68
DM
14use PVE::Tools qw(extract_param);
15use PVE::JSONSchema qw(get_standard_option);
16use PVE::RESTHandler;
17use PVE::INotify;
34db0c3f 18use PVE::APIServer::Formatter;
b66faa68 19
dae021a8 20use PMG::Utils;
b66faa68 21use PMG::AccessControl;
34db0c3f 22use PMG::Config;
b66faa68 23use PMG::DBTools;
34db0c3f 24use PMG::HTMLMail;
e84bf942 25use PMG::Quarantine;
b66faa68
DM
26
27use base qw(PVE::RESTHandler);
28
1284c016
DM
29my $spamdesc;
30
157a946b
DM
31my $verify_optional_pmail = sub {
32 my ($authuser, $role, $pmail) = @_;
33
34 if ($role eq 'quser') {
35 raise_param_exc({ pmail => "paramater not allwed with role '$role'"})
36 if defined($pmail);
37 $pmail = $authuser;
38 } else {
39 raise_param_exc({ pmail => "paramater required with role '$role'"})
40 if !defined($pmail);
41 }
42 return $pmail;
43};
44
1284c016
DM
45sub decode_spaminfo {
46 my ($info) = @_;
47
48 $spamdesc = PMG::Utils::load_sa_descriptions() if !$spamdesc;
49
50 my $res = [];
51
52 foreach my $test (split (',', $info)) {
53 my ($name, $score) = split (':', $test);
54
55 my $info = { name => $name, score => $score, desc => '-' };
56 if (my $si = $spamdesc->{$name}) {
57 $info->{desc} = $si->{desc};
58 $info->{url} = $si->{url} if defined($si->{url});
59 }
60 push @$res, $info;
61 }
62
63 return $res;
64}
b66faa68 65
157a946b
DM
66my $extract_email = sub {
67 my $data = shift;
68
69 return $data if !$data;
70
71 if ($data =~ m/^.*\s(\S+)\s*$/) {
72 $data = $1;
73 }
74
75 if ($data =~ m/^<([^<>\s]+)>$/) {
76 $data = $1;
77 }
78
79 if ($data !~ m/[\s><]/ && $data =~ m/^(.+\@[^\.]+\..*[^\.]+)$/) {
80 $data = $1;
81 } else {
82 $data = undef;
83 }
84
85 return $data;
86};
87
88my $get_real_sender = sub {
89 my ($ref) = @_;
90
91 my @lines = split('\n', $ref->{header});
92 my $head = Mail::Header->new(\@lines);
93
94 my @fromarray = split ('\s*,\s*', $head->get ('from') || $ref->{sender});
95 my $from = $extract_email->($fromarray[0]) || $ref->{sender};;
96 my $sender = $extract_email->($head->get ('sender'));
97
98 return $sender if $sender;
99
100 return $from;
101};
102
dae021a8
DM
103my $parse_header_info = sub {
104 my ($ref) = @_;
105
106 my $res = { subject => '', from => '' };
107
108 my @lines = split('\n', $ref->{header});
109 my $head = Mail::Header->new(\@lines);
110
111 $res->{subject} = PMG::Utils::decode_rfc1522(PVE::Tools::trim($head->get('subject'))) // '';
112
113 my @fromarray = split('\s*,\s*', $head->get('from') || $ref->{sender});
114
115 $res->{from} = PMG::Utils::decode_rfc1522(PVE::Tools::trim ($fromarray[0])) // '';
116
117 my $sender = PMG::Utils::decode_rfc1522(PVE::Tools::trim($head->get('sender')));
1284c016 118 $res->{sender} = $sender if $sender && ($sender ne $res->{from});
dae021a8
DM
119
120 $res->{envelope_sender} = $ref->{sender};
e84bf942 121 $res->{receiver} = $ref->{receiver} // $ref->{pmail};
6e8886d4 122 $res->{id} = 'C' . $ref->{cid} . 'R' . $ref->{rid};
dae021a8
DM
123 $res->{time} = $ref->{time};
124 $res->{bytes} = $ref->{bytes};
125
1284c016
DM
126 my $qtype = $ref->{qtype};
127
128 if ($qtype eq 'V') {
129 $res->{virusname} = $ref->{info};
130 } elsif ($qtype eq 'S') {
131 $res->{spamlevel} = $ref->{spamlevel} // 0;
1284c016
DM
132 }
133
dae021a8
DM
134 return $res;
135};
136
157a946b
DM
137my $pmail_param_type = {
138 description => "List entries for the user with this primary email address. Quarantine users cannot speficy this parameter, but it is required for all other roles.",
139 type => 'string', format => 'email',
140 optional => 1,
141};
6e8886d4 142
b66faa68
DM
143__PACKAGE__->register_method ({
144 name => 'index',
145 path => '',
146 method => 'GET',
147 permissions => { user => 'all' },
148 description => "Directory index.",
149 parameters => {
150 additionalProperties => 0,
151 properties => {},
152 },
153 returns => {
154 type => 'array',
155 items => {
156 type => "object",
157 properties => {},
158 },
159 links => [ { rel => 'child', href => "{name}" } ],
160 },
161 code => sub {
162 my ($param) = @_;
163
164 my $result = [
157a946b
DM
165 { name => 'whitelist' },
166 { name => 'blacklist' },
6e8886d4 167 { name => 'content' },
b66faa68 168 { name => 'spam' },
4f41cebc 169 { name => 'spamusers' },
b66faa68
DM
170 { name => 'virus' },
171 ];
172
173 return $result;
174 }});
175
157a946b 176
767657cb
DM
177my $read_or_modify_user_bw_list = sub {
178 my ($listname, $param, $addrs, $delete) = @_;
157a946b
DM
179
180 my $rpcenv = PMG::RESTEnvironment->get();
181 my $authuser = $rpcenv->get_user();
182 my $role = $rpcenv->get_role();
183
184 my $pmail = $verify_optional_pmail->($authuser, $role, $param->{pmail});
185
186 my $dbh = PMG::DBTools::open_ruledb();
187
767657cb
DM
188 my $list = PMG::Quarantine::add_to_blackwhite(
189 $dbh, $pmail, $listname, $addrs, $delete);
157a946b
DM
190
191 my $res = [];
192 foreach my $a (@$list) { push @$res, { address => $a }; }
193 return $res;
194};
195
767657cb
DM
196my $address_pattern = '[a-zA-Z0-9\+\-\_\*\.\@]+';
197
157a946b
DM
198__PACKAGE__->register_method ({
199 name => 'whitelist',
200 path => 'whitelist',
201 method => 'GET',
202 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
203 description => "Show user whitelist.",
204 parameters => {
205 additionalProperties => 0,
206 properties => {
207 pmail => $pmail_param_type,
208 },
209 },
210 returns => {
211 type => 'array',
212 items => {
213 type => "object",
214 properties => {
215 address => {
216 type => "string",
217 },
218 },
219 },
220 },
221 code => sub {
222 my ($param) = @_;
223
767657cb
DM
224 return $read_or_modify_user_bw_list->('WL', $param);
225 }});
226
227__PACKAGE__->register_method ({
228 name => 'whitelist_add',
229 path => 'whitelist',
230 method => 'POST',
231 description => "Add user whitelist entries.",
232 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
233 protected => 1,
234 parameters => {
235 additionalProperties => 0,
236 properties => {
237 pmail => $pmail_param_type,
238 address => {
239 description => "The address you want to add.",
240 type => "string",
241 pattern => $address_pattern,
242 maxLength => 512,
243 },
244 },
245 },
246 returns => { type => 'null' },
247 code => sub {
248 my ($param) = @_;
249
250 $read_or_modify_user_bw_list->('WL', $param, [ $param->{address} ]);
251
252 return undef;
253 }});
254
255__PACKAGE__->register_method ({
256 name => 'whitelist_delete',
257 path => 'whitelist/{address}',
258 method => 'DELETE',
259 description => "Delete user whitelist entries.",
260 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
261 protected => 1,
262 parameters => {
263 additionalProperties => 0,
264 properties => {
265 pmail => $pmail_param_type,
266 address => {
267 description => "The address you want to remove.",
268 type => "string",
269 pattern => $address_pattern,
270 maxLength => 512,
271 },
272 },
273 },
274 returns => { type => 'null' },
275 code => sub {
276 my ($param) = @_;
277
278 $read_or_modify_user_bw_list->('WL', $param, [ $param->{address} ], 1);
279
280 return undef;
157a946b
DM
281 }});
282
283__PACKAGE__->register_method ({
284 name => 'blacklist',
285 path => 'blacklist',
286 method => 'GET',
287 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
288 description => "Show user blacklist.",
289 parameters => {
290 additionalProperties => 0,
291 properties => {
292 pmail => $pmail_param_type,
293 },
294 },
295 returns => {
296 type => 'array',
297 items => {
298 type => "object",
299 properties => {
300 address => {
301 type => "string",
302 },
303 },
304 },
305 },
306 code => sub {
307 my ($param) = @_;
308
767657cb
DM
309 return $read_or_modify_user_bw_list->('BL', $param);
310 }});
311
312__PACKAGE__->register_method ({
313 name => 'blacklist_add',
314 path => 'blacklist',
315 method => 'POST',
316 description => "Add user blacklist entries.",
317 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
318 protected => 1,
319 parameters => {
320 additionalProperties => 0,
321 properties => {
322 pmail => $pmail_param_type,
323 address => {
324 description => "The address you want to add.",
325 type => "string",
326 pattern => $address_pattern,
327 maxLength => 512,
328 },
329 },
330 },
331 returns => { type => 'null' },
332 code => sub {
333 my ($param) = @_;
334
335 $read_or_modify_user_bw_list->('BL', $param, [ $param->{address} ]);
336
337 return undef;
338 }});
339
340__PACKAGE__->register_method ({
341 name => 'blacklist_delete',
342 path => 'blacklist/{address}',
343 method => 'DELETE',
344 description => "Delete user blacklist entries.",
345 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
346 protected => 1,
347 parameters => {
348 additionalProperties => 0,
349 properties => {
350 pmail => $pmail_param_type,
351 address => {
352 description => "The address you want to remove.",
353 type => "string",
354 pattern => $address_pattern,
355 maxLength => 512,
356 },
357 },
358 },
359 returns => { type => 'null' },
360 code => sub {
361 my ($param) = @_;
362
363 $read_or_modify_user_bw_list->('BL', $param, [ $param->{address} ], 1);
364
365 return undef;
157a946b
DM
366 }});
367
b66faa68
DM
368__PACKAGE__->register_method ({
369 name => 'spam',
370 path => 'spam',
371 method => 'GET',
372 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
373 description => "Show spam mails distribution (per day).",
374 parameters => {
375 additionalProperties => 0,
376 properties => {
377 starttime => {
378 description => "Only consider entries newer than 'startime' (unix epoch).",
379 type => 'integer',
380 minimum => 0,
381 optional => 1,
382 },
383 endtime => {
384 description => "Only consider entries older than 'endtime' (unix epoch).",
385 type => 'integer',
386 minimum => 1,
387 optional => 1,
388 },
157a946b 389 pmail => $pmail_param_type,
b66faa68
DM
390 },
391 },
392 returns => {
393 type => 'array',
394 items => {
395 type => "object",
396 properties => {
397 day => {
398 description => "Day (as unix epoch).",
399 type => 'integer',
400 },
bc1ebe25 401 count => {
b66faa68
DM
402 description => "Number of quarantine entries.",
403 type => 'integer',
404 },
405 spamavg => {
406 description => "Average spam level.",
407 type => 'number',
bc1ebe25 408 },
b66faa68
DM
409 },
410 },
ded33c7c 411 links => [ { rel => 'child', href => "{day}" } ],
b66faa68
DM
412 },
413 code => sub {
414 my ($param) = @_;
415
416 my $rpcenv = PMG::RESTEnvironment->get();
417 my $authuser = $rpcenv->get_user();
418 my $role = $rpcenv->get_role();
419
157a946b 420 my $pmail = $verify_optional_pmail->($authuser, $role, $param->{pmail});
b66faa68
DM
421
422 my $res = [];
bc1ebe25 423
b66faa68
DM
424 my $dbh = PMG::DBTools::open_ruledb();
425
ec7035c2 426 my $start = $param->{starttime};
b66faa68
DM
427 my $end = $param->{endtime};
428
429 my $timezone = tz_local_offset();
430
431 my $sth = $dbh->prepare(
432 "SELECT " .
433 "((time + $timezone) / 86400) * 86400 - $timezone as day, " .
434 "count (ID) as count, avg (Spamlevel) as spamavg " .
435 "FROM CMailStore, CMSReceivers WHERE " .
ec7035c2
DM
436 (defined($start) ? "time >= $start AND " : '') .
437 (defined($end) ? "time < $end AND " : '') .
ded33c7c 438 "pmail = ? AND " .
b66faa68
DM
439 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
440 "AND Status = 'N' " .
441 "GROUP BY day " .
442 "ORDER BY day DESC");
443
ded33c7c
DM
444 $sth->execute($pmail);
445
446 while (my $ref = $sth->fetchrow_hashref()) {
447 push @$res, $ref;
448 }
449
450 return $res;
451 }});
452
4f41cebc
DC
453__PACKAGE__->register_method ({
454 name => 'spamusers',
455 path => 'spamusers',
456 method => 'GET',
457 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
458 description => "Get a list of receivers of spam in the given timespan (Default the last 24 hours).",
459 parameters => {
460 additionalProperties => 0,
461 properties => {
462 starttime => {
463 description => "Only consider entries newer than 'starttime' (unix epoch). Default is 'now - 1day'.",
464 type => 'integer',
465 minimum => 0,
466 optional => 1,
467 },
468 endtime => {
469 description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
470 type => 'integer',
471 minimum => 1,
472 optional => 1,
473 },
474 },
475 },
476 returns => {
477 type => 'array',
478 items => {
479 type => "object",
480 properties => {
481 mail => {
482 description => 'the receiving email',
483 type => 'string',
484 },
485 },
486 },
487 },
488 code => sub {
489 my ($param) = @_;
490
491 my $rpcenv = PMG::RESTEnvironment->get();
492 my $authuser = $rpcenv->get_user();
493 my $role = $rpcenv->get_role();
494
495 my $res = [];
496
497 my $dbh = PMG::DBTools::open_ruledb();
498
499 my $start = $param->{starttime} // (time - 86400);
500 my $end = $param->{endtime} // ($start + 86400);
501
502 my $sth = $dbh->prepare(
503 "SELECT DISTINCT pmail " .
504 "FROM CMailStore, CMSReceivers WHERE " .
505 "time >= $start AND time < $end AND " .
506 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
507 "AND Status = 'N' ORDER BY pmail");
508
509 $sth->execute();
510
511 while (my $ref = $sth->fetchrow_hashref()) {
512 push @$res, { mail => $ref->{pmail} };
513 }
514
515 return $res;
516 }});
517
ded33c7c
DM
518__PACKAGE__->register_method ({
519 name => 'spamlist',
520 path => 'spam/{starttime}',
521 method => 'GET',
522 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
523 description => "Show spam mails distribution (per day).",
524 parameters => {
525 additionalProperties => 0,
526 properties => {
527 starttime => {
528 description => "Only consider entries newer than 'starttime' (unix epoch).",
529 type => 'integer',
530 minimum => 0,
531 },
532 endtime => {
533 description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
534 type => 'integer',
535 minimum => 1,
536 optional => 1,
537 },
157a946b 538 pmail => $pmail_param_type,
ded33c7c
DM
539 },
540 },
541 returns => {
542 type => 'array',
543 items => {
544 type => "object",
dae021a8
DM
545 properties => {
546 id => {
547 description => 'Unique ID',
548 type => 'string',
549 },
550 bytes => {
551 description => "Size of raw email.",
552 type => 'integer' ,
553 },
554 envelope_sender => {
555 description => "SMTP envelope sender.",
556 type => 'string',
557 },
558 from => {
559 description => "Header 'From' field.",
560 type => 'string',
561 },
562 sender => {
563 description => "Header 'Sender' field.",
564 type => 'string',
565 optional => 1,
566 },
567 receiver => {
568 description => "Receiver email address",
569 type => 'string',
570 },
571 subject => {
572 description => "Header 'Subject' field.",
573 type => 'string',
574 },
575 time => {
576 description => "Receive time stamp",
577 type => 'integer',
578 },
1284c016
DM
579 spamlevel => {
580 description => "Spam score.",
581 type => 'number',
582 },
dae021a8 583 },
ded33c7c
DM
584 },
585 },
586 code => sub {
587 my ($param) = @_;
588
589 my $rpcenv = PMG::RESTEnvironment->get();
590 my $authuser = $rpcenv->get_user();
591 my $role = $rpcenv->get_role();
592
157a946b 593 my $pmail = $verify_optional_pmail->($authuser, $role, $param->{pmail});
b66faa68 594
ded33c7c
DM
595 my $res = [];
596
597 my $dbh = PMG::DBTools::open_ruledb();
598
599 my $start = $param->{starttime};
600 my $end = $param->{endtime} // ($start + 86400);
601
602 my $sth = $dbh->prepare(
603 "SELECT * " .
604 "FROM CMailStore, CMSReceivers WHERE " .
605 "pmail = ? AND time >= $start AND time < $end AND " .
606 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
607 "AND Status = 'N' ORDER BY pmail, time, receiver");
608
609 $sth->execute($pmail);
610
b66faa68 611 while (my $ref = $sth->fetchrow_hashref()) {
dae021a8
DM
612 my $data = $parse_header_info->($ref);
613 push @$res, $data;
b66faa68
DM
614 }
615
616 return $res;
617 }});
618
6e8886d4
DM
619__PACKAGE__->register_method ({
620 name => 'content',
621 path => 'content',
622 method => 'GET',
623 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
34db0c3f 624 description => "Get email data. There is a special formatter called 'htmlmail' to get sanitized html view of the mail content (use the '/api2/htmlmail/quarantine/content' url).",
6e8886d4
DM
625 parameters => {
626 additionalProperties => 0,
627 properties => {
628 id => {
629 description => 'Unique ID',
630 type => 'string',
631 pattern => 'C\d+R\d+',
632 maxLength => 40,
633 },
34db0c3f
DM
634 raw => {
635 description => "Display 'raw' eml data. This is only used with the 'htmlmail' formatter.",
636 type => 'boolean',
637 optional => 1,
638 default => 0,
639 },
6e8886d4
DM
640 },
641 },
642 returns => {
643 type => "object",
cd31bb45
DM
644 properties => {
645 id => {
646 description => 'Unique ID',
647 type => 'string',
648 },
649 bytes => {
650 description => "Size of raw email.",
651 type => 'integer' ,
652 },
653 envelope_sender => {
654 description => "SMTP envelope sender.",
655 type => 'string',
656 },
657 from => {
658 description => "Header 'From' field.",
659 type => 'string',
660 },
661 sender => {
662 description => "Header 'Sender' field.",
663 type => 'string',
664 optional => 1,
665 },
666 receiver => {
667 description => "Receiver email address",
668 type => 'string',
669 },
670 subject => {
671 description => "Header 'Subject' field.",
672 type => 'string',
673 },
674 time => {
675 description => "Receive time stamp",
676 type => 'integer',
677 },
678 spamlevel => {
679 description => "Spam score.",
680 type => 'number',
681 },
682 spaminfo => {
683 description => "Information about matched spam tests (name, score, desc, url).",
684 type => 'array',
685 },
686 header => {
687 description => "Raw email header data.",
688 type => 'string',
689 },
690 content => {
691 description => "Raw email data (first 4096 bytes). Useful for preview. NOTE: The 'htmlmail' formatter displays the whole email.",
692 type => 'string',
6eac8473 693 },
cd31bb45 694 },
6e8886d4
DM
695 },
696 code => sub {
697 my ($param) = @_;
698
699 my $rpcenv = PMG::RESTEnvironment->get();
700 my $authuser = $rpcenv->get_user();
701 my $role = $rpcenv->get_role();
34db0c3f 702 my $format = $rpcenv->get_format();
6e8886d4
DM
703
704 my ($cid, $rid) = $param->{id} =~ m/^C(\d+)R(\d+)$/;
705 $cid = int($cid);
706 $rid = int($rid);
707
708 my $dbh = PMG::DBTools::open_ruledb();
709
710 my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid);
711
712 if ($role eq 'quser') {
713 raise_perm_exc("mail does not belong to user '$authuser'")
714 if $authuser ne $ref->{pmail};
715 }
716
717 my $res = $parse_header_info->($ref);
718
6e8886d4
DM
719
720 my $filename = $ref->{file};
721 my $spooldir = $PMG::MailQueue::spooldir;
722
723 my $path = "$spooldir/$filename";
724
34db0c3f
DM
725 if ($format eq 'htmlmail') {
726
727 my $cfg = PMG::Config->new();
728 my $viewimages = $cfg->get('spamquar', 'viewimages');
729 my $allowhref = $cfg->get('spamquar', 'allowhrefs');
730
34db0c3f
DM
731 $res->{content} = PMG::HTMLMail::email_to_html($path, $param->{raw}, $viewimages, $allowhref);
732
157a946b
DM
733 # to make result verification happy
734 $res->{file} = '';
735 $res->{header} = '';
736 $res->{spaminfo} = [];
34db0c3f 737 } else {
cd31bb45 738 # include additional details
34db0c3f 739
cd31bb45 740 my ($header, $content) = PMG::HTMLMail::read_raw_email($path, 4096);
157a946b 741
cd31bb45
DM
742 $res->{file} = $ref->{file};
743 $res->{spaminfo} = decode_spaminfo($ref->{info});
34db0c3f
DM
744 $res->{header} = $header;
745 $res->{content} = $content;
746 }
6e8886d4 747
6e8886d4
DM
748
749 return $res;
750
751 }});
752
34db0c3f
DM
753PVE::APIServer::Formatter::register_page_formatter(
754 'format' => 'htmlmail',
755 method => 'GET',
756 path => '/quarantine/content',
757 code => sub {
758 my ($res, $data, $param, $path, $auth, $config) = @_;
759
760 if(!HTTP::Status::is_success($res->{status})) {
761 return ("Error $res->{status}: $res->{message}", "text/plain");
762 }
763
764 my $ct = "text/html;charset=UTF-8";
765
766 my $raw = $data->{content};
767
768 return (encode('UTF-8', $raw), $ct, 1);
769});
770
157a946b
DM
771__PACKAGE__->register_method ({
772 name =>'action',
773 path => 'content',
774 method => 'POST',
775 description => "Execute quarantine actions.",
776 permissions => { check => [ 'admin', 'qmanager', 'quser'] },
777 protected => 1,
778 parameters => {
779 additionalProperties => 0,
780 properties => {
781 id => {
782 description => 'Unique ID',
783 type => 'string',
784 pattern => 'C\d+R\d+',
785 maxLength => 40,
786 },
787 action => {
788 description => 'Action - specify what you want to do with the mail.',
789 type => 'string',
790 enum => ['whitelist', 'blacklist', 'deliver', 'delete'],
791 },
792 },
793 },
794 returns => { type => "null" },
795 code => sub {
796 my ($param) = @_;
797
798 my $rpcenv = PMG::RESTEnvironment->get();
799 my $authuser = $rpcenv->get_user();
800 my $role = $rpcenv->get_role();
801 my $action = $param->{action};
802
803 my ($cid, $rid) = $param->{id} =~ m/^C(\d+)R(\d+)$/;
804 $cid = int($cid);
805 $rid = int($rid);
806
807 my $dbh = PMG::DBTools::open_ruledb();
808
809 my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid);
810
811 if ($role eq 'quser') {
812 raise_perm_exc("mail does not belong to user '$authuser'")
813 if $authuser ne $ref->{pmail};
814 }
815
816 my $sender = $get_real_sender->($ref);
817 my $username = $ref->{pmail};
818
819 if ($action eq 'whitelist') {
e84bf942 820 PMG::Quarantine::add_to_blackwhite($dbh, $username, 'WL', [ $sender ]);
157a946b 821 } elsif ($action eq 'blacklist') {
e84bf942 822 PMG::Quarantine::add_to_blackwhite($dbh, $username, 'BL', [ $sender ]);
157a946b 823 } elsif ($action eq 'deliver') {
e84bf942
DM
824 my $targets = [ $ref->{pmail} ];
825 PMG::Quarantine::deliver_quarantined_mail($dbh, $ref, $targets);
157a946b 826 } elsif ($action eq 'delete') {
e84bf942
DM
827 PMG::Quarantine::delete_quarantined_mail($dbh, $ref);
828 } else {
829 die "internal error"; # should not be reached
157a946b
DM
830 }
831
832 return undef;
833 }});
e84bf942 834
b66faa68 8351;