File Coverage

blib/lib/Mail/SPF/Mod.pm
Criterion Covered Total %
statement 25 64 39.0
branch 0 24 0.0
condition 0 3 0.0
subroutine 8 17 47.0
pod 1 6 16.6
total 34 114 29.8


line stmt bran cond sub pod time code
1             #
2             # Mail::SPF::Mod
3             # SPF record modifier class.
4             #
5             # (C) 2005-2012 Julian Mehnle
6             # 2005 Shevek
7             # $Id: Mod.pm 57 2012-01-30 08:15:31Z julian $
8             #
9             ##############################################################################
10              
11             package Mail::SPF::Mod;
12              
13             =head1 NAME
14              
15             Mail::SPF::Mod - SPF record modifier base class
16              
17             =head1 VERSION
18              
19             version 3.20250505
20              
21             =cut
22              
23 1     1   1589 use warnings;
  1         3  
  1         107  
24 1     1   8 use strict;
  1         2  
  1         32  
25              
26 1     1   7 use utf8; # Hack to keep Perl 5.6 from whining about /[\p{}]/.
  1         3  
  1         8  
27              
28 1     1   41 use base 'Mail::SPF::Term';
  1         3  
  1         194  
29              
30 1     1   9 use Mail::SPF::MacroString;
  1         3  
  1         46  
31              
32 1     1   6 use constant TRUE => (0 == 0);
  1         3  
  1         138  
33 1     1   7 use constant FALSE => not TRUE;
  1         2  
  1         99  
34              
35 1     1   7 use constant name_pattern => qr/ ${\__PACKAGE__->SUPER::name_pattern} (?= = ) /x;
  1         2  
  1         1  
  1         1343  
36              
37             =head1 DESCRIPTION
38              
39             An object of class B represents a modifier within an SPF
40             record. Mail::SPF::Mod cannot be instantiated directly. Create an instance of
41             a concrete sub-class instead.
42              
43             =head2 Constructors
44              
45             The following constructors are provided:
46              
47             =over
48              
49             =item B: returns I
50              
51             I. Creates a new SPF record modifier object.
52              
53             %options is a list of key/value pairs representing any of the following
54             options:
55              
56             =over
57              
58             =item B
59              
60             A I denoting the unparsed text of the modifier.
61              
62             =item B
63              
64             A I denoting the name of the modifier. I if a generic
65             I object (as opposed to a specific sub-class) is being
66             constructed.
67              
68             =item B
69              
70             Either a plain I or a I object denoting an
71             optional C parameter of the mechanism.
72              
73             =back
74              
75             =cut
76              
77             sub new {
78 0     0 1   my ($self, %options) = @_;
79 0 0         $self->class ne __PACKAGE__
80             or throw Mail::SPF::EAbstractClass;
81 0           $self = $self->SUPER::new(%options);
82 0 0         $self->{parse_text} = $self->{text} if not defined($self->{parse_text});
83             $self->{domain_spec} = Mail::SPF::MacroString->new(text => $self->{domain_spec})
84             if defined($self->{domain_spec})
85 0 0 0       and not UNIVERSAL::isa($self->{domain_spec}, 'Mail::SPF::MacroString');
86 0           return $self;
87             }
88              
89             =item B: returns I;
90             throws I, I
91              
92             I. Creates a new SPF record modifier object by parsing the string and
93             any options given.
94              
95             =back
96              
97             =head2 Class methods
98              
99             The following class methods are provided:
100              
101             =over
102              
103             =item B: returns I
104              
105             Returns a regular expression that matches any legal modifier name.
106              
107             =back
108              
109             =head2 Instance methods
110              
111             The following instance methods are provided:
112              
113             =over
114              
115             =cut
116              
117             sub parse {
118 0     0 0   my ($self) = @_;
119             defined($self->{parse_text})
120 0 0         or throw Mail::SPF::ENothingToParse('Nothing to parse for modifier');
121 0           $self->parse_name();
122 0           $self->parse_params(TRUE);
123 0           $self->parse_end();
124 0           return;
125             }
126              
127             sub parse_name {
128 0     0 0   my ($self) = @_;
129 0 0         if ($self->{parse_text} =~ s/^(${\$self->name_pattern})=//) {
  0            
130 0           $self->{name} = $1;
131             }
132             else {
133 0           throw Mail::SPF::EInvalidMod(
134             "Unexpected modifier name encountered in '" . $self->text . "'");
135             }
136 0           return;
137             }
138              
139             sub parse_params {
140 0     0 0   my ($self, $required) = @_;
141             # Parse generic macro string of parameters text (should be overridden in sub-classes):
142 0 0         if ($self->{parse_text} =~ s/^(${\$self->macro_string_pattern})$//) {
  0 0          
143 0           $self->{params_text} = $1;
144             }
145             elsif ($required) {
146 0           throw Mail::SPF::EInvalidMacroString(
147             "Invalid macro string encountered in '" . $self->text . "'");
148             }
149 0           return;
150             }
151              
152             sub parse_end {
153 0     0 0   my ($self) = @_;
154 0 0         $self->{parse_text} eq ''
155             or throw Mail::SPF::EJunkInTerm("Junk encountered in modifier '" . $self->text . "'");
156 0           delete($self->{parse_text});
157 0           return;
158             }
159              
160             =item B: returns I; throws I
161              
162             Returns the unparsed text of the modifier. Throws a
163             I exception if the modifier was created
164             synthetically instead of being parsed, and no text was provided.
165              
166             =item B: returns I
167              
168             Returns the name of the modifier.
169              
170             =cut
171              
172             # Read-only accessor:
173             __PACKAGE__->make_accessor('name', TRUE);
174              
175             =item B: returns I
176              
177             I. Returns the modifier's parameters formatted as a string.
178              
179             A sub-class of Mail::SPF::Mod does not have to implement this method if it
180             supports no parameters, although this is highly unlikely.
181              
182             =item B: returns I
183              
184             Formats the modifier's name and parameters as a string and returns it. You can
185             simply use a Mail::SPF::Mod object as a string for the same effect, see
186             L<"OVERLOADING">.
187              
188             =cut
189              
190             sub stringify {
191 0     0 0   my ($self) = @_;
192 0 0         my $params = $self->can('params') ? $self->params : undef;
193 0 0         return sprintf(
194             '%s=%s',
195             $self->name,
196             defined($params) ? $params : ''
197             );
198             }
199              
200             =item B: throws I, I,
201             I
202              
203             I. Processes the modifier. What that means depends on the actual
204             implementation in sub-classes. See L below.
205              
206             This method is abstract and must be implemented by sub-classes of
207             Mail::SPF::Mod.
208              
209             =back
210              
211             =head1 MODIFIER TYPES
212              
213             There are different basic types of modifiers, which are described below. All
214             of them are provided by the B module.
215              
216             =head2 Global modifiers - B
217              
218             B (RFC 4408) only knows "global" modifiers. A global modifier may
219             appear anywhere in an SPF record, but only once. During evaluation of the
220             record, global modifiers are processed after the last mechanism has been
221             evaluated and an SPF result has been determined.
222              
223             =cut
224              
225             package Mail::SPF::GlobalMod;
226             our @ISA = 'Mail::SPF::Mod';
227              
228             sub new {
229 0     0     my ($self, %options) = @_;
230 0 0         $self->class ne __PACKAGE__
231             or throw Mail::SPF::EAbstractClass;
232 0           return $self->SUPER::new(%options);
233             }
234              
235             =pod
236              
237             The following additional class method is provided by B:
238              
239             =over
240              
241             =item B: returns I
242              
243             I. Returns a I number between B<0> and B<1> denoting the
244             precedence of the type of the global modifier. Global modifiers present in an
245             SPF record are processed in the order of their precedence values, B<0> meaning
246             "first".
247              
248             This method is abstract and must be implemented by sub-classes of
249             Mail::SPF::GlobalMod.
250              
251             =back
252              
253             The following specific instance method is provided by B:
254              
255             =over
256              
257             =item B: throws I
258              
259             I. Processes the modifier. What that means depends on the actual
260             implementation in sub-classes. Takes both a I and a
261             I object. As global modifiers are generally processed
262             I an SPF result has already been determined, takes also the current
263             I. If the modifier wishes to modify the SPF result, it may
264             throw a different I object.
265              
266             This method is abstract and must be implemented by sub-classes of
267             Mail::SPF::GlobalMod.
268              
269             =back
270              
271             =head2 Positional modifiers - B
272              
273             B (RFC 4406) introduces the concept of "positional" modifiers.
274             According to RFC 4406, a positional modifier must follow a mechanism and
275             applies to that, and only that, mechanism. However, because this definition is
276             not very useful, and because no positional modifiers have been defined based on
277             it as of yet, B deviates from RFC 4406 as follows:
278              
279             A positional modifier may appear anywhere in an SPF record, and it is stateful,
280             i.e. it applies to all mechanisms and modifiers that follow it. Positional
281             modifiers are generally multiple, i.e. they may appear any number of times
282             throughout the record. During evaluation of the record, positional modifiers
283             are processed at exactly the time when they are encountered by the evaluator.
284             Consequently, all positional modifiers are processed before an SPF result is
285             determined.
286              
287             =cut
288              
289             package Mail::SPF::PositionalMod;
290             our @ISA = 'Mail::SPF::Mod';
291              
292             sub new {
293 0     0     my ($self, %options) = @_;
294 0 0         $self->class ne __PACKAGE__
295             or throw Mail::SPF::EAbstractClass;
296 0           return $self->SUPER::new(%options);
297             }
298              
299             =pod
300              
301             The following specific instance method is provided by
302             B:
303              
304             =over
305              
306             =item B: throws I, I
307              
308             I. Processes the modifier. What that means depends on the actual
309             implementation in sub-classes. Takes both a I and a
310             I object. As global modifiers are generally processed
311             I an SPF result has been determined, no result object is available to
312             the modifier. The modifier can (at least at this time) not directly modify the
313             final SPF result, however it may throw an exception to signal an error
314             condition.
315              
316             This method is abstract and must be implemented by sub-classes of
317             Mail::SPF::PositionalMod.
318              
319             =back
320              
321             =head2 Unknown modifiers - B
322              
323             Both B and B allow unknown modifiers to appear in SPF records
324             in order to allow new modifiers to be introduced without breaking existing
325             implementations. Obviously, unknown modifiers are neither global nor
326             positional, but they may appear any number of times throughout the record and
327             are simply ignored during evaluation of the record.
328              
329             =cut
330              
331             package Mail::SPF::UnknownMod;
332             our @ISA = 'Mail::SPF::Mod';
333              
334             =pod
335              
336             Also obviously, B does not support a C method.
337              
338             The following specific instance method is provided by
339             B:
340              
341             =over
342              
343             =item B: returns I
344              
345             Returns the modifier's unparsed value as a string.
346              
347             =cut
348              
349             sub params {
350 0     0     my ($self) = @_;
351 0           return $self->{params_text};
352             }
353              
354             =back
355              
356             =cut
357              
358             package Mail::SPF::Mod;
359              
360             =head1 OVERLOADING
361              
362             If a Mail::SPF::Mod object is used as a I, the C method is
363             used to convert the object into a string.
364              
365             =head1 SEE ALSO
366              
367             L, L
368              
369             L, L, L
370              
371             L
372              
373             For availability, support, and license information, see the README file
374             included with Mail::SPF.
375              
376             =head1 AUTHORS
377              
378             Julian Mehnle , Shevek
379              
380             =cut
381              
382             TRUE;