| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# This code is part of Perl distribution Mail-Box version 4.01. |
|
2
|
|
|
|
|
|
|
# The POD got stripped from this file by OODoc version 3.05. |
|
3
|
|
|
|
|
|
|
# For contributors see file ChangeLog. |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
# This software is copyright (c) 2001-2025 by Mark Overmeer. |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# This is free software; you can redistribute it and/or modify it under |
|
8
|
|
|
|
|
|
|
# the same terms as the Perl 5 programming language system itself. |
|
9
|
|
|
|
|
|
|
# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
package Mail::Box::Search;{ |
|
13
|
|
|
|
|
|
|
our $VERSION = '4.01'; |
|
14
|
|
|
|
|
|
|
} |
|
15
|
|
|
|
|
|
|
|
|
16
|
2
|
|
|
2
|
|
900
|
use parent 'Mail::Reporter'; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
12
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
2
|
|
|
2
|
|
137
|
use strict; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
47
|
|
|
19
|
2
|
|
|
2
|
|
7
|
use warnings; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
154
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
2
|
|
|
2
|
|
10
|
use Log::Report 'mail-box', import => [ qw/__x error/ ]; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
19
|
|
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
#-------------------- |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub init($) |
|
26
|
12
|
|
|
12
|
0
|
33
|
{ my ($self, $args) = @_; |
|
27
|
|
|
|
|
|
|
|
|
28
|
12
|
|
|
|
|
43
|
$self->SUPER::init($args); |
|
29
|
|
|
|
|
|
|
|
|
30
|
12
|
|
50
|
|
|
67
|
my $in = $args->{in} || 'BODY'; |
|
31
|
12
|
50
|
|
|
|
85
|
@$self{ qw/MBS_check_head MBS_check_body/ } |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
= $in eq 'BODY' ? (0,1) |
|
33
|
|
|
|
|
|
|
: $in eq 'HEAD' ? (1,0) |
|
34
|
|
|
|
|
|
|
: $in eq 'MESSAGE' ? (1,1) |
|
35
|
|
|
|
|
|
|
: error __x"search in BODY, HEAD or MESSAGE, not {what UNKNOWN}.", what => $in; |
|
36
|
|
|
|
|
|
|
|
|
37
|
12
|
50
|
66
|
|
|
87
|
! $self->{MBS_check_head} || $self->can('inHead') or error __x"cannot search in header."; |
|
38
|
12
|
50
|
66
|
|
|
103
|
! $self->{MBS_check_body} || $self->can('inBody') or error __x"cannot search in body."; |
|
39
|
|
|
|
|
|
|
|
|
40
|
12
|
|
|
|
|
29
|
my $deliver = $args->{deliver}; |
|
41
|
|
|
|
|
|
|
$self->{MBS_deliver} |
|
42
|
518
|
|
|
518
|
|
1206
|
= ref $deliver eq 'CODE' ? sub { $deliver->($self, $_[0]) } |
|
43
|
|
|
|
|
|
|
: !defined $deliver ? undef |
|
44
|
0
|
|
|
0
|
|
0
|
: $deliver eq 'DELETE' ? sub { $_[0]->{part}->toplevel->label(deleted => 1) } |
|
45
|
12
|
0
|
|
|
|
73
|
: error __x"don't know how to deliver results in {what UNKNOWN}.", what => $deliver; |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
|
|
47
|
12
|
|
50
|
|
|
216
|
my $logic = $args->{logical} || 'REPLACE'; |
|
48
|
12
|
|
|
|
|
57
|
$self->{MBS_negative} = $logic =~ s/\s*NOT\s*$//; |
|
49
|
12
|
|
|
|
|
113
|
$self->{MBS_logical} = $logic; |
|
50
|
|
|
|
|
|
|
|
|
51
|
12
|
|
|
|
|
48
|
$self->{MBS_label} = $args->{label}; |
|
52
|
12
|
|
100
|
|
|
58
|
$self->{MBS_binaries} = $args->{binaries} || 0; |
|
53
|
12
|
|
100
|
|
|
48
|
$self->{MBS_limit} = $args->{limit} || 0; |
|
54
|
12
|
|
50
|
|
|
53
|
$self->{MBS_decode} = $args->{decode} || 1; |
|
55
|
12
|
|
|
|
|
41
|
$self->{MBS_no_deleted} = not $args->{deleted}; |
|
56
|
12
|
50
|
|
|
|
43
|
$self->{MBS_delayed} = exists $args->{delayed} ? $args->{delayed} : 1; |
|
57
|
12
|
100
|
|
|
|
74
|
$self->{MBS_multiparts} = exists $args->{multiparts} ? $args->{multiparts} : 1; |
|
58
|
|
|
|
|
|
|
|
|
59
|
12
|
|
|
|
|
33
|
$self; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
#-------------------- |
|
63
|
|
|
|
|
|
|
|
|
64
|
63
|
|
|
63
|
1
|
240
|
sub deliver() { $_[0]->{MBS_deliver} } |
|
65
|
25
|
|
|
25
|
1
|
88
|
sub doMultiparts() { $_[0]->{MBS_multiparts} } |
|
66
|
343
|
|
|
343
|
1
|
906
|
sub parseDelayed() { $_[0]->{MBS_delayed} } |
|
67
|
376
|
|
|
376
|
1
|
1824
|
sub skipDeleted() { $_[0]->{MBS_no_deleted} } |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
#-------------------- |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub search(@) |
|
72
|
14
|
|
|
14
|
1
|
42
|
{ my ($self, $object) = @_; |
|
73
|
|
|
|
|
|
|
|
|
74
|
14
|
|
|
|
|
32
|
my $label = $self->{MBS_label}; |
|
75
|
14
|
|
|
|
|
28
|
my $limit = $self->{MBS_limit}; |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
my @messages |
|
78
|
14
|
50
|
|
|
|
189
|
= ref $object eq 'ARRAY' ? @$object |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
: $object->isa('Mail::Box') ? $object->messages |
|
80
|
|
|
|
|
|
|
: $object->isa('Mail::Message') ? ($object) |
|
81
|
|
|
|
|
|
|
: $object->isa('Mail::Box::Thread::Node') ? $object->threadMessages |
|
82
|
|
|
|
|
|
|
: error __x"expect messages to search, not {what UNKNOWN}.", what => $object; |
|
83
|
|
|
|
|
|
|
|
|
84
|
14
|
|
|
|
|
29
|
my $take = 0; |
|
85
|
14
|
100
|
100
|
|
|
138
|
if($limit < 0) { $take = -$limit; @messages = reverse @messages } |
|
|
1
|
50
|
|
|
|
4
|
|
|
|
1
|
100
|
|
|
|
3
|
|
|
86
|
0
|
|
|
|
|
0
|
elsif($limit > 0) { $take = $limit } |
|
87
|
1
|
|
|
|
|
3
|
elsif(!defined $label && !wantarray && !$self->deliver) {$take = 1 } |
|
88
|
|
|
|
|
|
|
|
|
89
|
14
|
|
|
|
|
31
|
my $logic = $self->{MBS_logical}; |
|
90
|
14
|
|
|
|
|
24
|
my @selected; |
|
91
|
14
|
|
|
|
|
20
|
my $count = 0; |
|
92
|
|
|
|
|
|
|
|
|
93
|
14
|
|
|
|
|
32
|
foreach my $message (@messages) |
|
94
|
376
|
100
|
100
|
|
|
1090
|
{ next if $self->skipDeleted && $message->isDeleted; |
|
95
|
343
|
50
|
33
|
|
|
2828
|
next unless $self->parseDelayed || !$message->isDelayed; |
|
96
|
|
|
|
|
|
|
|
|
97
|
343
|
50
|
|
|
|
710
|
my $set = defined $label ? $message->label($label) : 0; |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
my $selected |
|
100
|
|
|
|
|
|
|
= $set && $logic eq 'OR' ? 1 |
|
101
|
|
|
|
|
|
|
: !$set && $logic eq 'AND' ? 0 |
|
102
|
343
|
50
|
33
|
|
|
2027
|
: $self->{MBS_negative} ? ! $self->searchPart($message) |
|
|
|
50
|
33
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
: $self->searchPart($message); |
|
104
|
|
|
|
|
|
|
|
|
105
|
343
|
50
|
|
|
|
921
|
$message->label($label => $selected) if defined $label; |
|
106
|
343
|
100
|
|
|
|
781
|
if($selected) |
|
107
|
167
|
|
|
|
|
310
|
{ push @selected, $message; |
|
108
|
167
|
|
|
|
|
289
|
$count++; |
|
109
|
167
|
100
|
100
|
|
|
572
|
last if $take && $count == $take; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
14
|
100
|
|
|
|
242
|
$limit < 0 ? reverse @selected : @selected; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub searchPart($) |
|
119
|
376
|
|
|
376
|
1
|
835
|
{ my ($self, $part) = @_; |
|
120
|
|
|
|
|
|
|
|
|
121
|
376
|
|
|
|
|
622
|
my $matched = 0; |
|
122
|
|
|
|
|
|
|
$matched = $self->inHead($part, $part->head) |
|
123
|
376
|
100
|
|
|
|
1123
|
if $self->{MBS_check_head}; |
|
124
|
|
|
|
|
|
|
|
|
125
|
376
|
100
|
|
|
|
954
|
return $matched unless $self->{MBS_check_body}; |
|
126
|
335
|
50
|
66
|
|
|
739
|
return $matched if $matched && !$self->deliver; |
|
127
|
|
|
|
|
|
|
|
|
128
|
335
|
|
|
|
|
950
|
my $body = $part->body; |
|
129
|
335
|
|
|
|
|
1570
|
my @bodies; |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
# Handle multipart parts. |
|
132
|
|
|
|
|
|
|
|
|
133
|
335
|
100
|
|
|
|
1341
|
if($body->isMultipart) |
|
|
|
50
|
|
|
|
|
|
|
134
|
25
|
100
|
|
|
|
578
|
{ $self->doMultiparts or return $matched; |
|
135
|
|
|
|
|
|
|
|
|
136
|
24
|
|
|
|
|
146
|
@bodies = ($body->preamble, $body->epilogue); |
|
137
|
|
|
|
|
|
|
|
|
138
|
24
|
|
|
|
|
318
|
foreach my $piece (grep defined, $body->parts) |
|
139
|
33
|
50
|
33
|
|
|
336
|
{ next if $piece->isDelayed && ! $self->parseDelayed; |
|
140
|
|
|
|
|
|
|
|
|
141
|
33
|
|
|
|
|
538
|
$matched += $self->searchPart($piece); |
|
142
|
33
|
50
|
66
|
|
|
175
|
return $matched if $matched && !$self->deliver; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
elsif($body->isNested) |
|
146
|
0
|
0
|
|
|
|
0
|
{ $self->doMultiparts or return $matched; |
|
147
|
0
|
|
|
|
|
0
|
$matched += $self->searchPart($body->nested); |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
else |
|
150
|
310
|
|
|
|
|
762
|
{ @bodies = ($body); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# Handle normal bodies. |
|
154
|
|
|
|
|
|
|
|
|
155
|
334
|
|
|
|
|
913
|
foreach (grep defined, @bodies) |
|
156
|
349
|
100
|
100
|
|
|
1291
|
{ next if !$self->{MBS_binaries} && $_->isBinary; |
|
157
|
326
|
50
|
|
|
|
80969
|
my $body = $self->{MBS_decode} ? $_->decoded : $_; |
|
158
|
326
|
|
|
|
|
375412
|
my $inbody = $self->inBody($part, $body); |
|
159
|
326
|
|
|
|
|
974
|
$matched += $inbody; |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
334
|
|
|
|
|
7219
|
$matched; |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
|
|
0
|
1
|
|
sub inHead(@) { $_[0]->notImplemented } |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
0
|
1
|
|
sub inBody(@) { $_[0]->notImplemented } |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
#-------------------- |
|
172
|
|
|
|
|
|
|
|
|
173
|
0
|
|
|
0
|
1
|
|
sub printMatch($) { $_[0]->notImplemented } |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
1; |