13 use Time
::HiRes qw
(gettimeofday
);
20 my $msg = shift || '';
28 return $dbh->last_insert_id(
29 undef, undef, undef, undef, { sequence
=> $seq});
33 my ($filename, $lasttime) = @_;
35 my $st = stat($filename);
37 return 0 if !defined($st);
39 return ($lasttime >= $st->ctime);
42 sub extract_filename
{
45 if (my $value = $head->recommended_filename()) {
47 if (my $decvalue = MIME
::Words
::decode_mimewords
($value)) {
48 $decvalue =~ s/\0/ /g;
49 $decvalue = trim
($decvalue);
58 my ($entity, $add_id, $id) = @_;
62 foreach my $tag (grep {/^x-proxmox-tmp/i} $entity->head->tags) {
63 $entity->head->delete ($tag);
66 $entity->head->replace('X-Proxmox-tmp-AID', $id) if $add_id;
68 foreach my $part ($entity->parts) {
69 $id = remove_marks
($part, $add_id, $id + 1);
80 foreach my $k (keys %$dh) {
83 $body =~ s/__${k}__/$v/gs;
91 my ($entity, $sender, $targets, $xforward, $me, $nodsn) = @_;
99 my $smtp = Net
::SMTP-
>new('127.0.0.1', Port
=> 10025, Hello
=> $me) ||
100 die "unable to connect to localhost at port 10025";
102 if (defined($xforward)) {
105 foreach my $attr (keys %{$xforward}) {
106 $xfwd .= " $attr=$xforward->{$attr}";
109 if ($xfwd && $smtp->command("XFORWARD", $xfwd)->response() != CMD_OK
) {
110 syslog
('err', "xforward error - got: %s %s", $smtp->code, scalar($smtp->message));
114 if (!$smtp->mail($sender)) {
115 syslog
('err', "smtp error - got: %s %s", $smtp->code, scalar ($smtp->message));
116 die "smtp from: ERROR";
119 my $dsnopts = $nodsn ?
{Notify
=> ['NEVER']} : {};
121 if (!$smtp->to (@$targets, $dsnopts)) {
122 syslog
('err', "smtp error - got: %s %s", $smtp->code, scalar($smtp->message));
123 die "smtp to: ERROR";
127 #$entity->sync_headers ();
130 my $out = PMG
::SMTPPrinter-
>new($smtp);
131 $entity->print($out);
133 # make sure we always have a newline at the end of the mail
134 # else dataend() fails
135 $smtp->datasend("\n");
137 if ($smtp->dataend()) {
138 my @msgs = $smtp->message;
139 $resmess = $msgs[$#msgs];
140 ($resid) = $resmess =~ m/Ok: queued as ([0-9A-Z]+)/;
141 $rescode = $smtp->code;
143 die sprintf("unexpected SMTP result - got: %s %s : WARNING", $smtp->code, $resmess);
146 my @msgs = $smtp->message;
147 $resmess = $msgs[$#msgs];
148 $rescode = $smtp->code;
149 die sprintf("sending data failed - got: %s %s : ERROR", $smtp->code, $resmess);
154 $smtp->quit if $smtp;
157 syslog
('err', $err);
160 return wantarray ?
($resid, $rescode, $resmess) : $resid;
163 sub analyze_virus_clam
{
164 my ($queue, $dname, $pmg_cfg) = @_;
169 my $clamdscan_opts = "--stdout";
171 my ($csec, $usec) = gettimeofday
();
177 $previous_alarm = alarm($timeout);
180 die "$queue->{logid}: Maximum time ($timeout sec) exceeded. " .
181 "virus analyze (clamav) failed: ERROR";
184 open(CMD
, "/usr/bin/clamdscan $clamdscan_opts '$dname'|") ||
185 die "$queue->{logid}: can't exec clamdscan: $! : ERROR";
191 if (m/^$dname.*:\s+([^ :]*)\s+FOUND$/) {
192 # we just use the first detected virus name
193 $vinfo = $1 if !$vinfo;
195 if (m/^Infected files:\s(\d*)$/i) {
204 alarm(0); # avoid race conditions
206 if (!defined($ifiles)) {
207 die "$queue->{logid}: got undefined output from " .
208 "virus detector: $res : ERROR";
212 syslog
('info', "$queue->{logid}: virus detected: $vinfo (clamav)");
217 alarm($previous_alarm);
219 my ($csec_end, $usec_end) = gettimeofday
();
220 $queue->{ptime_clam
} =
221 int (($csec_end-$csec)*1000 + ($usec_end - $usec)/1000);
224 syslog
('err', $err);
226 $queue->{errors
} = 1;
229 $queue->{vinfo_clam
} = $vinfo;
231 return $vinfo ?
"$vinfo (clamav)" : undef;
235 my ($queue, $filename, $pmg_cfg, $testmode) = @_;
237 # TODO: support other virus scanners?
239 # always scan with clamav
240 return analyze_virus_clam
($queue, $filename, $pmg_cfg);
243 sub magic_mime_type_for_file
{
246 # we do not use get_mime_type_for_file, because that considers
247 # filename extensions - we only want magic type detection
249 my $bufsize = Xdgmime
::xdg_mime_get_max_buffer_extents
();
250 die "got strange value for max_buffer_extents" if $bufsize > 4096*10;
252 my $ct = "application/octet-stream";
254 my $fh = IO
::File-
>new("<$filename") ||
255 die "unable to open file '$filename' - $!";
258 if (($len = $fh->read($buf, $bufsize)) > 0) {
259 $ct = xdg_mime_get_mime_type_for_data
($buf, $len);
263 die "unable to read file '$filename' - $!" if ($len < 0);
271 if (my $path = $entity->{PMX_decoded_path
}) {
273 # set a reasonable default if magic does not give a result
274 $entity->{PMX_magic_ct
} = $entity->head->mime_attr('content-type');
276 if (my $ct = magic_mime_type_for_file
($path)) {
277 if ($ct ne 'application/octet-stream' || !$entity->{PMX_magic_ct
}) {
278 $entity->{PMX_magic_ct
} = $ct;
282 my $filename = $entity->head->recommended_filename;
283 $filename = basename
($path) if !defined($filename) || $filename eq '';
285 if (my $ct = xdg_mime_get_mime_type_from_file_name
($filename)) {
286 $entity->{PMX_glob_ct
} = $ct;
290 foreach my $part ($entity->parts) {
291 add_ct_marks
($part);