]>
Commit | Line | Data |
---|---|---|
758c7b6b DM |
1 | package PMG::RuleDB::Remove; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
758c7b6b DM |
5 | use DBI; |
6 | use Digest::SHA; | |
7 | use MIME::Words; | |
8 | use MIME::Entity; | |
9 | use Encode; | |
10 | ||
11 | use PVE::SafeSyslog; | |
12 | ||
13 | use PMG::Utils; | |
14 | use PMG::ModGroup; | |
15 | use PMG::RuleDB::Object; | |
16 | ||
17 | use base qw(PMG::RuleDB::Object); | |
18 | ||
19 | sub otype { | |
20 | return 4007; | |
21 | } | |
22 | ||
23 | sub otype_text { | |
24 | return 'Remove attachments'; | |
25 | } | |
26 | ||
27 | sub oclass { | |
28 | return 'action'; | |
29 | } | |
30 | ||
758c7b6b DM |
31 | sub oisedit { |
32 | return 1; | |
33 | } | |
34 | ||
35 | sub final { | |
36 | return 0; | |
37 | } | |
38 | ||
39 | sub priority { | |
40 | return 40; | |
41 | } | |
42 | ||
43 | sub new { | |
44 | my ($type, $all, $text, $ogroup) = @_; | |
45 | ||
46 | my $class = ref($type) || $type; | |
47 | ||
48 | $all = 0 if !defined ($all); | |
49 | ||
7a2cf7e6 | 50 | my $self = $class->SUPER::new($class->otype(), $ogroup); |
758c7b6b DM |
51 | |
52 | $self->{all} = $all; | |
53 | $self->{text} = $text; | |
54 | ||
55 | return $self; | |
56 | } | |
57 | ||
58 | sub load_attr { | |
59 | my ($type, $ruledb, $id, $ogroup, $value) = @_; | |
60 | ||
61 | my $class = ref($type) || $type; | |
62 | ||
9ef3f143 | 63 | defined ($value) || die "undefined value: ERROR"; |
758c7b6b DM |
64 | |
65 | my $obj; | |
66 | ||
67 | if ($value =~ m/^([01])(\:(.*))?$/s) { | |
68 | $obj = $class->new($1, $3, $ogroup); | |
69 | } else { | |
70 | $obj = $class->new(0, undef, $ogroup); | |
71 | } | |
72 | ||
73 | $obj->{id} = $id; | |
74 | ||
75 | $obj->{digest} = Digest::SHA::sha1_hex($id, $value, $ogroup); | |
76 | ||
77 | return $obj; | |
78 | } | |
79 | ||
80 | sub save { | |
81 | my ($self, $ruledb) = @_; | |
82 | ||
9ef3f143 | 83 | defined($self->{ogroup}) || die "undefined ogroup: ERROR"; |
758c7b6b DM |
84 | |
85 | my $value = $self->{all} ? '1' : '0'; | |
86 | ||
87 | if ($self->{text}) { | |
88 | $value .= ":$self->{text}"; | |
89 | } | |
90 | ||
91 | if (defined ($self->{id})) { | |
92 | # update | |
93 | ||
94 | $ruledb->{dbh}->do( | |
95 | "UPDATE Object SET Value = ? WHERE ID = ?", | |
96 | undef, $value, $self->{id}); | |
97 | ||
98 | } else { | |
99 | # insert | |
100 | ||
101 | my $sth = $ruledb->{dbh}->prepare( | |
102 | "INSERT INTO Object (Objectgroup_ID, ObjectType, Value) " . | |
103 | "VALUES (?, ?, ?);"); | |
104 | ||
105 | $sth->execute($self->ogroup, $self->otype, $value); | |
106 | ||
107 | $self->{id} = PMG::Utils::lastid($ruledb->{dbh}, 'object_id_seq'); | |
108 | } | |
109 | ||
110 | return $self->{id}; | |
111 | } | |
112 | ||
113 | sub delete_marked_parts { | |
365d5b95 | 114 | my ($self, $queue, $entity, $html, $rtype, $marks, $rulename) = @_; |
758c7b6b DM |
115 | |
116 | my $nparts = []; | |
117 | ||
118 | my $pn = $entity->parts; | |
119 | for (my $i = 0; $i < $pn; $i++) { | |
120 | my $part = $entity->parts($i); | |
121 | ||
122 | my ($id, $found); | |
123 | ||
124 | if ($id = $part->head->mime_attr('x-proxmox-tmp-aid')) { | |
125 | chomp $id; | |
126 | ||
127 | if ($self->{all}) { | |
128 | my $ctype_part = $part->head->mime_type; | |
129 | if (!($i == 0 && $ctype_part =~ m|text/.*|i)) { | |
130 | $found = 1; | |
131 | } | |
132 | } else { | |
133 | foreach my $m (@$marks) { | |
134 | $found = 1 if $m eq $id; | |
135 | } | |
136 | } | |
137 | ||
138 | } | |
139 | ||
140 | if ($found) { | |
141 | ||
142 | my $on = PMG::Utils::extract_filename($part->head) || ''; | |
143 | ||
144 | my $text = PMG::Utils::subst_values($html, { FILENAME => $on } ); | |
145 | ||
146 | my $fname = "REMOVED_ATTACHMENT_$id." . ($rtype eq "text/html" ? "html" : "txt"); | |
147 | ||
148 | my $ent = MIME::Entity->build( | |
149 | Type => $rtype, | |
150 | Charset => 'UTF-8', | |
151 | Encoding => "quoted-printable", | |
152 | Filename => $fname, | |
153 | Disposition => "attachment", | |
154 | Data => encode('UTF-8', $text)); | |
155 | ||
156 | push (@$nparts, $ent); | |
157 | ||
365d5b95 SI |
158 | syslog ('info', "%s: removed attachment $id ('%s', rule: %s)", |
159 | $queue->{logid}, $on, $rulename); | |
758c7b6b DM |
160 | |
161 | } else { | |
162 | $self->delete_marked_parts($queue, $part, $html, $rtype, $marks); | |
163 | push (@$nparts, $part); | |
164 | } | |
165 | } | |
166 | ||
167 | $entity->parts ($nparts); | |
168 | } | |
169 | ||
170 | sub execute { | |
171 | my ($self, $queue, $ruledb, $mod_group, $targets, | |
172 | $msginfo, $vars, $marks) = @_; | |
173 | ||
6c65ab40 | 174 | my $rulename = $vars->{RULE} // 'unknown'; |
365d5b95 | 175 | |
758c7b6b DM |
176 | if (!$self->{all} && ($#$marks == -1)) { |
177 | # no marks | |
178 | return; | |
179 | } | |
180 | ||
181 | my $subgroups = $mod_group->subgroups ($targets); | |
182 | ||
183 | my $html = PMG::Utils::subst_values($self->{text}, $vars); | |
184 | ||
185 | $html = "This attachment was removed: __FILENAME__\n" if !$html; | |
186 | ||
187 | my $rtype = "text/plain"; | |
188 | ||
189 | if ($html =~ m/\<\w+\>/s) { | |
190 | $rtype = "text/html"; | |
191 | } | |
192 | ||
193 | foreach my $ta (@$subgroups) { | |
194 | my ($tg, $entity) = (@$ta[0], @$ta[1]); | |
195 | ||
196 | # handle singlepart mails | |
197 | my $ctype = $entity->head->mime_type; | |
198 | if (!$entity->is_multipart && (!$self->{all} || $ctype !~ m|text/.*|i)) { | |
199 | $entity->make_multipart(); | |
200 | my $first_part = $entity->parts(0); | |
201 | $first_part->head->mime_attr('x-proxmox-tmp-aid' => $entity->head->mime_attr('x-proxmox-tmp-aid')); | |
202 | $entity->head->delete('x-proxmox-tmp-aid'); | |
203 | } | |
204 | ||
365d5b95 | 205 | $self->delete_marked_parts($queue, $entity, $html, $rtype, $marks, $rulename); |
758c7b6b DM |
206 | |
207 | if ($msginfo->{testmode}) { | |
208 | $entity->head->mime_attr('Content-type.boundary' => '------=_TEST123456') if $entity->is_multipart; | |
209 | } | |
210 | } | |
211 | } | |
212 | ||
213 | sub short_desc { | |
214 | my $self = shift; | |
215 | ||
216 | if ($self->{all}) { | |
217 | return "remove all attachments"; | |
218 | } else { | |
219 | return "remove matching attachments"; | |
220 | } | |
221 | } | |
222 | ||
46eec8b4 DC |
223 | sub properties { |
224 | my ($class) = @_; | |
225 | ||
226 | return { | |
227 | all => { | |
228 | description => "Remove all attachments", | |
229 | type => 'boolean', | |
230 | optional => 1, | |
231 | }, | |
232 | text => { | |
233 | description => "The replacement text.", | |
234 | type => 'string', | |
235 | maxLength => 2048 | |
236 | } | |
237 | }; | |
238 | } | |
239 | ||
240 | sub get { | |
241 | my ($self) = @_; | |
242 | ||
243 | return { | |
244 | text => $self->{text}, | |
245 | all => $self->{all}, | |
246 | }; | |
247 | } | |
248 | ||
249 | sub update { | |
250 | my ($self, $param) = @_; | |
251 | ||
252 | $self->{text} = $param->{text}; | |
253 | $self->{all} = $param->{all} ? 1 : 0; | |
254 | } | |
758c7b6b DM |
255 | |
256 | 1; | |
257 | __END__ | |
258 | ||
259 | =head1 PMG::RuleDB::Remove | |
260 | ||
261 | Remove attachments. |