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