Mailing List Archive

svn commit: r1916171 - in /spamassassin/trunk: MANIFEST lib/Mail/SpamAssassin/HTML.pm t/html_visibility.t
Author: sidney
Date: Thu Mar 7 23:38:30 2024
New Revision: 1916171

URL: http://svn.apache.org/viewvc?rev=1916171&view=rev
Log:
bug 8210 Parse and recognize CSS background property

Added:
spamassassin/trunk/t/html_visibility.t
Modified:
spamassassin/trunk/MANIFEST
spamassassin/trunk/lib/Mail/SpamAssassin/HTML.pm

Modified: spamassassin/trunk/MANIFEST
URL: http://svn.apache.org/viewvc/spamassassin/trunk/MANIFEST?rev=1916171&r1=1916170&r2=1916171&view=diff
==============================================================================
--- spamassassin/trunk/MANIFEST (original)
+++ spamassassin/trunk/MANIFEST Thu Mar 7 23:38:30 2024
@@ -541,6 +541,7 @@ t/hashbl.t
t/html_colors.t
t/html_obfu.t
t/html_utf8.t
+t/html_visibility.t
t/idn_dots.t
t/if_can.t
t/if_else.t

Modified: spamassassin/trunk/lib/Mail/SpamAssassin/HTML.pm
URL: http://svn.apache.org/viewvc/spamassassin/trunk/lib/Mail/SpamAssassin/HTML.pm?rev=1916171&r1=1916170&r2=1916171&view=diff
==============================================================================
--- spamassassin/trunk/lib/Mail/SpamAssassin/HTML.pm (original)
+++ spamassassin/trunk/lib/Mail/SpamAssassin/HTML.pm Thu Mar 7 23:38:30 2024
@@ -562,7 +562,7 @@ sub text_style {
my $value = lc $2;
# prevent parsing of the valid CSS3 property value as
# 'invalid color' (Bug 7892)
- $value =~ s/\s+!important$//;
+ $value =~ s/\s*!\s*important$//;

if (index($value, 'rgb') >= 0) {
$value =~ tr/0-9,//cd;
@@ -575,19 +575,41 @@ sub text_style {
# do nothing, just prevent parsing of the valid
# CSS3 property value as 'invalid color' (Bug 7778)
}
- elsif ($value eq 'transparent' && $whcolor eq 'bgcolor') {
- # do nothing, just prevent parsing of the valid
- # CSS3 property value as 'invalid color' (Bug 7892)
+ elsif ($value eq 'transparent') {
+ # keep for now, handle outside the loop (Bug 8205)
+ $new{$whcolor} = $value;
}
else {
$new{$whcolor} = name_to_rgb($value);
}
}
+ elsif (/^\s*background:\s*(.+?)\s*$/) {
+ # parse CSS background property (Bug 8210)
+ my $layers = parse_css_background(lc($1));
+ # loop through values in the bottom layer and look for valid colors
+ for my $value (@{$layers->[-1]}) {
+ my $color = name_to_rgb($value);
+ if ($color ne 'invalid') {
+ $new{bgcolor} = $color;
+ last;
+ }
+ }
+
+ }
elsif (/^\s*([a-z_-]+)\s*:\s*(\S.*?)\s*$/i) {
# "display: none", "visibility: hidden", etc.
$new{'style_'.$1} = $2;
}
}
+ # Handle transparent colors (Bug 8205)
+ if ($new{bgcolor} eq 'transparent') {
+ # replace with parent's bgcolor
+ $new{bgcolor} = $self->{text_style}[-1]->{bgcolor};
+ }
+ if ($new{fgcolor} eq 'transparent') {
+ # replace with current bgcolor
+ $new{fgcolor} = $new{bgcolor};
+ }
}
elsif ($name eq "bgcolor") {
# overwrite with hex value, $new{bgcolor} is set below
@@ -616,6 +638,92 @@ sub text_style {
}
}

+# Parses a CSS background property value.
+# Returns an arrayref of layers, each layer is an arrayref of values such as
+# [
+# 'rgb(255, 192, 0)',
+# '35%',
+# 'url("../../media/examples/lizard.png")'
+# ]
+# https://developer.mozilla.org/en-US/docs/Web/CSS/background
+sub parse_css_background {
+ my ($background) = @_;
+
+ my @layers;
+ my @tokens;
+ my @stack;
+ my ($state,$token) = (0,'');
+ for (my $i=0;$i < length($background);$i++) {
+ my $ch = substr($background, $i, 1);
+ if ($state == 0) {
+ if ($ch eq ' ') {
+ push @tokens, $token if $token ne '';
+ $token = '';
+ } elsif ($ch eq '(') {
+ $token .= $ch;
+ push @stack, $state;
+ $state = 1;
+ } elsif ($ch eq '"') {
+ $token .= $ch;
+ push @stack, $state;
+ $state = 2;
+ } elsif ($ch eq q(')) {
+ $token .= $ch;
+ push @stack, $state;
+ $state = 3;
+ } elsif ($ch eq ',') {
+ push @tokens, $token if $token ne '';
+ $token = '';
+ push @layers, [ @tokens ];
+ @tokens = ();
+ } else {
+ $token .= $ch;
+ }
+ } elsif ($state == 1) {
+ if ($ch eq ')') {
+ $token .= $ch;
+ push @tokens, $token;
+ $token = '';
+ $state = pop @stack;
+ } elsif ($ch eq '"') {
+ $token .= $ch;
+ push(@stack, $state);
+ $state = 2;
+ } elsif ($ch eq q(')) {
+ $token .= $ch;
+ push(@stack, $state);
+ $state = 3;
+ } else {
+ $token .= $ch;
+ }
+ } elsif ($state == 2) {
+ if ($ch eq '"') {
+ $token .= $ch;
+ $state = pop @stack;
+ } else {
+ $token .= $ch;
+ }
+ } elsif ($state == 3) {
+ if ($ch eq q(')) {
+ $token .= $ch;
+ $state = pop @stack;
+ } else {
+ $token .= $ch;
+ }
+ }
+ }
+
+ if ($token ne '') {
+ push @tokens, $token;
+ }
+ if ( scalar @tokens > 0 ) {
+ push @layers, [ @tokens ];
+ }
+
+ return \@layers;
+
+}
+
sub html_font_invisible {
my ($self, $text) = @_;


Added: spamassassin/trunk/t/html_visibility.t
URL: http://svn.apache.org/viewvc/spamassassin/trunk/t/html_visibility.t?rev=1916171&view=auto
==============================================================================
--- spamassassin/trunk/t/html_visibility.t (added)
+++ spamassassin/trunk/t/html_visibility.t Thu Mar 7 23:38:30 2024
@@ -0,0 +1,77 @@
+#!/usr/bin/perl -T
+use strict;
+use warnings;
+use lib 'lib';
+use Mail::SpamAssassin::HTML;
+use Test::More;
+
+my @tests = (
+ {
+ html => '<div style="background-color: transparent">X</div>',
+ visibility => 'visible',
+ font_invalid_color => 0,
+ },
+ {
+ html => '<div style="color: transparent">X</div>',
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => '<div style="color: transparent;background-color: red">X</div>',
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => '<div style="background-color: red;color: transparent">X</div>',
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => '<div style="background: 60px 60px, 0 0, 30px 30px, red;color: transparent">X</div>',
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => q{<div style="background: url('../../media/examples/lizard.png'), red;color: transparent">X</div>},
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => q{<div style='background: url("../../media/examples/lizard.png"), linear-gradient(rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)), 60px 60px, 0 0, 30px 30px, red;color: transparent'>X</div>},
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => '<div style="background-color: transparent;color: transparent">X</div>',
+ visibility => 'invisible',
+ font_invalid_color => 0,
+ },
+ {
+ html => '<div style="color: red !important">X</div>',
+ visibility => 'visible',
+ font_invalid_color => 0,
+ },
+);
+
+plan tests => scalar @tests * 2;
+
+foreach my $test (@tests) {
+ my $html = $test->{html};
+
+ my $html_obj = Mail::SpamAssassin::HTML->new(0,0, debug => 'message');
+ $html_obj->parse($html);
+
+ my $visible_text = $html_obj->get_rendered_text(invisible => 0);
+ my $invisible_text = $html_obj->get_rendered_text(invisible => 1);
+
+ my $visibility =
+ ($visible_text =~ /\S/ ? 'visible' : '') .
+ ($invisible_text =~ /\S/ ? 'invisible' : '');
+
+ is($visibility, $test->{visibility}, $html);
+
+ my $font_invalid_color = $html_obj->{results}->{font_invalid_color} // 0;
+
+ is($font_invalid_color, $test->{font_invalid_color}, $html);
+}
+