File Coverage

blib/lib/Mail/Lite/Processor/Match.pm
Criterion Covered Total %
statement 107 138 77.5
branch 38 48 79.1
condition 27 35 77.1
subroutine 20 24 83.3
pod 0 5 0.0
total 192 250 76.8


line stmt bran cond sub pod time code
1             #===============================================================================
2             #
3             # FILE: Match.pm
4             #
5             # DESCRIPTION: Processor::Match match processor
6             #
7             # FILES: ---
8             # BUGS: ---
9             # NOTES: ---
10             # AUTHOR: Pavel Boldin (),
11             # COMPANY:
12             #===============================================================================
13              
14             package Mail::Lite::Processor::Match;
15              
16 2     2   12 use strict;
  2         5  
  2         95  
17 2     2   10 use warnings;
  2         4  
  2         67  
18              
19 2     2   11 use Mail::Lite::Constants;
  2         4  
  2         200  
20 2     2   12 use Smart::Comments -ENV;
  2         3  
  2         25  
21 2     2   4619 use Digest::MD5 qw/md5_hex/;
  2         6  
  2         145  
22 2     2   13 use Carp qw/cluck/;
  2         3  
  2         1949  
23              
24             require Data::Dumper;
25              
26             sub _dump {
27 0     0   0 my @a = @_;
28 0         0 my $dd = Data::Dumper->new(\@a);
29 0         0 return $dd->Indent(1)->Terse(1)->Dump;
30             #Data::Dumper->new(\@_)->Indent(1)->Terse(1)->Dump;
31             }
32              
33             sub _match_rule {
34 1077     1077   2279 my ( $rule, $data ) = @_;
35              
36 1077         2578 my ( $message, $field ) = @$data;
37              
38             #warn _dump( $rule, $field, $message );
39              
40 1077   50     2739 my $matched = $message->{matched} ||= {};
41              
42 1077   100     3187 my $rule_hash = "$field:".($rule||'defined');
43              
44 1077 100       2787 if ( exists $matched->{ $rule_hash } ) {
45 77 100       794 return 1 if $matched->{ $rule_hash };
46 5         20 return 0;
47             }
48             else
49             {
50 1000         1041 my $result;
51              
52 1000 50 33     2745 if ( ref $rule eq 'HASH' && exists $rule->{matcher} ) {
53            
54 0         0 $result = _check_with_custom_processor( $message, $rule );
55             }
56             else {
57 1000 100       4686 if ( $field eq 'body' ) {
    100          
58 602         1563 $result = match_body( $message, $rule );
59             }
60             elsif ( my $checker = __PACKAGE__->can("match_$field") ) {
61             #warn "Can match_$field";
62 29         102 $result = $checker->( $message, $rule );
63             }
64             else {
65             #warn "Can match_header_field: $field, $rule";
66 369         972 $result = match_header_field($message, $field, $rule);
67             }
68             }
69              
70 1000         3247 $matched->{ $rule_hash } = $result;
71              
72 1000         3789 return $result;
73             }
74             }
75              
76              
77             sub _match_message {
78             #warn _dump( @_ );
79 938     938   1426 my $rules = shift;
80 938         1099 my $message = shift;
81              
82              
83 938   100     2479 my $matched = $message->{matched} ||= {};
84              
85             #keys %$rules;
86 938         2301 foreach my $k (keys %$rules) {
87             #while (my ($k, $v) = each %$rules) {
88 987         1579 my $v = $rules->{$k};
89              
90 987   100     4612 my $rule_hash = "$k:".($v || 'defined');
91 987 100       3372 if ( exists $matched->{ $rule_hash } ){
92 54 50       173 next if $matched->{ $rule_hash };
93             # #keys %$rules;
94 0         0 return;
95             }
96             else {
97 933         3409 my $result = _recurse_conditions( \&_match_rule, $v,
98             [ $message, $k ]
99             );
100              
101             # $matched->{ $rule_hash } = $result;
102              
103 933 100       5825 return unless $result;
104             }
105             }
106              
107 565         2826 return 1;
108             }
109              
110             sub _recurse_conditions {
111             #open my $fh, '>>output.txt';
112             # if ( ref $_[1] eq 'HASH' ) {
113             #print $_[1], "\n";
114             #print join (', ', exists $_[1]->{'AND'}, exists $_[1]->{'NOT'}, exists $_[1]->{'OR'}), "\n";
115             #print tied( $_[1] ) ? 'tied' : 'untied', "\n";
116             #print _dump( $_[1]->{'OR'} );
117             #print $fh "Join:".join (', ', %{ $_[1] }), "\n";
118             # } elsif ( ref $_[1] eq 'ARRAY' ) {
119             #print $fh "Join:".join (', ', @{ $_[1] }), "\n";
120             # } elsif ( not ref $_[1] ) {
121             #print $fh $_[1], "\n";
122             # }
123             #close $fh;
124             #warn ( ("".\@_) x 1024 );
125              
126 2540     2540   3365 my $handler = shift;
127 2540         3300 my $rule = shift;
128 2540         3578 my $data = shift;
129              
130             ### $rule
131              
132 2540 50 100     16120 if ( ref $rule eq 'HASH'
      66        
      66        
133             and
134             exists $rule->{'AND'} ||
135             exists $rule->{'OR' } ||
136             exists $rule->{'NOT'}
137             and
138             scalar keys %$rule > 1
139             ) {
140 0         0 die q{Wrong keys in }
141             ._dump($rule).
142             qq{\nYou should not mess up OR/AND/NOT with plain fields}.
143             qq{\nSeparate them into different array members};
144              
145             }
146              
147 2540 50 66     9854 if ( ref $rule eq 'HASH' and exists $rule->{'AND'} ) {
148 0         0 $rule = $rule->{'AND'};
149             }
150              
151 2540 100       5312 if ( ref $rule eq 'ARRAY' ) {
152             #warn 'AND: '.ref $data;
153 312         684 foreach my $r ( @$rule ) {
154             #warn 'rule is: '.$r;
155 684 100       1453 if ( ! _recurse_conditions( $handler, $r, $data ) ) {
156 175         503 return 0;
157             }
158             }
159              
160             #warn 'and: ',_dump $rule, $data;
161 137         363 return 1;
162             }
163              
164 2228 100 100     8594 if ( ref $rule eq 'HASH' and exists $rule->{'NOT'} ) {
165             # warn 'NOT: '.ref $data;
166 30         110 return ! _recurse_conditions( $handler, $rule->{'NOT'}, $data );
167             }
168              
169 2198 100 100     7737 if ( ref $rule eq 'HASH' and exists $rule->{'OR'} ) {
170 183         314 $rule = $rule->{'OR'};
171             #warn 'OR: '.ref $data;
172             #warn _dump $rule;
173              
174             #warn _dump $data->{matched};
175 183         347 foreach my $r ( @$rule ) {
176             #warn 'oring: ', $handler eq \&_match_message;
177 213 100       396 if ( _recurse_conditions( $handler, $r, $data ) ) {
178             #warn 'or: ',_dump $r, $data;
179 154         440 return 1;
180             }
181             }
182              
183 29         110 return 0;
184             }
185              
186             #warn 'simply: '.ref $data;
187             #warn _dump $data if ref $data eq 'Mail::Lite::Message';
188 2015 50       4972 if ( $ENV{FAKE_THEM_ALL} ) {
189             # print "faken saved: $ENV{FAKE_THEM_ALL}\n";
190             #warn 'hash with: '.scalar (values %$rule) if ref $rule eq 'HASH';
191             }
192              
193              
194             #warn 'simply', $handler eq \&_match_rule;
195 2015         3746 return $handler->( $rule, $data );
196             }
197              
198             sub _check_with_custom_processor {
199 0     0   0 my ($message, $rule) = @_;
200 0 0       0 if ( not ref $rule->{matcher} eq 'CODE' ) {
201 0         0 my ($package, $sub) = $rule->{matcher} =~ /(.*)::(.*)/;
202 0         0 $package->require;
203              
204             {
205 2     2   14 no strict 'refs'; ## no critic
  2         4  
  2         328  
  0         0  
206 0         0 $rule->{matcher} = *{"$package\::$sub"}{CODE};
  0         0  
207             }
208             }
209              
210 0         0 return $rule->{matcher}->( $message, $rule );
211             }
212              
213             our $match_text = \&_match_text;
214              
215             sub match_body {
216 602     602 0 1018 my ( $message, $rule ) = @_;
217              
218 602         1918 my $body = $message->{body};
219              
220             #warn "rule = $rule";
221 602         2948 @_ = ($body, $rule);
222 2     2   12 no strict 'refs';
  2         5  
  2         190  
223 602         2069 goto &$match_text;
224              
225             #return _match_text( $body, $rule );
226             }
227              
228             sub _match_subject {
229 0     0   0 my ( $message, $rule ) = @_;
230              
231 0         0 my $text = $message->{subject};
232              
233             #die "$text ::: $rule";
234             #warn "rule = $rule";
235 0         0 @_ = ($text, $rule);
236 2     2   10 no strict 'refs';
  2         5  
  2         223  
237 0         0 goto &$match_text;
238 0         0 goto &{'_match_text'};
  0         0  
239              
240             #return _match_text( $text, $rule );
241             }
242              
243             sub _match_from {
244 0     0   0 my ( $message, $rule ) = @_;
245              
246 0         0 my $text = $message->{from};
247              
248             #warn "rule = $rule";
249 0         0 @_ = ($text, $rule);
250 2     2   12 no strict 'refs';
  2         4  
  2         460  
251 0         0 goto &$match_text;
252 0         0 goto &{'_match_text'};
  0         0  
253              
254             #return _match_text( $text, $rule );
255             }
256              
257             sub match_to {
258 29     29 0 48 my ( $message, $rule ) = @_;;
259              
260             #warn "rule = $rule";
261 29         151 my $msg_recipients = $message->recipients;
262 29         53 foreach my $msg_to (@{$msg_recipients}) {
  29         87  
263 29 50       74 return 1 if _match_text( $msg_to, $rule );
264             }
265              
266 0         0 return 0;
267             }
268              
269             sub match_header_field {
270 369     369 0 743 my ( $message, $field, $rule ) = @_;
271              
272 369 100       856 $field = 'subject' if $field eq 'subj';
273              
274             #my $value = $message->raw_header;
275              
276 369 100       1559 my $value = exists $message->{ $field }
277             ? $message->{ $field } : $message->header( $field );
278              
279             #die "$value, $field, $rule";
280             #warn "rule = $rule";
281             #die $value, $field, $rule;
282             #return _match_text( $value, '(?im)^'.$field.':\s+[^\n]*'.$rule );
283 369         1237 @_ = ($value, $rule);
284 2     2   12 no strict 'refs';
  2         4  
  2         678  
285 369         1251 goto &$match_text;
286 0         0 goto &{'_match_text'};
  0         0  
287              
288             #return _match_text( $value, $rule );
289             }
290              
291             our $rules;
292              
293             sub _match_text {
294 1000     1000   1817 my ($text, $rule) = @_;
295              
296             ### $text
297             ### $rule
298              
299             #warn "$text, $rule", " is ".$text =~ /$rule/;
300              
301             # пустые правила для проверки существования поля
302 1000 100 66     4285 return 1 if defined $text && !defined $rule;
303              
304 974 50       1782 return unless $text;
305              
306             # return $text =~ qr/$rule/;
307              
308             # if ( $rule =~ tr/()*\./()*\./ ) {
309             # $rule = 0;
310             # }
311              
312             # if ( index( $rule, "qr" ) != 0 ) {
313             # return $text eq $rule;
314             # }
315              
316 974   66     4661 $rule = $rules->{$rule} ||= qr/$rule/;
317              
318             #warn "Don't matches";
319 974         10792 return $text =~ $rule;
320             }
321              
322             #
323             sub match {
324 680     680 0 1128 my ( $me, $processor, $message ) = @_;
325              
326 680 50       1853 if ( not ref $message ) {
327 0         0 die "Message is not ref: $message";
328             }
329              
330 680         1057 my $match_rules = $processor->{match_rules};
331              
332 680 100       1884 if ( _recurse_conditions( \&_match_message, $match_rules, $message ) ) {
333             #print '_recurse_conditions is ok', "\n";
334             #warn _dump ( $match_rules );
335 307         1191 return OK;
336             }
337              
338 373         1415 return NEXT_RULE;
339             }
340              
341             sub process {
342 680     680 0 871 my $args_ref = shift;
343              
344 680         1521 my ( $processor, $message ) = @$args_ref{ qw/processor input/ };
345              
346             #Mail::Lite::Processor::Match->require;
347              
348 680         2176 return __PACKAGE__->match( $processor, $message );
349             }
350              
351             =head1
352              
353             =head2 SYNOPSIS
354              
355             * test
356              
357             =cut
358              
359             1;