File Coverage

blib/lib/Validate/SPF/Parser.pm
Criterion Covered Total %
statement 112 169 66.2
branch 40 72 55.5
condition 4 12 33.3
subroutine 15 25 60.0
pod n/a
total 171 278 61.5


line stmt bran cond sub pod time code
1             package Validate::SPF::Parser;
2              
3             # ABSTRACT: SPF v1 parser implementation
4              
5             ####################################################################
6             #
7             # This file was generated using Parse::Yapp version 1.05.
8             #
9             # Don't edit this file, use source file instead.
10             #
11             # ANY CHANGE MADE HERE WILL BE LOST !
12             #
13             ####################################################################
14              
15 13     13   1015382 use strict;
  13         26  
  13         422  
16 13     13   54 use warnings;
  13         17  
  13         611  
17              
18             our $VERSION = '0.005'; # VERSION
19             our $AUTHORITY = 'cpan:CHIM'; # AUTHORITY
20              
21 13     13   57 use vars qw ( @ISA );
  13         16  
  13         1019  
22              
23             @ISA = qw( Parse::Yapp::Driver );
24              
25             #Included Parse/Yapp/Driver.pm file----------------------------------------
26             {
27             #
28             # Module Parse::Yapp::Driver
29             #
30             # This module is part of the Parse::Yapp package available on your
31             # nearest CPAN
32             #
33             # Any use of this module in a standalone parser make the included
34             # text under the same copyright as the Parse::Yapp module itself.
35             #
36             # This notice should remain unchanged.
37             #
38             # (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved.
39             # (see the pod text in Parse::Yapp module for use and distribution rights)
40             #
41              
42             package Parse::Yapp::Driver;
43              
44             require 5.004;
45              
46 13     13   63 use strict;
  13         14  
  13         385  
47              
48 13     13   55 use vars qw ( $VERSION $COMPATIBLE $FILENAME );
  13         18  
  13         748  
49              
50             $VERSION = '1.05';
51             $COMPATIBLE = '0.07';
52             $FILENAME=__FILE__;
53              
54 13     13   55 use Carp;
  13         14  
  13         10913  
55              
56             #Known parameters, all starting with YY (leading YY will be discarded)
57             my(%params)=(YYLEX => 'CODE', 'YYERROR' => 'CODE', YYVERSION => '',
58             YYRULES => 'ARRAY', YYSTATES => 'ARRAY', YYDEBUG => '');
59             #Mandatory parameters
60             my(@params)=('LEX','RULES','STATES');
61              
62             sub new {
63 13     13   36 my($class)=shift;
64 13         24 my($errst,$nberr,$token,$value,$check,$dotpos);
65 13         166 my($self)={ ERROR => \&_Error,
66             ERRST => \$errst,
67             NBERR => \$nberr,
68             TOKEN => \$token,
69             VALUE => \$value,
70             DOTPOS => \$dotpos,
71             STACK => [],
72             DEBUG => 0,
73             CHECK => \$check };
74              
75 13         80 _CheckParams( [], \%params, \@_, $self );
76              
77 13 50 33     172 exists($$self{VERSION})
78             and $$self{VERSION} < $COMPATIBLE
79             and croak "Yapp driver version $VERSION ".
80             "incompatible with version $$self{VERSION}:\n".
81             "Please recompile parser module.";
82              
83 13 50       34 ref($class)
84             and $class=ref($class);
85              
86 13         77 bless($self,$class);
87             }
88              
89             sub YYParse {
90 139     139   191 my($self)=shift;
91 139         128 my($retval);
92              
93 139         409 _CheckParams( \@params, \%params, \@_, $self );
94              
95 139 50       349 if($$self{DEBUG}) {
96 0         0 _DBLoad();
97 0         0 $retval = eval '$self->_DBParse()';#Do not create stab entry on compile
98 0 0       0 $@ and die $@;
99             }
100             else {
101 139         517 $retval = $self->_Parse();
102             }
103 139         640 $retval
104             }
105              
106             sub YYData {
107 1643     1643   1537 my($self)=shift;
108              
109 1643 100       2915 exists($$self{USER})
110             or $$self{USER}={};
111              
112 1643         4868 $$self{USER};
113              
114             }
115              
116             sub YYErrok {
117 0     0   0 my($self)=shift;
118              
119 0         0 ${$$self{ERRST}}=0;
  0         0  
120 0         0 undef;
121             }
122              
123             sub YYNberr {
124 0     0   0 my($self)=shift;
125              
126 0         0 ${$$self{NBERR}};
  0         0  
127             }
128              
129             sub YYRecovering {
130 0     0   0 my($self)=shift;
131              
132 0         0 ${$$self{ERRST}} != 0;
  0         0  
133             }
134              
135             sub YYAbort {
136 0     0   0 my($self)=shift;
137              
138 0         0 ${$$self{CHECK}}='ABORT';
  0         0  
139 0         0 undef;
140             }
141              
142             sub YYAccept {
143 66     66   101 my($self)=shift;
144              
145 66         66 ${$$self{CHECK}}='ACCEPT';
  66         108  
146 66         90 undef;
147             }
148              
149             sub YYError {
150 68     68   126 my($self)=shift;
151              
152 68         78 ${$$self{CHECK}}='ERROR';
  68         115  
153 68         117 undef;
154             }
155              
156             sub YYSemval {
157 0     0   0 my($self)=shift;
158 0         0 my($index)= $_[0] - ${$$self{DOTPOS}} - 1;
  0         0  
159              
160 0         0 $index < 0
161 0 0 0     0 and -$index <= @{$$self{STACK}}
162             and return $$self{STACK}[$index][1];
163              
164 0         0 undef; #Invalid index
165             }
166              
167             sub YYCurtok {
168 0     0   0 my($self)=shift;
169              
170             @_
171 0 0       0 and ${$$self{TOKEN}}=$_[0];
  0         0  
172 0         0 ${$$self{TOKEN}};
  0         0  
173             }
174              
175             sub YYCurval {
176 22     22   35 my($self)=shift;
177              
178             @_
179 22 50       57 and ${$$self{VALUE}}=$_[0];
  0         0  
180 22         18 ${$$self{VALUE}};
  22         165  
181             }
182              
183             sub YYExpect {
184 0     0   0 my($self)=shift;
185              
186 0         0 keys %{$self->{STATES}[$self->{STACK}[-1][0]]{ACTIONS}}
  0         0  
187             }
188              
189             sub YYLexer {
190 0     0   0 my($self)=shift;
191              
192 0         0 $$self{LEX};
193             }
194              
195              
196             #################
197             # Private stuff #
198             #################
199              
200              
201             sub _CheckParams {
202 152     152   209 my($mandatory,$checklist,$inarray,$outhash)=@_;
203 152         167 my($prm,$value);
204 152         227 my($prmlst)={};
205              
206 152         580 while(($prm,$value)=splice(@$inarray,0,2)) {
207 317         433 $prm=uc($prm);
208 317 50       704 exists($$checklist{$prm})
209             or croak("Unknow parameter '$prm'");
210 317 50       692 ref($value) eq $$checklist{$prm}
211             or croak("Invalid value for parameter '$prm'");
212 317         828 $prm=unpack('@2A*',$prm);
213 317         908 $$outhash{$prm}=$value;
214             }
215 152         584 for (@$mandatory) {
216 417 50       962 exists($$outhash{$_})
217             or croak("Missing mandatory parameter '".lc($_)."'");
218             }
219             }
220              
221             sub _Error {
222 0     0   0 print "Parse error.\n";
223             }
224              
225             sub _DBLoad {
226             {
227 13     13   74 no strict 'refs';
  13     0   22  
  13         12826  
  0         0  
228              
229 0 0       0 exists(${__PACKAGE__.'::'}{_DBParse})#Already loaded ?
  0         0  
230             and return;
231             }
232 0         0 my($fname)=__FILE__;
233 0         0 my(@drv);
234 0 0       0 open(DRV,"<$fname") or die "Report this as a BUG: Cannot open $fname";
235 0         0 while() {
236             /^\s*sub\s+_Parse\s*{\s*$/ .. /^\s*}\s*#\s*_Parse\s*$/
237 0 0       0 and do {
238 0         0 s/^#DBG>//;
239 0         0 push(@drv,$_);
240             }
241             }
242 0         0 close(DRV);
243              
244 0         0 $drv[0]=~s/_P/_DBP/;
245 0         0 eval join('',@drv);
246             }
247              
248             #Note that for loading debugging version of the driver,
249             #this file will be parsed from 'sub _Parse' up to '}#_Parse' inclusive.
250             #So, DO NOT remove comment at end of sub !!!
251             sub _Parse {
252 139     139   183 my($self)=shift;
253              
254 139         342 my($rules,$states,$lex,$error)
255             = @$self{ 'RULES', 'STATES', 'LEX', 'ERROR' };
256 139         369 my($errstatus,$nberror,$token,$value,$stack,$check,$dotpos)
257             = @$self{ 'ERRST', 'NBERR', 'TOKEN', 'VALUE', 'STACK', 'CHECK', 'DOTPOS' };
258              
259             #DBG> my($debug)=$$self{DEBUG};
260             #DBG> my($dbgerror)=0;
261              
262             #DBG> my($ShowCurToken) = sub {
263             #DBG> my($tok)='>';
264             #DBG> for (split('',$$token)) {
265             #DBG> $tok.= (ord($_) < 32 or ord($_) > 126)
266             #DBG> ? sprintf('<%02X>',ord($_))
267             #DBG> : $_;
268             #DBG> }
269             #DBG> $tok.='<';
270             #DBG> };
271              
272 139         169 $$errstatus=0;
273 139         133 $$nberror=0;
274 139         230 ($$token,$$value)=(undef,undef);
275 139         337 @$stack=( [ 0, undef ] );
276 139         185 $$check='';
277              
278 139         138 while(1) {
279 1000         819 my($actions,$act,$stateno);
280              
281 1000         1059 $stateno=$$stack[-1][0];
282 1000         998 $actions=$$states[$stateno];
283              
284             #DBG> print STDERR ('-' x 40),"\n";
285             #DBG> $debug & 0x2
286             #DBG> and print STDERR "In state $stateno:\n";
287             #DBG> $debug & 0x08
288             #DBG> and print STDERR "Stack:[".
289             #DBG> join(',',map { $$_[0] } @$stack).
290             #DBG> "]\n";
291              
292              
293 1000 100       1554 if (exists($$actions{ACTIONS})) {
294              
295             defined($$token)
296 688 100       1099 or do {
297 573         969 ($$token,$$value)=&$lex($self);
298             #DBG> $debug & 0x01
299             #DBG> and print STDERR "Need token. Got ".&$ShowCurToken."\n";
300             };
301              
302 688 100       18817 $act= exists($$actions{ACTIONS}{$$token})
    100          
303             ? $$actions{ACTIONS}{$$token}
304             : exists($$actions{DEFAULT})
305             ? $$actions{DEFAULT}
306             : undef;
307             }
308             else {
309 312         340 $act=$$actions{DEFAULT};
310             #DBG> $debug & 0x01
311             #DBG> and print STDERR "Don't need token.\n";
312             }
313              
314             defined($act)
315 1000 100       1610 and do {
316              
317             $act > 0
318 991 100       1440 and do { #shift
319              
320             #DBG> $debug & 0x04
321             #DBG> and print STDERR "Shift and go to state $act.\n";
322              
323             $$errstatus
324 533 50       826 and do {
325 0         0 --$$errstatus;
326              
327             #DBG> $debug & 0x10
328             #DBG> and $dbgerror
329             #DBG> and $$errstatus == 0
330             #DBG> and do {
331             #DBG> print STDERR "**End of Error recovery.\n";
332             #DBG> $dbgerror=0;
333             #DBG> };
334             };
335              
336              
337 533         930 push(@$stack,[ $act, $$value ]);
338              
339 533 100       1054 $$token ne '' #Don't eat the eof
340             and $$token=$$value=undef;
341 533         628 next;
342             };
343              
344             #reduce
345 458         374 my($lhs,$len,$code,@sempar,$semval);
346 458         375 ($lhs,$len,$code)=@{$$rules[-$act]};
  458         888  
347              
348             #DBG> $debug & 0x04
349             #DBG> and $act
350             #DBG> and print STDERR "Reduce using rule ".-$act." ($lhs,$len): ";
351              
352 458 100       1031 $act
353             or $self->YYAccept();
354              
355 458         393 $$dotpos=$len;
356              
357             unpack('A1',$lhs) eq '@' #In line rule
358 458 50       1223 and do {
359 0 0       0 $lhs =~ /^\@[0-9]+\-([0-9]+)$/
360             or die "In line rule name '$lhs' ill formed: ".
361             "report it as a BUG.\n";
362 0         0 $$dotpos = $1;
363             };
364              
365 853         1418 @sempar = $$dotpos
366 458 50       1232 ? map { $$_[1] } @$stack[ -$$dotpos .. -1 ]
367             : ();
368              
369 458 50       1226 $semval = $code ? &$code( $self, @sempar )
    100          
370             : @sempar ? $sempar[0] : undef;
371              
372 458         756 splice(@$stack,-$len,$len);
373              
374             $$check eq 'ACCEPT'
375 458 100       877 and do {
376              
377             #DBG> $debug & 0x04
378             #DBG> and print STDERR "Accept.\n";
379              
380 66         186 return($semval);
381             };
382              
383             $$check eq 'ABORT'
384 392 50       633 and do {
385              
386             #DBG> $debug & 0x04
387             #DBG> and print STDERR "Abort.\n";
388              
389 0         0 return(undef);
390              
391             };
392              
393             #DBG> $debug & 0x04
394             #DBG> and print STDERR "Back to state $$stack[-1][0], then ";
395              
396             $$check eq 'ERROR'
397 392 100       624 or do {
398             #DBG> $debug & 0x04
399             #DBG> and print STDERR
400             #DBG> "go to state $$states[$$stack[-1][0]]{GOTOS}{$lhs}.\n";
401              
402             #DBG> $debug & 0x10
403             #DBG> and $dbgerror
404             #DBG> and $$errstatus == 0
405             #DBG> and do {
406             #DBG> print STDERR "**End of Error recovery.\n";
407             #DBG> $dbgerror=0;
408             #DBG> };
409              
410 328         699 push(@$stack,
411             [ $$states[$$stack[-1][0]]{GOTOS}{$lhs}, $semval ]);
412 328         335 $$check='';
413 328         408 next;
414             };
415              
416             #DBG> $debug & 0x04
417             #DBG> and print STDERR "Forced Error recovery.\n";
418              
419 64         175 $$check='';
420              
421             };
422              
423             #Error
424             $$errstatus
425 73 50       159 or do {
426              
427 73         76 $$errstatus = 1;
428 73         159 &$error($self);
429 73 50       139 $$errstatus # if 0, then YYErrok has been called
430             or next; # so continue parsing
431              
432             #DBG> $debug & 0x10
433             #DBG> and do {
434             #DBG> print STDERR "**Entering Error recovery.\n";
435             #DBG> ++$dbgerror;
436             #DBG> };
437              
438 73         86 ++$$nberror;
439              
440             };
441              
442             $$errstatus == 3 #The next token is not valid: discard it
443 73 50       175 and do {
444             $$token eq '' # End of input: no hope
445 0 0       0 and do {
446             #DBG> $debug & 0x10
447             #DBG> and print STDERR "**At eof: aborting.\n";
448 0         0 return(undef);
449             };
450              
451             #DBG> $debug & 0x10
452             #DBG> and print STDERR "**Dicard invalid token ".&$ShowCurToken.".\n";
453              
454 0         0 $$token=$$value=undef;
455             };
456              
457 73         92 $$errstatus=3;
458              
459 73   33     688 while( @$stack
      66        
460             and ( not exists($$states[$$stack[-1][0]]{ACTIONS})
461             or not exists($$states[$$stack[-1][0]]{ACTIONS}{error})
462             or $$states[$$stack[-1][0]]{ACTIONS}{error} <= 0)) {
463              
464             #DBG> $debug & 0x10
465             #DBG> and print STDERR "**Pop state $$stack[-1][0].\n";
466              
467 81         230 pop(@$stack);
468             }
469              
470             @$stack
471 73 50       156 or do {
472              
473             #DBG> $debug & 0x10
474             #DBG> and print STDERR "**No state left on stack: aborting.\n";
475              
476 73         182 return(undef);
477             };
478              
479             #shift the error token
480              
481             #DBG> $debug & 0x10
482             #DBG> and print STDERR "**Shift \$error token and go to state ".
483             #DBG> $$states[$$stack[-1][0]]{ACTIONS}{error}.
484             #DBG> ".\n";
485              
486 0           push(@$stack, [ $$states[$$stack[-1][0]]{ACTIONS}{error}, undef ]);
487              
488             }
489              
490             #never reached
491 0           croak("Error in driver logic. Please, report it as a BUG");
492              
493             }#_Parse
494             #DO NOT remove comment
495              
496             1;
497              
498             }
499             #End of include--------------------------------------------------
500              
501              
502             #line 1 "Parser.yp"
503             #
504             # Validate::SPF::Parser source file
505             #
506             # Author: Anton Gerasimov
507             #
508              
509             use Regexp::Common qw( net );
510             use utf8;
511              
512             binmode( STDOUT, ':utf8' );
513              
514             my $input;
515              
516             my %errors = (
517             E_DEFAULT => "Just error",
518             E_SYNTAX => "Syntax error near token '%s'",
519             E_INVALID_VERSION => "Invalid SPF version",
520             E_IPADDR_EXPECTED => "Expected ip or network address",
521             E_DOMAIN_EXPECTED => "Expected domain name",
522             E_UNEXPECTED_BITMASK => "Unexpected bitmask",
523             E_UNEXPECTED_IPADDR => "Unexpected ip address",
524             E_UNEXPECTED_DOMAIN => "Unexpected domain name",
525             );
526              
527              
528              
529              
530             sub new {
531             my( $class ) = shift;
532              
533             ref( $class ) and $class = ref( $class );
534              
535             my $self =
536             $class->SUPER::new(
537             yyversion => '1.05',
538             yystates => [
539             {#State 0
540             ACTIONS => {
541             'MECHANISM' => 2,
542             'QUALIFIER' => 6,
543             'VERSION' => 13,
544             'LITERAL' => 7
545             },
546             GOTOS => {
547             'mechanism' => 1,
548             'version' => 5,
549             'with_bitmask' => 4,
550             'with_domain' => 3,
551             'with_domain_bitmask' => 8,
552             'modifier' => 9,
553             'chunks' => 10,
554             'with_ipaddress' => 11,
555             'chunk' => 14,
556             'spf' => 12
557             }
558             },
559             {#State 1
560             DEFAULT => -6
561             },
562             {#State 2
563             ACTIONS => {
564             ":" => 15,
565             "/" => 16
566             },
567             DEFAULT => -17
568             },
569             {#State 3
570             DEFAULT => -11
571             },
572             {#State 4
573             DEFAULT => -10
574             },
575             {#State 5
576             DEFAULT => -5
577             },
578             {#State 6
579             ACTIONS => {
580             'MECHANISM' => 17
581             }
582             },
583             {#State 7
584             ACTIONS => {
585             "=" => 18
586             },
587             DEFAULT => -12
588             },
589             {#State 8
590             DEFAULT => -9
591             },
592             {#State 9
593             DEFAULT => -7
594             },
595             {#State 10
596             ACTIONS => {
597             'MECHANISM' => 2,
598             'QUALIFIER' => 6,
599             'VERSION' => 13,
600             'LITERAL' => 7
601             },
602             DEFAULT => -1,
603             GOTOS => {
604             'mechanism' => 1,
605             'version' => 5,
606             'with_bitmask' => 4,
607             'with_domain' => 3,
608             'with_domain_bitmask' => 8,
609             'modifier' => 9,
610             'with_ipaddress' => 11,
611             'chunk' => 19
612             }
613             },
614             {#State 11
615             DEFAULT => -8
616             },
617             {#State 12
618             ACTIONS => {
619             '' => 20
620             }
621             },
622             {#State 13
623             DEFAULT => -2
624             },
625             {#State 14
626             DEFAULT => -4
627             },
628             {#State 15
629             ACTIONS => {
630             'DOMAIN' => 21,
631             'IPADDRESS' => 22
632             }
633             },
634             {#State 16
635             ACTIONS => {
636             'BITMASK' => 23
637             }
638             },
639             {#State 17
640             ACTIONS => {
641             ":" => 24,
642             "/" => 25
643             },
644             DEFAULT => -18
645             },
646             {#State 18
647             ACTIONS => {
648             'DOMAIN' => 27,
649             'LITERAL' => 26,
650             'IPADDRESS' => 28
651             }
652             },
653             {#State 19
654             DEFAULT => -3
655             },
656             {#State 20
657             DEFAULT => 0
658             },
659             {#State 21
660             ACTIONS => {
661             "/" => 29
662             },
663             DEFAULT => -19
664             },
665             {#State 22
666             ACTIONS => {
667             "/" => 30
668             },
669             DEFAULT => -25
670             },
671             {#State 23
672             DEFAULT => -21
673             },
674             {#State 24
675             ACTIONS => {
676             'DOMAIN' => 31,
677             'IPADDRESS' => 32
678             }
679             },
680             {#State 25
681             ACTIONS => {
682             'BITMASK' => 33
683             }
684             },
685             {#State 26
686             DEFAULT => -14
687             },
688             {#State 27
689             DEFAULT => -13
690             },
691             {#State 28
692             ACTIONS => {
693             "/" => 34
694             },
695             DEFAULT => -15
696             },
697             {#State 29
698             ACTIONS => {
699             'BITMASK' => 35
700             }
701             },
702             {#State 30
703             ACTIONS => {
704             'BITMASK' => 36
705             }
706             },
707             {#State 31
708             ACTIONS => {
709             "/" => 37
710             },
711             DEFAULT => -20
712             },
713             {#State 32
714             ACTIONS => {
715             "/" => 38
716             },
717             DEFAULT => -26
718             },
719             {#State 33
720             DEFAULT => -22
721             },
722             {#State 34
723             ACTIONS => {
724             'BITMASK' => 39
725             }
726             },
727             {#State 35
728             DEFAULT => -23
729             },
730             {#State 36
731             DEFAULT => -27
732             },
733             {#State 37
734             ACTIONS => {
735             'BITMASK' => 40
736             }
737             },
738             {#State 38
739             ACTIONS => {
740             'BITMASK' => 41
741             }
742             },
743             {#State 39
744             DEFAULT => -16
745             },
746             {#State 40
747             DEFAULT => -24
748             },
749             {#State 41
750             DEFAULT => -28
751             }
752             ],
753             yyrules => [
754             [#Rule 0
755             '$start', 2, undef
756             ],
757             [#Rule 1
758             'spf', 1,
759             sub
760             #line 31 "Parser.yp"
761             { $_[1] }
762             ],
763             [#Rule 2
764             'version', 1,
765             sub
766             #line 36 "Parser.yp"
767             {
768             $_[1] eq 'v=spf1' and
769             return $_[0]->_ver_generic( $_[1] );
770              
771             $_[0]->raise_error( 'E_INVALID_VERSION', $_[1] );
772             }
773             ],
774             [#Rule 3
775             'chunks', 2,
776             sub
777             #line 46 "Parser.yp"
778             { push( @{$_[1]}, $_[2] ) if defined $_[2]; $_[1] }
779             ],
780             [#Rule 4
781             'chunks', 1,
782             sub
783             #line 48 "Parser.yp"
784             { defined $_[1] ? [ $_[1] ] : [ ] }
785             ],
786             [#Rule 5
787             'chunk', 1, undef
788             ],
789             [#Rule 6
790             'chunk', 1, undef
791             ],
792             [#Rule 7
793             'chunk', 1, undef
794             ],
795             [#Rule 8
796             'mechanism', 1, undef
797             ],
798             [#Rule 9
799             'mechanism', 1, undef
800             ],
801             [#Rule 10
802             'mechanism', 1, undef
803             ],
804             [#Rule 11
805             'mechanism', 1, undef
806             ],
807             [#Rule 12
808             'modifier', 1,
809             sub
810             #line 66 "Parser.yp"
811             {
812             # print "got (LITERAL): $_[1]\n";
813              
814             # for known literals - specific error
815             $_[0]->raise_error( 'E_DOMAIN_EXPECTED', $_[1] )
816             if $_[1] =~ /\A(redirect|exp)\Z/i;
817              
818             # for unknown literals - syntax error
819             $_[0]->YYError;
820              
821             return;
822             }
823             ],
824             [#Rule 13
825             'modifier', 3,
826             sub
827             #line 79 "Parser.yp"
828             {
829             # print "got (LITERAL_DOMAIN): $_[1] = $_[3]\n";
830              
831             return unless $_[1] =~ /\A(redirect|exp)\Z/i;
832              
833             return $_[0]->_mod_generic( $_[1], $_[3] );
834             }
835             ],
836             [#Rule 14
837             'modifier', 3,
838             sub
839             #line 87 "Parser.yp"
840             {
841             # print "got (LITERAL_LITERAL): $_[1] = $_[3]\n";
842              
843             # looks like "version"
844             if ( $_[1] eq 'v' ) {
845             my $ctx = $_[1] . '=' . $_[3];
846              
847             return $_[0]->_ver_generic( $ctx ) if $_[3] eq 'spf1';
848              
849             $_[0]->raise_error( 'E_INVALID_VERSION', $ctx );
850             }
851              
852             return;
853             }
854             ],
855             [#Rule 15
856             'modifier', 3,
857             sub
858             #line 102 "Parser.yp"
859             {
860             # print "got (LITERAL_IPADDRESS): $_[1] = $_[3]\n";
861              
862             # known literals
863             $_[0]->raise_error( 'E_DOMAIN_EXPECTED', $_[3] )
864             if $_[1] =~ /\A(redirect|exp)\Z/i;
865              
866             return;
867             }
868             ],
869             [#Rule 16
870             'modifier', 5,
871             sub
872             #line 112 "Parser.yp"
873             {
874             # print "got (LITERAL_IPADDRESS_BITMASK): $_[1] = $_[3] / $_[5]\n";
875              
876             # known literals
877             $_[0]->raise_error( 'E_DOMAIN_EXPECTED', $_[3] . '/' . $_[5] )
878             if $_[1] =~ /\A(redirect|exp)\Z/i;
879              
880             return;
881             }
882             ],
883             [#Rule 17
884             'with_domain', 1,
885             sub
886             #line 126 "Parser.yp"
887             {
888             $_[0]->raise_error( 'E_IPADDR_EXPECTED', $_[1] )
889             if $_[1] =~ /ip[46]/i;
890             $_[0]->raise_error( 'E_DOMAIN_EXPECTED', $_[1] )
891             if $_[1] =~ /\A(exists|include)\Z/i;
892              
893             $_[0]->_mech_domain( '+', $_[1], $_[1] =~ /all/i ? undef : '@' );
894             }
895             ],
896             [#Rule 18
897             'with_domain', 2,
898             sub
899             #line 135 "Parser.yp"
900             {
901             $_[0]->raise_error( 'E_IPADDR_EXPECTED', $_[1] . $_[2] )
902             if $_[2] =~ /ip[46]/i;
903             $_[0]->raise_error( 'E_DOMAIN_EXPECTED', $_[1] . $_[2] )
904             if $_[2] =~ /\A(exists|include)\Z/i;
905              
906             $_[0]->_mech_domain( $_[1], $_[2], $_[2] =~ /all/i ? undef : '@' );
907             }
908             ],
909             [#Rule 19
910             'with_domain', 3,
911             sub
912             #line 144 "Parser.yp"
913             {
914             my $ctx = $_[1] . ':' . $_[3];
915              
916             $_[0]->raise_error( 'E_UNEXPECTED_DOMAIN', $ctx )
917             if $_[1] =~ /all/i;
918              
919             $_[0]->_mech_domain( '+', $_[1], $_[3] );
920             }
921             ],
922             [#Rule 20
923             'with_domain', 4,
924             sub
925             #line 153 "Parser.yp"
926             {
927             my $ctx = $_[1] . $_[2] . ':' . $_[4];
928              
929             $_[0]->raise_error( 'E_UNEXPECTED_DOMAIN', $ctx )
930             if $_[2] =~ /all/i;
931              
932             $_[0]->_mech_domain( $_[1], $_[2], $_[4] );
933             }
934             ],
935             [#Rule 21
936             'with_bitmask', 3,
937             sub
938             #line 166 "Parser.yp"
939             {
940             my $ctx = $_[1] . '/' . $_[3];
941              
942             $_[0]->raise_error( 'E_IPADDR_EXPECTED', $ctx )
943             if $_[1] =~ /ip[46]/i;
944              
945             $_[0]->raise_error( 'E_UNEXPECTED_BITMASK', $ctx )
946             if $_[1] =~ /\A(ptr|all|exists|include)\Z/i;
947              
948             $_[0]->_mech_domain_bitmask( '+', $_[1], '@', $_[3] );
949             }
950             ],
951             [#Rule 22
952             'with_bitmask', 4,
953             sub
954             #line 178 "Parser.yp"
955             {
956             my $ctx = $_[1] . $_[2] . '/' . $_[4];
957              
958             $_[0]->raise_error( 'E_IPADDR_EXPECTED', $ctx )
959             if $_[2] =~ /ip[46]/i;
960              
961             $_[0]->raise_error( 'E_UNEXPECTED_BITMASK', $ctx )
962             if $_[2] =~ /\A(ptr|all|exists|include)\Z/i;
963              
964             $_[0]->_mech_domain_bitmask( $_[1], $_[2], '@', $_[4] );
965             }
966             ],
967             [#Rule 23
968             'with_domain_bitmask', 5,
969             sub
970             #line 194 "Parser.yp"
971             {
972             my $ctx = $_[1] . ':' . $_[3] . '/' . $_[5];
973              
974             $_[0]->raise_error( 'E_UNEXPECTED_BITMASK', $ctx )
975             if $_[1] =~ /\A(ptr|all|exists|include)\Z/i;
976              
977             $_[0]->_mech_domain_bitmask( '+', $_[1], $_[3], $_[5] );
978             }
979             ],
980             [#Rule 24
981             'with_domain_bitmask', 6,
982             sub
983             #line 203 "Parser.yp"
984             {
985             my $ctx = $_[1] . $_[2] . ':' . $_[4] . '/' . $_[6];
986              
987             $_[0]->raise_error( 'E_UNEXPECTED_BITMASK', $ctx )
988             if $_[2] =~ /\A(ptr|all|exists|include)\Z/i;
989              
990             $_[0]->_mech_domain_bitmask( $_[1], $_[2], $_[4], $_[6] );
991             }
992             ],
993             [#Rule 25
994             'with_ipaddress', 3,
995             sub
996             #line 216 "Parser.yp"
997             {
998             my $ctx = $_[1] . ':' . $_[3];
999              
1000             $_[0]->raise_error( 'E_UNEXPECTED_IPADDR', $ctx )
1001             if $_[1] =~ /\A(a|mx|ptr|all|exists|include)\Z/i;
1002              
1003             $_[0]->_mech_ipaddr_bitmask( '+', $_[1], $_[3], undef );
1004             }
1005             ],
1006             [#Rule 26
1007             'with_ipaddress', 4,
1008             sub
1009             #line 225 "Parser.yp"
1010             {
1011             my $ctx = $_[1] . $_[2] . ':' . $_[4];
1012              
1013             $_[0]->raise_error( 'E_UNEXPECTED_IPADDR', $ctx )
1014             if $_[2] =~ /\A(a|mx|ptr|all|exists|include)\Z/i;
1015              
1016             $_[0]->_mech_ipaddr_bitmask( $_[1], $_[2], $_[4], undef );
1017             }
1018             ],
1019             [#Rule 27
1020             'with_ipaddress', 5,
1021             sub
1022             #line 234 "Parser.yp"
1023             {
1024             my $ctx = $_[1] . ':' . $_[3] . '/' . $_[5];
1025              
1026             $_[0]->raise_error( 'E_UNEXPECTED_IPADDR', $ctx )
1027             if $_[1] =~ /\A(a|mx|ptr|all|exists|include)\Z/i;
1028              
1029             $_[0]->_mech_ipaddr_bitmask( '+', $_[1], $_[3], $_[5] );
1030             }
1031             ],
1032             [#Rule 28
1033             'with_ipaddress', 6,
1034             sub
1035             #line 243 "Parser.yp"
1036             {
1037             my $ctx = $_[1] . $_[2] . ':' . $_[4] . '/' . $_[6];
1038              
1039             $_[0]->raise_error( 'E_UNEXPECTED_IPADDR', $ctx )
1040             if $_[2] =~ /\A(a|mx|ptr|all|exists|include)\Z/i;
1041              
1042             $_[0]->_mech_ipaddr_bitmask( $_[1], $_[2], $_[4], $_[6] );
1043             }
1044             ]
1045             ],
1046             @_
1047             );
1048              
1049             bless $self, $class;
1050             }
1051              
1052              
1053             #line 253 "Parser.yp"
1054              
1055              
1056             sub parse {
1057             my ( $self, $text ) = @_;
1058              
1059             $input = $self->YYData->{INPUT} = $text;
1060             delete $self->YYData->{ERRMSG};
1061              
1062             return $self->YYParse( yylex => \&_lexer, yyerror => \&_error );
1063             }
1064              
1065             sub error {
1066             my ( $self ) = @_;
1067             return $self->YYData->{ERRMSG};
1068             }
1069              
1070             sub _build_error {
1071             my ( $self, $code, $context, @extra ) = @_;
1072              
1073             $code = 'E_DEFAULT' unless exists $errors{$code};
1074              
1075             $self->YYData->{ERRMSG} = {
1076             text => sprintf( $errors{$code} => @extra ),
1077             code => $code,
1078             context => $context,
1079             };
1080             }
1081              
1082             sub raise_error {
1083             my ( $self, @params ) = @_;
1084              
1085             $self->_build_error( @params );
1086             $self->YYError;
1087             }
1088              
1089             sub _error {
1090             my ( $self ) = @_;
1091              
1092             unless ( exists $self->YYData->{ERRMSG} ) {
1093             substr( $input, index( $input, ($self->YYCurval || '') ), 0, '<*>' );
1094              
1095             $self->_build_error( 'E_SYNTAX', $input, ($self->YYCurval || '') );
1096             }
1097              
1098             return;
1099             }
1100              
1101             sub _lexer {
1102             my ( $parser ) = @_;
1103              
1104             $parser->YYData->{INPUT} =~ s/^\s*//;
1105              
1106             for ( $parser->YYData->{INPUT} ) {
1107             # printf( "[debug] %s\n", $_ );
1108              
1109             s/^(v\=spf1)\b//i
1110             and return ( 'VERSION', $1 );
1111              
1112             s/^(\/)\b//i
1113             and return ( '/', '/' );
1114             s/^(\:)\b//i
1115             and return ( ':', ':' );
1116             s/^(\=)\b//i
1117             and return ( '=', '=' );
1118              
1119             # qualifiers
1120             s/^([-~\+\?])\b//i
1121             and return ( 'QUALIFIER', $1 );
1122              
1123             # mechanisms
1124             s/^(all|ptr|a|mx|ip4|ip6|exists|include)\b//i
1125             and return ( 'MECHANISM', $1 );
1126              
1127             s/^($RE{net}{IPv4}{dec}|$RE{net}{IPv6}{-sep=>':'})\b//i
1128             and return ( 'IPADDRESS', $1 );
1129              
1130             s/^([_\.a-z\d][\-a-z\d]*\.[\.\-a-z\d]*[a-z\d]?)\b//i
1131             and return ( 'DOMAIN', $1 );
1132              
1133             s/^(\d{1,3})\b//i
1134             and return ( 'BITMASK', $1 );
1135              
1136             s/^([a-z\d\.\-_]+)\b//i
1137             and return ( 'LITERAL', $1 );
1138              
1139             # garbage
1140             s/^(.+)\b//i
1141             and return ( 'UNKNOWN', $1 );
1142             }
1143              
1144             # EOF
1145             return ( '', undef );
1146             }
1147              
1148             # generic modifier
1149             sub _mod_generic {
1150             my ( $self, $mod, $domain ) = @_;
1151              
1152             return +{
1153             type => 'mod',
1154             modifier => lc $mod,
1155             (
1156             $domain
1157             ? ( domain => $domain ) :
1158             ( )
1159             ),
1160             };
1161             }
1162              
1163             # generic skip
1164             sub _skip_generic {
1165             my ( $self, $token, $val ) = @_;
1166              
1167             return +{
1168             type => 'skip',
1169             token => lc $token,
1170             value => $val,
1171             };
1172             }
1173              
1174             # generic version
1175             sub _ver_generic {
1176             my ( $self, $ver ) = @_;
1177              
1178             return +{
1179             type => 'ver',
1180             version => lc $ver,
1181             };
1182             }
1183              
1184              
1185             # generic mechanism
1186             sub _mech_generic {
1187             my ( $self, $qualifier, $mech, $domain, $ipaddr, $bitmask ) = @_;
1188              
1189             return +{
1190             type => 'mech',
1191             qualifier => $qualifier,
1192             mechanism => lc $mech,
1193             (
1194             $domain
1195             ? ( domain => $domain ) :
1196             ( )
1197             ),
1198             (
1199             $ipaddr
1200             ? ( ( defined $bitmask ? 'network' : 'ipaddress' ) => $ipaddr )
1201             : ( )
1202             ),
1203             (
1204             defined $bitmask
1205             ? ( bitmask => $bitmask )
1206             : ( )
1207             ),
1208             };
1209             }
1210              
1211             sub _mech_domain {
1212             my ( $self, $qualifier, $mech, $domain ) = @_;
1213              
1214             return $self->_mech_generic( $qualifier, $mech, $domain, undef, undef );
1215             }
1216              
1217             sub _mech_domain_bitmask {
1218             my ( $self, $qualifier, $mech, $domain, $bitmask ) = @_;
1219              
1220             return $self->_mech_generic( $qualifier, $mech, $domain, undef, $bitmask );
1221             }
1222              
1223             sub _mech_ipaddr_bitmask {
1224             my ( $self, $qualifier, $mech, $ipaddr, $bitmask ) = @_;
1225              
1226             return $self->_mech_generic( $qualifier, $mech, undef, $ipaddr, $bitmask );
1227             }
1228              
1229             1;
1230              
1231             __END__