File Coverage

blib/lib/Text/SpamAssassin.pm
Criterion Covered Total %
statement 11 13 84.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 16 18 88.8


line stmt bran cond sub pod time code
1             package Text::SpamAssassin;
2             BEGIN {
3 1     1   6882 $Text::SpamAssassin::VERSION = '2.001';
4             }
5              
6 1     1   20 use 5.006;
  1         3  
  1         35  
7 1     1   5 use strict;
  1         1  
  1         28  
8 1     1   8 use warnings;
  1         2  
  1         31  
9              
10 1     1   1683 use Mail::SpamAssassin;
  0            
  0            
11             use Mail::Address;
12             use Mail::Header;
13             use Mail::Internet;
14             use POSIX qw(strftime);
15             use Data::Random qw(rand_chars);
16              
17             BEGIN {
18             if ($Mail::SpamAssassin::VERSION < 3) {
19             require Mail::SpamAssassin::NoMailAudit;
20             }
21             }
22              
23             sub new {
24             my ($class, %opts) = @_;
25              
26             my $self = bless {}, $class;
27             $self->reset;
28              
29             $self->{analyzer} = Mail::SpamAssassin->new($opts{sa_options});
30             $self->{analyzer}->compile_now if not $opts{lazy};
31              
32             return $self;
33             }
34              
35             sub DESTROY {
36             my ($self) = @_;
37              
38             local $@;
39             eval { $self->{analyzer}->finish };
40             }
41              
42             sub reset {
43             my ($self) = @_;
44              
45             $self->reset_metadata;
46             $self->reset_headers;
47              
48             return $self;
49             }
50              
51             sub reset_metadata {
52             my ($self) = @_;
53              
54             $self->{metadata} = {};
55              
56             return $self;
57             }
58              
59             sub reset_headers {
60             my ($self) = @_;
61              
62             $self->{header} = {};
63              
64             return $self;
65             }
66              
67             sub set_metadata {
68             my ($self, $key, $value) = @_;
69              
70             if (defined $value) {
71             $self->{metadata}{lc $key} = $value;
72             }
73             else {
74             delete $self->{metadata}{lc $key};
75             }
76              
77             return $self;
78             }
79              
80             sub set_header {
81             my ($self, $key, $value) = @_;
82              
83             $value = [ $value ] if not ref $value;
84              
85             if (defined $value) {
86             $self->{header}{lc $key} = $value;
87             }
88             else {
89             delete $self->{header}{lc $key};
90             }
91              
92             return $self;
93             }
94              
95             sub set_text {
96             my ($self, @text) = @_;
97              
98             $self->{text} = join '', @text;
99             delete $self->{html};
100              
101             return $self;
102             }
103              
104             sub set_html {
105             my ($self, @html) = @_;
106              
107             $self->{html} = join '', @html;
108             delete $self->{text};
109              
110             return $self;
111             }
112              
113             sub analyze {
114             my ($self) = @_;
115              
116             my $msg = $self->_generate_message;
117             my $status = $self->{analyzer}->check($msg);
118             $msg->finish;
119              
120             if (! $status) {
121             return {
122             verdict => 'UNKNOWN',
123             score => 0,
124             rules => '',
125             };
126             }
127              
128             my $result = {
129             verdict => $status->is_spam ? 'SUSPICIOUS' : 'OK',
130             score => $status->get_hits,
131             rules => $status->get_names_of_tests_hit,
132             };
133              
134             $status->finish;
135              
136             return $result;
137             }
138              
139             sub _generate_header {
140             my ($self) = @_;
141              
142             my $h = Mail::Header->new;
143              
144             for my $key ( keys %{$self->{headers}} ) {
145             $h->add($key, $_) for @{$self->{headers}{$key}};
146             }
147              
148             my $set = sub {
149             my ($key, $value) = @_;
150             $h->get($key) or $h->add($key, $value);
151             };
152              
153             $set->('To' => q{blog@example.com});
154             $set->('From' => Mail::Address->new(
155             $self->{metadata}{author} || q{Anonymous Coward},
156             $self->{metadata}{email} || q{nobody@example.com},
157             )->format);
158             $set->('Subject' => $self->{metadata}{subject} || q{Eponymous});
159              
160             $set->('Date' => strftime("%a, %d %b %Y %H:%M:%S %z", localtime));
161              
162             $set->('Received' => sprintf (
163             q{from %s ([%s]) by localhost (Postfix) with SMTP id %s for ; %s},
164             $self->{metadata}{ip} || q{127.0.0.1},
165             $self->{metadata}{ip} || q{127.0.0.1},
166             (join '', rand_chars(set => 'alphanumeric', size => 10)),
167             strftime("%a, %d %b %Y %H:%M:%S %z", localtime),
168             ));
169              
170             $set->('Message-Id', sprintf (
171             q{<%s@%s.example.com>},
172             (join '', rand_chars(set => 'alphanumeric', size => 32)),
173             (join '', rand_chars(set => 'alphanumeric', size => 10)),
174             ));
175              
176             $set->('MIME-Version', q{1.0});
177             $set->('Content-Transfer-Encoding', q{8bit});
178              
179             if ( $self->{html} ) {
180             $set->('Content-Type', q{text/html; charset="us-ascii"});
181             }
182             else {
183             $set->('Content-Type', q{text/plain; charset="us-ascii"});
184             }
185              
186             return $h;
187             }
188              
189             sub _generate_body {
190             my ($self) = @_;
191              
192             my @lines;
193              
194             if ( $self->{text} ) {
195             @lines = (
196             (map { "$_: $self->{metadata}{$_}" } sort keys %{$self->{metadata}}),
197             (keys %{$self->{metadata}} ? q{} : ()),
198             $self->{text},
199             );
200             }
201              
202             elsif ( $self->{html} ) {
203             @lines = (
204             q{},
205             q{Anazlyzed comment
    },
206             (map { "
  • $_: $self->{metadata}{$_}
  • " } sort keys %{$self->{metadata}}),
    207             q{},
    208             $self->{html},
    209             q{},
    210             );
    211             }
    212              
    213             return join "\n", @lines;
    214             }
    215              
    216             sub _generate_message {
    217             my ($self) = @_;
    218              
    219             my $msg = Mail::Internet->new(
    220             Header => $self->_generate_header,
    221             Body => [$self->_generate_body],
    222             );
    223              
    224             if ($Mail::SpamAssassin::VERSION < 3) {
    225             return Mail::SpamAssassin::NoMailAudit->new(
    226             data => [ split(/\n/, $msg->as_string) ],
    227             );
    228             }
    229              
    230             return Mail::SpamAssassin::Message->new({
    231             message => $msg->as_string,
    232             });
    233             }
    234              
    235             1;
    236              
    237             __END__