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