File Coverage

blib/lib/Mail/Message/Head/ListGroup.pm
Criterion Covered Total %
statement 106 112 94.6
branch 74 92 80.4
condition 30 48 62.5
subroutine 16 17 94.1
pod 7 8 87.5
total 233 277 84.1


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