line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyrights 2001-2023 by [Mark Overmeer ]. |
2
|
|
|
|
|
|
|
# For other contributors see ChangeLog. |
3
|
|
|
|
|
|
|
# See the manual pages for details on the licensing terms. |
4
|
|
|
|
|
|
|
# Pod stripped from pm file by OODoc 2.03. |
5
|
|
|
|
|
|
|
# This code is part of distribution Mail-Message. Meta-POD processed with |
6
|
|
|
|
|
|
|
# OODoc into POD and HTML manual-pages. See README.md |
7
|
|
|
|
|
|
|
# Copyright Mark Overmeer. Licensed under the same terms as Perl itself. |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
package Mail::Message::Head::ListGroup; |
10
|
2
|
|
|
2
|
|
1616
|
use vars '$VERSION'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
122
|
|
11
|
|
|
|
|
|
|
$VERSION = '3.013'; |
12
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
12
|
use base 'Mail::Message::Head::FieldGroup'; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
562
|
|
14
|
|
|
|
|
|
|
|
15
|
2
|
|
|
2
|
|
14
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
39
|
|
16
|
2
|
|
|
2
|
|
13
|
use warnings; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
50
|
|
17
|
|
|
|
|
|
|
|
18
|
2
|
|
|
2
|
|
11
|
use List::Util 'first'; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
4094
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
sub init($$) |
22
|
0
|
|
|
0
|
0
|
|
{ my ($self, $args) = @_; |
23
|
0
|
|
|
|
|
|
$self->SUPER::init($args); |
24
|
|
|
|
|
|
|
|
25
|
0
|
|
|
|
|
|
my $address = $args->{address}; |
26
|
0
|
0
|
0
|
|
|
|
if(!defined $address) { ; } |
|
|
0
|
|
|
|
|
|
27
|
|
|
|
|
|
|
elsif(!ref $address || !$address->isa('Mail::Message::Field::Address')) |
28
|
0
|
|
|
|
|
|
{ require Mail::Message::Field::Address; |
29
|
0
|
|
|
|
|
|
my $mi = Mail::Message::Field::Address->coerce($address); |
30
|
|
|
|
|
|
|
|
31
|
0
|
0
|
|
|
|
|
defined $mi |
32
|
|
|
|
|
|
|
or $self->log(ERROR => "Cannot convert \"$address\" into an address object"), return; |
33
|
|
|
|
|
|
|
|
34
|
0
|
|
|
|
|
|
$address = $mi; |
35
|
|
|
|
|
|
|
} |
36
|
0
|
0
|
|
|
|
|
$self->{MMHL_address} = $address if defined $args->{address}; |
37
|
|
|
|
|
|
|
|
38
|
0
|
0
|
|
|
|
|
$self->{MMHL_listname} = $args->{listname} if defined $args->{listname}; |
39
|
0
|
0
|
|
|
|
|
$self->{MMHL_rfc} = $args->{rfc} if defined $args->{rfc}; |
40
|
0
|
|
|
|
|
|
$self->{MMHL_fns} = []; |
41
|
0
|
|
|
|
|
|
$self; |
42
|
|
|
|
|
|
|
} |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
#------------------------------------------ |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub from($) |
48
|
0
|
|
|
0
|
1
|
|
{ my ($class, $from) = @_; |
49
|
0
|
0
|
|
|
|
|
my $head = $from->isa('Mail::Message::Head') ? $from : $from->head; |
50
|
0
|
|
|
|
|
|
my $self = $class->new(head => $head); |
51
|
|
|
|
|
|
|
|
52
|
0
|
0
|
|
|
|
|
return () unless $self->collectFields; |
53
|
|
|
|
|
|
|
|
54
|
0
|
|
|
|
|
|
my ($type, $software, $version, $field); |
55
|
0
|
0
|
0
|
|
|
|
if(my $communigate = $head->get('X-ListServer')) |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
{ ($software, $version) = $communigate =~ m/^(.*)\s+LIST\s*([\d.]+)\s*$/i; |
57
|
0
|
0
|
|
|
|
|
$type = ($software =~ m/Pro/ ? 'CommuniGatePro' : 'CommuniGate'); |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
elsif(my $mailman = $head->get('X-Mailman-Version')) |
60
|
0
|
|
|
|
|
|
{ $version = "$mailman"; |
61
|
0
|
|
|
|
|
|
$type = 'Mailman'; |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
elsif(my $majordomo = $head->get('X-Majordomo-Version')) |
64
|
0
|
|
|
|
|
|
{ $version = "$majordomo"; |
65
|
0
|
|
|
|
|
|
$type = 'Majordomo'; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
elsif(my $ecartis = $head->get('X-Ecartis-Version')) |
68
|
0
|
|
|
|
|
|
{ ($software, $version) = $ecartis =~ m/^(.*)\s+(v[\d.]+)/; |
69
|
0
|
|
|
|
|
|
$type = 'Ecartis'; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
elsif(my $listar = $head->get('X-Listar-Version')) |
72
|
0
|
|
|
|
|
|
{ ($software, $version) = $listar =~ m/^(.*?)\s+(v[\w.]+)/; |
73
|
0
|
|
|
|
|
|
$type = 'Listar'; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
elsif(defined($field = $head->get('List-Software')) |
76
|
|
|
|
|
|
|
&& $field =~ m/listbox/i) |
77
|
0
|
|
|
|
|
|
{ ($software, $version) = $field =~ m/^(\S*)\s*(v[\d.]+)\s*$/; |
78
|
0
|
|
|
|
|
|
$type = 'Listbox'; |
79
|
|
|
|
|
|
|
} |
80
|
0
|
|
|
0
|
|
|
elsif($field = first { m!LISTSERV-TCP/IP!s } $head->get('Received')) |
81
|
|
|
|
|
|
|
{ # Listserv is hard to recognise |
82
|
0
|
|
|
|
|
|
($software, $version) = $field =~ |
83
|
|
|
|
|
|
|
m!\( (LISTSERV-TCP/IP) \s+ release \s+ (\S+) \)!xs; |
84
|
0
|
|
|
|
|
|
$type = 'Listserv'; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
elsif(defined($field = $head->get('X-Mailing-List')) |
87
|
|
|
|
|
|
|
&& $field =~ m[archive/latest]) |
88
|
0
|
|
|
|
|
|
{ $type = 'Smartlist' } |
89
|
|
|
|
|
|
|
elsif(defined($field = $head->get('Mailing-List')) && $field =~ m/yahoo/i ) |
90
|
0
|
|
|
|
|
|
{ $type = 'YahooGroups' } |
91
|
|
|
|
|
|
|
elsif(defined($field) && $field =~ m/(ezmlm)/i ) |
92
|
0
|
|
|
|
|
|
{ $type = 'Ezmlm' } |
93
|
|
|
|
|
|
|
elsif(my $fml = $head->get('X-MLServer')) |
94
|
0
|
|
|
|
|
|
{ ($software, $version) = $fml =~ m/^\s*(\S+)\s*\[\S*\s*([^\]]*?)\s*\]/; |
95
|
0
|
|
|
|
|
|
$type = 'FML'; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
elsif(defined($field = $head->get('List-Subscribe') |
98
|
|
|
|
|
|
|
|| $head->get('List-Unsubscribe')) |
99
|
|
|
|
|
|
|
&& $field =~ m/sympa/i) |
100
|
0
|
|
|
|
|
|
{ $type = 'Sympa' } |
101
|
0
|
|
|
0
|
|
|
elsif(first { m/majordom/i } $head->get('Received')) |
102
|
|
|
|
|
|
|
{ # Majordomo is hard to recognize |
103
|
0
|
|
|
|
|
|
$type = "Majordomo"; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
elsif($field = $head->get('List-ID') && $field =~ m/listbox\.com/i) |
106
|
0
|
|
|
|
|
|
{ $type = "Listbox" } |
107
|
|
|
|
|
|
|
|
108
|
0
|
|
|
|
|
|
$self->detected($type, $software, $version); |
109
|
0
|
|
|
|
|
|
$self; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
#------------------------------------------ |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub rfc() |
116
|
0
|
|
|
0
|
1
|
|
{ my $self = shift; |
117
|
0
|
0
|
|
|
|
|
return $self->{MMHL_rfc} if defined $self->{MMHL_rfc}; |
118
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
my $head = $self->head; |
120
|
0
|
0
|
|
|
|
|
defined $head->get('List-Post') ? 'rfc2369' |
|
|
0
|
|
|
|
|
|
121
|
|
|
|
|
|
|
: defined $head->get('List-Id') ? 'rfc2919' |
122
|
|
|
|
|
|
|
: undef; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
#------------------------------------------ |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub address() |
129
|
0
|
|
|
0
|
1
|
|
{ my $self = shift; |
130
|
0
|
0
|
|
|
|
|
return $self->{MMHL_address} if exists $self->{MMHL_address}; |
131
|
|
|
|
|
|
|
|
132
|
0
|
|
0
|
|
|
|
my $type = $self->type || 'Unknown'; |
133
|
0
|
|
|
|
|
|
my $head = $self->head; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my ($field, $address); |
136
|
0
|
0
|
0
|
|
|
|
if($type eq 'Smartlist' && defined($field = $head->get('X-Mailing-List'))) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
137
|
0
|
0
|
|
|
|
|
{ $address = $1 if $field =~ m/\<([^>]+)\>/ } |
138
|
|
|
|
|
|
|
elsif($type eq 'YahooGroups') |
139
|
0
|
|
|
|
|
|
{ $address = $head->get('X-Apparently-To')->unfoldedBody } |
140
|
|
|
|
|
|
|
elsif($type eq 'Listserv') |
141
|
0
|
|
|
|
|
|
{ $address = $head->get('Sender') } |
142
|
|
|
|
|
|
|
|
143
|
0
|
|
0
|
|
|
|
$address ||= $head->get('List-Post') || $head->get('Reply-To') |
|
|
|
0
|
|
|
|
|
144
|
|
|
|
|
|
|
|| $head->get('Sender'); |
145
|
0
|
0
|
|
|
|
|
$address = $address->study if ref $address; |
146
|
|
|
|
|
|
|
|
147
|
0
|
0
|
|
|
|
|
if(!defined $address) { ; } |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
148
|
|
|
|
|
|
|
elsif(!ref $address) |
149
|
0
|
|
|
|
|
|
{ $address =~ s/\bowner-|-(?:owner|bounce|admin)\@//i; |
150
|
0
|
|
|
|
|
|
$address = Mail::Message::Field::Address->new(address => $address); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
elsif($address->isa('Mail::Message::Field::Addresses')) |
153
|
|
|
|
|
|
|
{ # beautify |
154
|
0
|
|
|
|
|
|
$address = ($address->addresses)[0]; |
155
|
0
|
0
|
|
|
|
|
my $username = defined $address ? $address->username : ''; |
156
|
0
|
0
|
|
|
|
|
if($username =~ s/^owner-|-(owner|bounce|admin)$//i) |
157
|
0
|
|
|
|
|
|
{ $address = Mail::Message::Field::Address->new |
158
|
|
|
|
|
|
|
(username => $username, domain => $address->domain); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
elsif($address->isa('Mail::Message::Field::URIs')) |
162
|
0
|
|
|
0
|
|
|
{ my $uri = first { $_->scheme eq 'mailto' } $address->URIs; |
|
0
|
|
|
|
|
|
|
163
|
0
|
0
|
|
|
|
|
$address = defined $uri |
164
|
|
|
|
|
|
|
? Mail::Message::Field::Address->new(address => $uri->to) |
165
|
|
|
|
|
|
|
: undef; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
else # Don't understand life anymore :-( |
168
|
0
|
|
|
|
|
|
{ undef $address; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
0
|
|
|
|
|
|
$self->{MMHL_address} = $address; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
#------------------------------------------ |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub listname() |
178
|
0
|
|
|
0
|
1
|
|
{ my $self = shift; |
179
|
0
|
0
|
|
|
|
|
return $self->{MMHL_listname} if exists $self->{MMHL_listname}; |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
my $head = $self->head; |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# Some lists have a field with the name only |
184
|
0
|
|
0
|
|
|
|
my $list = $head->get('List-ID') || $head->get('X-List') |
185
|
|
|
|
|
|
|
|| $head->get('X-ML-Name'); |
186
|
|
|
|
|
|
|
|
187
|
0
|
|
|
|
|
|
my $listname; |
188
|
0
|
0
|
|
|
|
|
if(defined $list) |
|
|
0
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
{ $listname = $list->study->decodedBody; |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
elsif(my $address = $self->address) |
192
|
0
|
|
0
|
|
|
|
{ $listname = $address->phrase || $address->address; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
$self->{MMHL_listname} = $listname; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
#------------------------------------------ |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
my $list_field_names |
202
|
|
|
|
|
|
|
= qr/ ^ (?: List|X-Envelope|X-Original ) - |
203
|
|
|
|
|
|
|
| ^ (?: Precedence|Mailing-List|Approved-By ) $ |
204
|
|
|
|
|
|
|
| ^ X-(?: Loop|BeenThere|Sequence|List|Sender|MLServer ) $ |
205
|
|
|
|
|
|
|
| ^ X-(?: Mailman|Listar|Egroups|Encartis|ML ) - |
206
|
|
|
|
|
|
|
| ^ X-(?: Archive|Mailing|Original|Mail|ListServer ) - |
207
|
|
|
|
|
|
|
| ^ (?: Mail-Followup|Delivered|Errors|X-Apperently ) -To $ |
208
|
|
|
|
|
|
|
/xi; |
209
|
|
|
|
|
|
|
|
210
|
0
|
|
|
0
|
1
|
|
sub isListGroupFieldName($) { $_[1] =~ $list_field_names } |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
#------------------------------------------ |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
sub collectFields() |
216
|
0
|
|
|
0
|
1
|
|
{ my $self = shift; |
217
|
0
|
|
|
|
|
|
my @names = map { $_->name } $self->head->grepNames($list_field_names); |
|
0
|
|
|
|
|
|
|
218
|
0
|
|
|
|
|
|
$self->addFields(@names); |
219
|
0
|
|
|
|
|
|
@names; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
#------------------------------------------ |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub details() |
226
|
0
|
|
|
0
|
1
|
|
{ my $self = shift; |
227
|
0
|
|
0
|
|
|
|
my $type = $self->type || 'Unknown'; |
228
|
|
|
|
|
|
|
|
229
|
0
|
|
|
|
|
|
my $software = $self->software; |
230
|
0
|
0
|
0
|
|
|
|
undef $software if defined($software) && $type eq $software; |
231
|
0
|
|
|
|
|
|
my $version = $self->version; |
232
|
0
|
0
|
|
|
|
|
my $release |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
233
|
|
|
|
|
|
|
= defined $software |
234
|
|
|
|
|
|
|
? (defined $version ? " ($software $version)" : " ($software)") |
235
|
|
|
|
|
|
|
: (defined $version ? " ($version)" : ''); |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
0
|
|
|
|
my $address = $self->address || 'unknown address'; |
238
|
0
|
|
|
|
|
|
my $fields = scalar $self->fields; |
239
|
0
|
|
|
|
|
|
"$type at $address$release, $fields fields"; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
#------------------------------------------ |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
1; |