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