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