~ubuntu-branches/ubuntu/natty/spamassassin/natty

« back to all changes in this revision

Viewing changes to lib/Mail/SpamAssassin/Plugin/ImageInfo.pm

  • Committer: Package Import Robot
  • Author(s): Noah Meyerhans
  • Date: 2010-03-21 23:20:31 UTC
  • mfrom: (0.4.1) (1.4.1) (29.2.1 maverick)
  • Revision ID: package-import@ubuntu.com-20100321232031-ryqjxh9cx27epnka
Tags: 3.3.1-1
* New upstream version.
* Update several patches now that bugfixes have been incorporated
  upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
# The ASF licenses this file to you under the Apache License, Version 2.0
6
6
# (the "License"); you may not use this file except in compliance with
7
7
# the License.  You may obtain a copy of the License at:
8
 
 
8
#
9
9
#     http://www.apache.org/licenses/LICENSE-2.0
10
 
 
10
#
11
11
# Unless required by applicable law or agreed to in writing, software
12
12
# distributed under the License is distributed on an "AS IS" BASIS,
13
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
16
# </@LICENSE>
17
17
#
18
18
# -------------------------------------------------------
 
19
# ImageInfo Plugin for SpamAssassin
 
20
# Version: 0.7
 
21
# Created: 2006-08-02
 
22
# Modified: 2007-01-17
 
23
#
 
24
# Changes:
 
25
#   0.7 - added image_name_regex to allow pattern matching on the image name
 
26
#       - added support for image/pjpeg content types (progressive jpeg)
 
27
#       - updated imageinfo.cf with a few sample rules for using image_name_regex()
 
28
#   0.6 - fixed dems_ bug in image_size_range_
 
29
#   0.5 - added image_named and image_to_text_ratio
 
30
#   0.4 - added image_size_exact and image_size_range
 
31
#   0.3 - added jpeg support
 
32
#   0.2 - optimized by theo
 
33
#   0.1 - added gif/png support
 
34
#
19
35
#
20
36
# Usage:
21
37
#  image_count()
22
38
#
23
 
#     body RULENAME  eval:image_count(<type>,<min>,[max]) 
24
 
#        type: 'all','gif','png', or 'jpeg'  
25
 
#        min: required, message contains at least this 
 
39
#     body RULENAME  eval:image_count(<type>,<min>,[max])
 
40
#        type: 'all','gif','png', or 'jpeg'
 
41
#        min: required, message contains at least this
26
42
#             many images
27
 
#        max: optional, if specified, message must not 
 
43
#        max: optional, if specified, message must not
28
44
#             contain more than this number of images
29
45
#
30
 
#  examples
31
 
32
 
#     body ONE_IMAGE  eval:image_count('all',1,1) 
 
46
#  image_count() examples
 
47
#
 
48
#     body ONE_IMAGE  eval:image_count('all',1,1)
33
49
#     body ONE_OR_MORE_IMAGES  eval:image_count('all',1)
34
50
#     body ONE_PNG eval:image_count('png',1,1)
35
51
#     body TWO_GIFS eval:image_count('gif',2,2)
44
60
#        max: optional, if specified, message must not
45
61
#             contain more than this much pixel area
46
62
#
47
 
#  examples
48
 
#
49
 
#     body LARGE_IMAGE_AREA  eval:pixel_coverage('all',150000)
50
 
#     body SMALL_GIF_AREA  eval:pixel_coverage('gif',1,40000)
51
 
#
52
 
#  See the ruleset for ways to meta image_count() 
53
 
#  and pixel_coverage() together.  
 
63
#   pixel_coverage() examples
 
64
#
 
65
#     body LARGE_IMAGE_AREA  eval:pixel_coverage('all',150000)  # catches any images that are 150k pixel/sq or higher
 
66
#     body SMALL_GIF_AREA  eval:pixel_coverage('gif',1,40000)   # catches only gifs that 1 to 40k pixel/sql
 
67
#
 
68
#  image_name_regex()
 
69
#
 
70
#     body RULENAME  eval:image_name_regex(<regex>)
 
71
#        regex: full quoted regexp, see examples below
 
72
#
 
73
#  image_name_regex() examples
 
74
#
 
75
#     body CG_DOUBLEDOT_GIF  eval:image_name_regex('/^\w{2,9}\.\.gif$/i') # catches double dot gifs  abcd..gif
 
76
#
 
77
#
54
78
#
55
79
# -------------------------------------------------------
56
80
 
75
99
  $class = ref($class) || $class;
76
100
  my $self = $class->SUPER::new($mailsaobject);
77
101
  bless ($self, $class);
78
 
  
 
102
 
79
103
  $self->register_eval_rule ("image_count");
80
104
  $self->register_eval_rule ("pixel_coverage");
81
105
  $self->register_eval_rule ("image_size_exact");
82
106
  $self->register_eval_rule ("image_size_range");
83
107
  $self->register_eval_rule ("image_named");
 
108
  $self->register_eval_rule ("image_name_regex");
84
109
  $self->register_eval_rule ("image_to_text_ratio");
85
110
 
86
111
  return $self;
105
130
    #my $has_global_color_table = $global_color_table ? 1 : 0;
106
131
    #my $sorted_colors = ($packed & 0x08)?1:0;
107
132
    #my $resolution = ((($packed & 0x70) >> 4) + 1);
108
 
 
 
133
 
109
134
    if ($height && $width) {
110
135
      my $area = $width * $height;
111
136
      $pms->{imageinfo}->{pc_gif} += $area;
112
137
      $pms->{imageinfo}->{dems_gif}->{"${height}x${width}"} = 1;
113
138
      $pms->{imageinfo}->{names_all}->{$part->{'name'}} = 1 if $part->{'name'};
114
 
      dbg("imageinfo: gif image ".($part->{'name'} ? $part->{'name'} : '')." is $height x $width pixels ($area pixels sq.), with $color_table_size color table"); 
 
139
      dbg("imageinfo: gif image ".($part->{'name'} ? $part->{'name'} : '')." is $height x $width pixels ($area pixels sq.), with $color_table_size color table");
115
140
    }
116
141
  },
117
142
 
126
151
    my $chunksize = 8;
127
152
    my ($width, $height) = ( 0, 0 );
128
153
    my ($depth, $ctype, $compression, $filter, $interlace);
129
 
  
 
154
 
130
155
    while ($pos < $datalen) {
131
156
      my ($len, $type) = unpack("Na4", substr($data, $pos, $chunksize));
132
157
      $pos += $chunksize;
133
 
 
 
158
 
134
159
      last if $type eq "IEND";  # end of png image.
135
160
 
136
161
      next unless ( $type eq "IHDR" && $len == 13 );
137
 
      
 
162
 
138
163
      my $bytes = substr($data, $pos, $len + 4);
139
164
      my $crc = unpack("N", substr($bytes, -4, 4, ""));
140
165
 
181
206
    }
182
207
 
183
208
    if ($height && $width) {
184
 
      my $area = $height * $width; 
 
209
      my $area = $height * $width;
185
210
      $pms->{imageinfo}->{pc_jpeg} += $area;
186
211
      $pms->{imageinfo}->{dems_jpeg}->{"${height}x${width}"} = 1;
187
212
      $pms->{imageinfo}->{names_all}->{$part->{'name'}} = 1 if $part->{'name'};
201
226
    $pms->{'imageinfo'}->{"count_$type"} = 0;
202
227
  }
203
228
 
204
 
  foreach my $p ($pms->{msg}->find_parts(qr@^image/(?:gif|png|jpe?g)$@, 1)) {
 
229
  foreach my $p ($pms->{msg}->find_parts(qr@^image/(?:gif|png|jpeg)$@, 1)) {
205
230
    # make sure its base64 encoded
206
231
    my $cte = lc $p->get_header('content-transfer-encoding') || '';
207
232
    next if ($cte !~ /^base64$/);
208
233
 
209
234
    my ($type) = $p->{'type'} =~ m@/(\w+)$@;
210
 
    $type='jpeg' if $type eq 'jpg';
211
235
    if ($type && exists $get_details{$type}) {
212
236
       $get_details{$type}->($pms,$p);
213
237
       $pms->{'imageinfo'}->{"count_$type"} ++;
246
270
 
247
271
# -----------------------------------------
248
272
 
 
273
sub image_name_regex {
 
274
  my ($self,$pms,$body,$re) = @_;
 
275
  return unless (defined $re);
 
276
 
 
277
  # make sure we have image data read in.
 
278
  if (!exists $pms->{'imageinfo'}) {
 
279
    $self->_get_images($pms);
 
280
  }
 
281
 
 
282
  return 0 unless (exists $pms->{'imageinfo'}->{"names_all"});
 
283
 
 
284
  my $hit = 0;
 
285
  foreach my $name (keys %{$pms->{'imageinfo'}->{"names_all"}}) {
 
286
    dbg("imageinfo: checking image named $name against regex $re");
 
287
    if (eval { $name =~ /$re/ }) { $hit = 1 }
 
288
    dbg("imageinfo: error in regex /$re/ - $@") if $@;
 
289
    if ($hit) {
 
290
      dbg("imageinfo: image_name_regex hit on $name");
 
291
      return 1;
 
292
    }
 
293
  }
 
294
  return 0;
 
295
 
 
296
}
 
297
 
 
298
# -----------------------------------------
 
299
 
249
300
sub image_count {
250
301
  my ($self,$pms,$body,$type,$min,$max) = @_;
251
 
  
 
302
 
252
303
  return unless defined $min;
253
304
 
254
305
  # make sure we have image data read in.
271
322
  if (!exists $pms->{'imageinfo'}) {
272
323
    $self->_get_images($pms);
273
324
  }
274
 
  
 
325
 
275
326
  # dbg("imageinfo: pc_$type: $min, ".($max ? $max:'').", $type, ".$pms->{'imageinfo'}->{"pc_$type"});
276
327
  return result_check($min, $max, $pms->{'imageinfo'}->{"pc_$type"});
277
328
}
287
338
    $self->_get_images($pms);
288
339
  }
289
340
 
290
 
  # depending on how you call this eval (body vs rawbody), 
 
341
  # depending on how you call this eval (body vs rawbody),
291
342
  # the $textlen will differ.
292
343
  my $textlen = length(join('',@$body));
293
344
 
294
345
  return 0 unless ( $textlen > 0 && exists $pms->{'imageinfo'}->{"pc_$type"} && $pms->{'imageinfo'}->{"pc_$type"} > 0);
295
 
  
 
346
 
296
347
  my $ratio = $textlen / $pms->{'imageinfo'}->{"pc_$type"};
297
348
  dbg("imageinfo: image ratio=$ratio, min=$min max=$max");
298
349
  return result_check($min, $max, $ratio, 1);
325
376
    $self->_get_images($pms);
326
377
  }
327
378
 
328
 
  return unless (exists $pms->{'imageinfo'}->{"dems_$type"});
 
379
  my $name = 'dems_'.$type;
 
380
  return unless (exists $pms->{'imageinfo'}->{$name});
329
381
 
330
382
  foreach my $dem ( keys %{$pms->{'imageinfo'}->{"dems_$type"}}) {
331
383
    my ($h,$w) = split(/x/,$dem);