line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
4
|
|
|
4
|
|
57409
|
use warnings; |
|
4
|
|
|
|
|
15
|
|
|
4
|
|
|
|
|
119
|
|
2
|
4
|
|
|
4
|
|
37
|
use strict; |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
494
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Mail::IMAPClient::MessageSet; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Mail::IMAPClient::MessageSet - ranges of message sequence numbers |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=cut |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
use overload |
13
|
|
|
|
|
|
|
'""' => "str" |
14
|
1
|
|
|
1
|
|
4
|
, '.=' => sub {$_[0]->cat($_[1])} |
15
|
0
|
|
|
0
|
|
0
|
, '+=' => sub {$_[0]->cat($_[1])} |
16
|
1
|
|
|
1
|
|
4
|
, '-=' => sub {$_[0]->rem($_[1])} |
17
|
4
|
|
|
|
|
39
|
, '@{}' => "unfold" |
18
|
4
|
|
|
4
|
|
4578
|
, fallback => 1; |
|
4
|
|
|
|
|
3700
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new |
21
|
1
|
|
|
1
|
1
|
72
|
{ my $class = shift; |
22
|
1
|
|
|
|
|
4
|
my $range = $class->range(@_); |
23
|
1
|
|
|
|
|
4
|
bless \$range, $class; |
24
|
|
|
|
|
|
|
} |
25
|
|
|
|
|
|
|
|
26
|
3
|
|
|
3
|
0
|
721
|
sub str { overload::StrVal( ${$_[0]} ) } |
|
3
|
|
|
|
|
12
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub _unfold_range($) |
29
|
|
|
|
|
|
|
# { my $x = shift; return if $x =~ m/[^0-9,:]$/; $x =~ s/\:/../g; eval $x; } |
30
|
36
|
100
|
|
36
|
|
60
|
{ map { /(\d+)\s*\:\s*(\d+)/ ? ($1..$2) : $_ } |
|
60
|
|
|
|
|
267
|
|
31
|
|
|
|
|
|
|
split /\,/, shift; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub rem |
35
|
1
|
|
|
1
|
0
|
2
|
{ my $self = shift; |
36
|
1
|
|
|
|
|
3
|
my %delete = map { ($_ => 1) } map { _unfold_range $_ } @_; |
|
2
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
3
|
|
37
|
1
|
|
|
|
|
3
|
$$self = $self->range(grep {not $delete{$_}} $self->unfold); |
|
30
|
|
|
|
|
48
|
|
38
|
1
|
|
|
|
|
5
|
$self; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
sub cat |
42
|
1
|
|
|
1
|
0
|
2
|
{ my $self = shift; |
43
|
1
|
|
|
|
|
4
|
$$self = $self->range($$self, @_); |
44
|
1
|
|
|
|
|
3
|
$self; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub range |
48
|
3
|
|
|
3
|
0
|
6
|
{ my $self = shift; |
49
|
|
|
|
|
|
|
|
50
|
3
|
|
|
|
|
5
|
my @msgs; |
51
|
3
|
|
|
|
|
6
|
foreach my $m (@_) |
52
|
31
|
50
|
33
|
|
|
84
|
{ defined $m && length $m |
53
|
|
|
|
|
|
|
or next; |
54
|
|
|
|
|
|
|
|
55
|
31
|
50
|
|
|
|
47
|
foreach my $mm (ref $m eq 'ARRAY' ? @$m : $m) |
56
|
31
|
|
|
|
|
42
|
{ push @msgs, _unfold_range $mm; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
@msgs |
61
|
3
|
50
|
|
|
|
7
|
or return undef; |
62
|
|
|
|
|
|
|
|
63
|
3
|
|
|
|
|
11
|
@msgs = sort {$a <=> $b} @msgs; |
|
153
|
|
|
|
|
160
|
|
64
|
3
|
|
|
|
|
5
|
my $low = my $high = shift @msgs; |
65
|
|
|
|
|
|
|
|
66
|
3
|
|
|
|
|
5
|
my @ranges; |
67
|
3
|
|
|
|
|
4
|
foreach my $m (@msgs) |
68
|
84
|
100
|
|
|
|
115
|
{ next if $m == $high; # double |
69
|
|
|
|
|
|
|
|
70
|
75
|
100
|
|
|
|
94
|
if($m == $high + 1) { $high = $m } |
|
65
|
|
|
|
|
74
|
|
71
|
|
|
|
|
|
|
else |
72
|
10
|
50
|
|
|
|
21
|
{ push @ranges, $low == $high ? $low : "$low:$high"; |
73
|
10
|
|
|
|
|
12
|
$low = $high = $m; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
3
|
50
|
|
|
|
8
|
push @ranges, $low == $high ? $low : "$low:$high" ; |
78
|
3
|
|
|
|
|
14
|
join ",", @ranges; |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub unfold |
82
|
4
|
|
|
4
|
1
|
987
|
{ my $self = shift; |
83
|
4
|
50
|
|
|
|
17
|
wantarray ? ( _unfold_range $$self ) : [ _unfold_range $$self ]; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head1 SYNOPSIS |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
my @msgs = $imap->search("SUBJECT","Virus"); # returns 1,3,4,5,6,9,10 |
89
|
|
|
|
|
|
|
my $msgset = Mail::IMAPClient::MessageSet->new(@msgs); |
90
|
|
|
|
|
|
|
print $msgset; # prints "1,3:6,9:10" |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# add message 14 to the set: |
93
|
|
|
|
|
|
|
$msgset += 14; |
94
|
|
|
|
|
|
|
print $msgset; # prints "1,3:6,9:10,14" |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# add messages 16,17,18,19, and 20 to the set: |
97
|
|
|
|
|
|
|
$msgset .= "16,17,18:20"; |
98
|
|
|
|
|
|
|
print $msgset; # prints "1,3:6,9:10,14,16:20" |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Hey, I didn't really want message 17 in there; let's take it out: |
101
|
|
|
|
|
|
|
$msgset -= 17; |
102
|
|
|
|
|
|
|
print $msgset; # prints "1,3:6,9:10,14,16,18:20" |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# Now let's iterate over each message: |
105
|
|
|
|
|
|
|
for my $msg (@$msgset) |
106
|
|
|
|
|
|
|
{ print "$msg\n"; # Prints: "1\n3\n4\n5\n6..16\n18\n19\n20\n" |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
print join("\n", @$msgset)."\n"; # same simpler |
109
|
|
|
|
|
|
|
local $" = "\n"; print "@$msgset\n"; # even more simple |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
=head1 DESCRIPTION |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
The B module is designed to make life easier |
114
|
|
|
|
|
|
|
for programmers who need to manipulate potentially large sets of IMAP |
115
|
|
|
|
|
|
|
message UID's or sequence numbers. |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
This module presents an object-oriented interface into handling your |
118
|
|
|
|
|
|
|
message sets. The object reference returned by the L method is an |
119
|
|
|
|
|
|
|
overloaded reference to a scalar variable that contains the message set's |
120
|
|
|
|
|
|
|
compact RFC2060 representation. The object is overloaded so that using |
121
|
|
|
|
|
|
|
it like a string returns this compact message set representation. You |
122
|
|
|
|
|
|
|
can also add messages to the set (using either a '.=' operator or a '+=' |
123
|
|
|
|
|
|
|
operator) or remove messages (with the '-=' operator). And if you use |
124
|
|
|
|
|
|
|
it as an array reference, it will humor you and act like one by calling |
125
|
|
|
|
|
|
|
L for you. |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
RFC2060 specifies that multiple messages can be provided to certain IMAP |
128
|
|
|
|
|
|
|
commands by separating them with commas. For example, "1,2,3,4,5" would |
129
|
|
|
|
|
|
|
specify messages 1, 2, 3, 4, and (you guessed it!) 5. However, if you are |
130
|
|
|
|
|
|
|
performing an operation on lots of messages, this string can get quite long. |
131
|
|
|
|
|
|
|
So long that it may slow down your transaction, and perhaps even cause the |
132
|
|
|
|
|
|
|
server to reject it. So RFC2060 also permits you to specify a range of |
133
|
|
|
|
|
|
|
messages, so that messages 1, 2, 3, 4 and 5 can also be specified as |
134
|
|
|
|
|
|
|
"1:5". |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
This is where B comes in. It will convert |
137
|
|
|
|
|
|
|
your message set into the shortest correct syntax. This could potentially |
138
|
|
|
|
|
|
|
save you tons of network I/O, as in the case where you want to fetch the |
139
|
|
|
|
|
|
|
flags for all messages in a 10000 message folder, where the messages |
140
|
|
|
|
|
|
|
are all numbered sequentially. Delimited as commas, and making the |
141
|
|
|
|
|
|
|
best-case assumption that the first message is message "1", it would take |
142
|
|
|
|
|
|
|
48893 bytes to specify the whole message set using the comma-delimited |
143
|
|
|
|
|
|
|
method. To specify it as a range, it takes just seven bytes (1:10000). |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Note that the L B method can be used as |
146
|
|
|
|
|
|
|
a short-cut to specifying Cnew(@etc)>.) |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head1 CLASS METHODS |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
The only class method you need to worry about is B. And if you create |
151
|
|
|
|
|
|
|
your B objects via L's |
152
|
|
|
|
|
|
|
B method then you don't even need to worry about B. |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=head2 new |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Example: |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
my $msgset = Mail::IMAPClient::MessageSet->new(@msgs); |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
The B method requires at least one argument. That argument can be |
161
|
|
|
|
|
|
|
either a message, a comma-separated list of messages, a colon-separated |
162
|
|
|
|
|
|
|
range of messages, or a combination of comma-separated messages and |
163
|
|
|
|
|
|
|
colon-separated ranges. It can also be a reference to an array of messages, |
164
|
|
|
|
|
|
|
comma-separated message lists, and colon separated ranges. |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
If more then one argument is supplied to B, then those arguments should |
167
|
|
|
|
|
|
|
be more message numbers, lists, and ranges (or references to arrays of them) |
168
|
|
|
|
|
|
|
just as in the first argument. |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
The message numbers passed to B can really be any kind of number at |
171
|
|
|
|
|
|
|
all but to be useful in a L session they should be either |
172
|
|
|
|
|
|
|
message UID's (if your I parameter is true) or message sequence numbers. |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
The B method will return a reference to a B |
175
|
|
|
|
|
|
|
object. That object, when double quoted, will act just like a string whose |
176
|
|
|
|
|
|
|
value is the message set expressed in the shortest possible way, with the |
177
|
|
|
|
|
|
|
message numbers sorted in ascending order and with duplicates removed. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 OBJECT METHODS |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
The only object method currently available to a B |
182
|
|
|
|
|
|
|
object is the L method. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
=head2 unfold |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
Example: |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $msgset = $imap->Range( $imap->messages ) ; |
189
|
|
|
|
|
|
|
my @all_messages = $msgset->unfold; |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
The B method returns an array of messages that belong to the |
192
|
|
|
|
|
|
|
message set. If called in a scalar context it returns a reference to the |
193
|
|
|
|
|
|
|
array instead. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head1 OVERRIDDEN OPERATIONS |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
B overrides a number of operators in order |
198
|
|
|
|
|
|
|
to make manipulating your message sets easier. The overridden operations are: |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head2 stringify |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Attempts to stringify a B object will result in |
203
|
|
|
|
|
|
|
the compact message specification being returned, which is almost certainly |
204
|
|
|
|
|
|
|
what you will want. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=head2 Auto-increment |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
Attempts to autoincrement a B object will |
209
|
|
|
|
|
|
|
result in a message (or messages) being added to the object's message set. |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Example: |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
$msgset += 34; |
214
|
|
|
|
|
|
|
# Message #34 is now in the message set |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head2 Concatenate |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Attempts to concatenate to a B object will |
219
|
|
|
|
|
|
|
result in a message (or messages) being added to the object's message set. |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
Example: |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
$msgset .= "34,35,36,40:45"; |
224
|
|
|
|
|
|
|
# Messages 34,35,36,40,41,42,43,44,and 45 are now in the message set |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
The C<.=> operator and the C<+=> operator can be used interchangeably, but |
227
|
|
|
|
|
|
|
as you can see by looking at the examples there are times when use of one |
228
|
|
|
|
|
|
|
has an aesthetic advantage over use of the other. |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=head2 Autodecrement |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
Attempts to autodecrement a B object will |
233
|
|
|
|
|
|
|
result in a message being removed from the object's message set. |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Examples: |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
$msgset -= 34; |
238
|
|
|
|
|
|
|
# Message #34 is no longer in the message set |
239
|
|
|
|
|
|
|
$msgset -= "1:10"; |
240
|
|
|
|
|
|
|
# Messages 1 through 10 are no longer in the message set |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
If you attempt to remove a message that was not in the original message set |
243
|
|
|
|
|
|
|
then your resulting message set will be the same as the original, only more |
244
|
|
|
|
|
|
|
expensive. However, if you attempt to remove several messages from the message |
245
|
|
|
|
|
|
|
set and some of those messages were in the message set and some were not, |
246
|
|
|
|
|
|
|
the additional overhead of checking for the messages that were not there |
247
|
|
|
|
|
|
|
is negligible. In either case you get back the message set you want regardless |
248
|
|
|
|
|
|
|
of whether it was already like that or not. |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head1 AUTHOR |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
David J. Kernen |
253
|
|
|
|
|
|
|
The Kernen Consulting Group, Inc |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=head1 COPYRIGHT |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Copyright 1999, 2000, 2001, 2002 The Kernen Group, Inc. |
258
|
|
|
|
|
|
|
All rights reserved. |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it |
261
|
|
|
|
|
|
|
under the terms of either: |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=over 4 |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
=item a) the "Artistic License" which comes with this Kit, or |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
=item b) the GNU General Public License as published by the Free Software |
268
|
|
|
|
|
|
|
Foundation; either version 1, or (at your option) any later version. |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=back |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, but |
273
|
|
|
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of |
274
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU |
275
|
|
|
|
|
|
|
General Public License or the Artistic License for more details. All your |
276
|
|
|
|
|
|
|
base are belong to us. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=cut |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
1; |