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