]> git.proxmox.com Git - pmg-api.git/blob - PMG/API2/Quarantine.pm
code cleanup - remove unused var $role
[pmg-api.git] / PMG / API2 / Quarantine.pm
1 package PMG::API2::Quarantine;
2
3 use strict;
4 use warnings;
5 use Time::Local;
6 use Time::Zone;
7 use Data::Dumper;
8 use Encode;
9
10 use Mail::Header;
11
12 use PVE::SafeSyslog;
13 use PVE::Exception qw(raise_param_exc raise_perm_exc);
14 use PVE::Tools qw(extract_param);
15 use PVE::JSONSchema qw(get_standard_option);
16 use PVE::RESTHandler;
17 use PVE::INotify;
18 use PVE::APIServer::Formatter;
19
20 use PMG::Utils;
21 use PMG::AccessControl;
22 use PMG::Config;
23 use PMG::DBTools;
24 use PMG::HTMLMail;
25 use PMG::Quarantine;
26
27 use base qw(PVE::RESTHandler);
28
29 my $spamdesc;
30
31 my $verify_optional_pmail = sub {
32 my ($authuser, $role, $pmail) = @_;
33
34 if ($role eq 'quser') {
35 raise_param_exc({ pmail => "parameter not allwed with role '$role'"})
36 if defined($pmail);
37 $pmail = $authuser;
38 } else {
39 raise_param_exc({ pmail => "parameter required with role '$role'"})
40 if !defined($pmail);
41 }
42 return $pmail;
43 };
44
45 sub 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 }
65
66 my $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
88 my $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
103 my $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')));
118 $res->{sender} = $sender if $sender && ($sender ne $res->{from});
119
120 $res->{envelope_sender} = $ref->{sender};
121 $res->{receiver} = $ref->{receiver} // $ref->{pmail};
122 $res->{id} = 'C' . $ref->{cid} . 'R' . $ref->{rid};
123 $res->{time} = $ref->{time};
124 $res->{bytes} = $ref->{bytes};
125
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;
132 }
133
134 return $res;
135 };
136
137 my $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 };
142
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 = [
165 { name => 'whitelist' },
166 { name => 'blacklist' },
167 { name => 'content' },
168 { name => 'spam' },
169 { name => 'spamusers' },
170 { name => 'virus' },
171 ];
172
173 return $result;
174 }});
175
176
177 my $read_or_modify_user_bw_list = sub {
178 my ($listname, $param, $addrs, $delete) = @_;
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
188 my $list = PMG::Quarantine::add_to_blackwhite(
189 $dbh, $pmail, $listname, $addrs, $delete);
190
191 my $res = [];
192 foreach my $a (@$list) { push @$res, { address => $a }; }
193 return $res;
194 };
195
196 my $address_pattern = '[a-zA-Z0-9\+\-\_\*\.\@]+';
197
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
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;
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
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;
366 }});
367
368 __PACKAGE__->register_method ({
369 name => 'spamusers',
370 path => 'spamusers',
371 method => 'GET',
372 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
373 description => "Get a list of receivers of spam in the given timespan (Default the last 24 hours).",
374 parameters => {
375 additionalProperties => 0,
376 properties => {
377 starttime => {
378 description => "Only consider entries newer than 'starttime' (unix epoch). Default is 'now - 1day'.",
379 type => 'integer',
380 minimum => 0,
381 optional => 1,
382 },
383 endtime => {
384 description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
385 type => 'integer',
386 minimum => 1,
387 optional => 1,
388 },
389 },
390 },
391 returns => {
392 type => 'array',
393 items => {
394 type => "object",
395 properties => {
396 mail => {
397 description => 'the receiving email',
398 type => 'string',
399 },
400 },
401 },
402 },
403 code => sub {
404 my ($param) = @_;
405
406 my $rpcenv = PMG::RESTEnvironment->get();
407 my $authuser = $rpcenv->get_user();
408
409 my $res = [];
410
411 my $dbh = PMG::DBTools::open_ruledb();
412
413 my $start = $param->{starttime} // (time - 86400);
414 my $end = $param->{endtime} // ($start + 86400);
415
416 my $sth = $dbh->prepare(
417 "SELECT DISTINCT pmail " .
418 "FROM CMailStore, CMSReceivers WHERE " .
419 "time >= $start AND time < $end AND " .
420 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
421 "AND Status = 'N' ORDER BY pmail");
422
423 $sth->execute();
424
425 while (my $ref = $sth->fetchrow_hashref()) {
426 push @$res, { mail => $ref->{pmail} };
427 }
428
429 return $res;
430 }});
431
432 __PACKAGE__->register_method ({
433 name => 'quarusers',
434 path => 'quarusers',
435 method => 'GET',
436 permissions => { check => [ 'admin', 'qmanager', 'audit'] },
437 description => "Get a list of users with whitelist/blacklist setttings.",
438 parameters => {
439 additionalProperties => 0,
440 properties => {},
441 },
442 returns => {
443 type => 'array',
444 items => {
445 type => "object",
446 properties => {
447 mail => {
448 description => 'the receiving email',
449 type => 'string',
450 },
451 },
452 },
453 },
454 code => sub {
455 my ($param) = @_;
456
457 my $rpcenv = PMG::RESTEnvironment->get();
458 my $authuser = $rpcenv->get_user();
459
460 my $res = [];
461
462 my $dbh = PMG::DBTools::open_ruledb();
463
464 my $sth = $dbh->prepare(
465 "SELECT DISTINCT pmail FROM UserPrefs ORDER BY pmail");
466
467 $sth->execute();
468
469 while (my $ref = $sth->fetchrow_hashref()) {
470 push @$res, { mail => $ref->{pmail} };
471 }
472
473 return $res;
474 }});
475
476 __PACKAGE__->register_method ({
477 name => 'spam',
478 path => 'spam',
479 method => 'GET',
480 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
481 description => "Get a list of quarantined spam mails in the given timeframe (default the last 24 hours) for the given user.",
482 parameters => {
483 additionalProperties => 0,
484 properties => {
485 starttime => {
486 description => "Only consider entries newer than 'starttime' (unix epoch). This is set to 'now - 1day' by default.",
487 type => 'integer',
488 minimum => 0,
489 optional => 1,
490 },
491 endtime => {
492 description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
493 type => 'integer',
494 minimum => 1,
495 optional => 1,
496 },
497 pmail => $pmail_param_type,
498 },
499 },
500 returns => {
501 type => 'array',
502 items => {
503 type => "object",
504 properties => {
505 id => {
506 description => 'Unique ID',
507 type => 'string',
508 },
509 bytes => {
510 description => "Size of raw email.",
511 type => 'integer' ,
512 },
513 envelope_sender => {
514 description => "SMTP envelope sender.",
515 type => 'string',
516 },
517 from => {
518 description => "Header 'From' field.",
519 type => 'string',
520 },
521 sender => {
522 description => "Header 'Sender' field.",
523 type => 'string',
524 optional => 1,
525 },
526 receiver => {
527 description => "Receiver email address",
528 type => 'string',
529 },
530 subject => {
531 description => "Header 'Subject' field.",
532 type => 'string',
533 },
534 time => {
535 description => "Receive time stamp",
536 type => 'integer',
537 },
538 spamlevel => {
539 description => "Spam score.",
540 type => 'number',
541 },
542 },
543 },
544 },
545 code => sub {
546 my ($param) = @_;
547
548 my $rpcenv = PMG::RESTEnvironment->get();
549 my $authuser = $rpcenv->get_user();
550 my $role = $rpcenv->get_role();
551
552 my $pmail = $verify_optional_pmail->($authuser, $role, $param->{pmail});
553
554 my $res = [];
555
556 my $dbh = PMG::DBTools::open_ruledb();
557
558 my $start = $param->{starttime} // (time - 86400);
559 my $end = $param->{endtime} // ($start + 86400);
560
561 my $sth = $dbh->prepare(
562 "SELECT * " .
563 "FROM CMailStore, CMSReceivers WHERE " .
564 "pmail = ? AND time >= $start AND time < $end AND " .
565 "QType = 'S' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
566 "AND Status = 'N' ORDER BY pmail, time, receiver");
567
568 $sth->execute($pmail);
569
570 while (my $ref = $sth->fetchrow_hashref()) {
571 my $data = $parse_header_info->($ref);
572 push @$res, $data;
573 }
574
575 return $res;
576 }});
577
578 __PACKAGE__->register_method ({
579 name => 'virus',
580 path => 'virus',
581 method => 'GET',
582 permissions => { check => [ 'admin', 'qmanager', 'audit' ] },
583 description => "Get a list of quarantined virus mails in the given timeframe (default the last 24 hours).",
584 parameters => {
585 additionalProperties => 0,
586 properties => {
587 starttime => {
588 description => "Only consider entries newer than 'starttime' (unix epoch). This is set to 'now - 1day' by default.",
589 type => 'integer',
590 minimum => 0,
591 optional => 1,
592 },
593 endtime => {
594 description => "Only consider entries older than 'endtime' (unix epoch). This is set to '<start> + 1day' by default.",
595 type => 'integer',
596 minimum => 1,
597 optional => 1,
598 },
599 },
600 },
601 returns => {
602 type => 'array',
603 items => {
604 type => "object",
605 properties => {
606 id => {
607 description => 'Unique ID',
608 type => 'string',
609 },
610 bytes => {
611 description => "Size of raw email.",
612 type => 'integer' ,
613 },
614 envelope_sender => {
615 description => "SMTP envelope sender.",
616 type => 'string',
617 },
618 from => {
619 description => "Header 'From' field.",
620 type => 'string',
621 },
622 sender => {
623 description => "Header 'Sender' field.",
624 type => 'string',
625 optional => 1,
626 },
627 receiver => {
628 description => "Receiver email address",
629 type => 'string',
630 },
631 subject => {
632 description => "Header 'Subject' field.",
633 type => 'string',
634 },
635 time => {
636 description => "Receive time stamp",
637 type => 'integer',
638 },
639 virusname => {
640 description => "Virus name.",
641 type => 'string',
642 },
643 },
644 },
645 },
646 code => sub {
647 my ($param) = @_;
648
649 my $rpcenv = PMG::RESTEnvironment->get();
650 my $authuser = $rpcenv->get_user();
651
652 my $res = [];
653
654 my $dbh = PMG::DBTools::open_ruledb();
655
656 my $start = $param->{starttime} // (time - 86400);
657 my $end = $param->{endtime} // ($start + 86400);
658
659 my $sth = $dbh->prepare(
660 "SELECT * " .
661 "FROM CMailStore, CMSReceivers WHERE " .
662 "time >= $start AND time < $end AND " .
663 "QType = 'V' AND CID = CMailStore_CID AND RID = CMailStore_RID " .
664 "AND Status = 'N' ORDER BY time, receiver");
665
666 $sth->execute();
667
668 while (my $ref = $sth->fetchrow_hashref()) {
669 my $data = $parse_header_info->($ref);
670 push @$res, $data;
671 }
672
673 return $res;
674 }});
675
676 __PACKAGE__->register_method ({
677 name => 'content',
678 path => 'content',
679 method => 'GET',
680 permissions => { check => [ 'admin', 'qmanager', 'audit', 'quser'] },
681 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).",
682 parameters => {
683 additionalProperties => 0,
684 properties => {
685 id => {
686 description => 'Unique ID',
687 type => 'string',
688 pattern => 'C\d+R\d+',
689 maxLength => 40,
690 },
691 raw => {
692 description => "Display 'raw' eml data. This is only used with the 'htmlmail' formatter.",
693 type => 'boolean',
694 optional => 1,
695 default => 0,
696 },
697 },
698 },
699 returns => {
700 type => "object",
701 properties => {
702 id => {
703 description => 'Unique ID',
704 type => 'string',
705 },
706 bytes => {
707 description => "Size of raw email.",
708 type => 'integer' ,
709 },
710 envelope_sender => {
711 description => "SMTP envelope sender.",
712 type => 'string',
713 },
714 from => {
715 description => "Header 'From' field.",
716 type => 'string',
717 },
718 sender => {
719 description => "Header 'Sender' field.",
720 type => 'string',
721 optional => 1,
722 },
723 receiver => {
724 description => "Receiver email address",
725 type => 'string',
726 },
727 subject => {
728 description => "Header 'Subject' field.",
729 type => 'string',
730 },
731 time => {
732 description => "Receive time stamp",
733 type => 'integer',
734 },
735 spamlevel => {
736 description => "Spam score.",
737 type => 'number',
738 },
739 spaminfo => {
740 description => "Information about matched spam tests (name, score, desc, url).",
741 type => 'array',
742 },
743 header => {
744 description => "Raw email header data.",
745 type => 'string',
746 },
747 content => {
748 description => "Raw email data (first 4096 bytes). Useful for preview. NOTE: The 'htmlmail' formatter displays the whole email.",
749 type => 'string',
750 },
751 },
752 },
753 code => sub {
754 my ($param) = @_;
755
756 my $rpcenv = PMG::RESTEnvironment->get();
757 my $authuser = $rpcenv->get_user();
758 my $role = $rpcenv->get_role();
759 my $format = $rpcenv->get_format();
760
761 my ($cid, $rid) = $param->{id} =~ m/^C(\d+)R(\d+)$/;
762 $cid = int($cid);
763 $rid = int($rid);
764
765 my $dbh = PMG::DBTools::open_ruledb();
766
767 my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid);
768
769 if ($role eq 'quser') {
770 raise_perm_exc("mail does not belong to user '$authuser'")
771 if $authuser ne $ref->{pmail};
772 }
773
774 my $res = $parse_header_info->($ref);
775
776
777 my $filename = $ref->{file};
778 my $spooldir = $PMG::MailQueue::spooldir;
779
780 my $path = "$spooldir/$filename";
781
782 if ($format eq 'htmlmail') {
783
784 my $cfg = PMG::Config->new();
785 my $viewimages = $cfg->get('spamquar', 'viewimages');
786 my $allowhref = $cfg->get('spamquar', 'allowhrefs');
787
788 $res->{content} = PMG::HTMLMail::email_to_html($path, $param->{raw}, $viewimages, $allowhref);
789
790 # to make result verification happy
791 $res->{file} = '';
792 $res->{header} = '';
793 $res->{spaminfo} = [];
794 } else {
795 # include additional details
796
797 my ($header, $content) = PMG::HTMLMail::read_raw_email($path, 4096);
798
799 $res->{file} = $ref->{file};
800 $res->{spaminfo} = decode_spaminfo($ref->{info});
801 $res->{header} = $header;
802 $res->{content} = $content;
803 }
804
805
806 return $res;
807
808 }});
809
810 PVE::APIServer::Formatter::register_page_formatter(
811 'format' => 'htmlmail',
812 method => 'GET',
813 path => '/quarantine/content',
814 code => sub {
815 my ($res, $data, $param, $path, $auth, $config) = @_;
816
817 if(!HTTP::Status::is_success($res->{status})) {
818 return ("Error $res->{status}: $res->{message}", "text/plain");
819 }
820
821 my $ct = "text/html;charset=UTF-8";
822
823 my $raw = $data->{content};
824
825 return (encode('UTF-8', $raw), $ct, 1);
826 });
827
828 __PACKAGE__->register_method ({
829 name =>'action',
830 path => 'content',
831 method => 'POST',
832 description => "Execute quarantine actions.",
833 permissions => { check => [ 'admin', 'qmanager', 'quser'] },
834 protected => 1,
835 parameters => {
836 additionalProperties => 0,
837 properties => {
838 id => {
839 description => 'Unique ID',
840 type => 'string',
841 pattern => 'C\d+R\d+',
842 maxLength => 40,
843 },
844 action => {
845 description => 'Action - specify what you want to do with the mail.',
846 type => 'string',
847 enum => ['whitelist', 'blacklist', 'deliver', 'delete'],
848 },
849 },
850 },
851 returns => { type => "null" },
852 code => sub {
853 my ($param) = @_;
854
855 my $rpcenv = PMG::RESTEnvironment->get();
856 my $authuser = $rpcenv->get_user();
857 my $role = $rpcenv->get_role();
858 my $action = $param->{action};
859
860 my ($cid, $rid) = $param->{id} =~ m/^C(\d+)R(\d+)$/;
861 $cid = int($cid);
862 $rid = int($rid);
863
864 my $dbh = PMG::DBTools::open_ruledb();
865
866 my $ref = PMG::DBTools::load_mail_data($dbh, $cid, $rid);
867
868 if ($role eq 'quser') {
869 raise_perm_exc("mail does not belong to user '$authuser'")
870 if $authuser ne $ref->{pmail};
871 }
872
873 my $sender = $get_real_sender->($ref);
874 my $username = $ref->{pmail};
875
876 if ($action eq 'whitelist') {
877 PMG::Quarantine::add_to_blackwhite($dbh, $username, 'WL', [ $sender ]);
878 } elsif ($action eq 'blacklist') {
879 PMG::Quarantine::add_to_blackwhite($dbh, $username, 'BL', [ $sender ]);
880 } elsif ($action eq 'deliver') {
881 my $targets = [ $ref->{pmail} ];
882 PMG::Quarantine::deliver_quarantined_mail($dbh, $ref, $targets);
883 } elsif ($action eq 'delete') {
884 PMG::Quarantine::delete_quarantined_mail($dbh, $ref);
885 } else {
886 die "internal error"; # should not be reached
887 }
888
889 return undef;
890 }});
891
892 1;