-
Notifications
You must be signed in to change notification settings - Fork 6
/
token.go
150 lines (126 loc) · 2.46 KB
/
token.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package spf
import "strconv"
type tokenType int
const (
tEOF tokenType = iota
tErr
mechanismBeg
tVersion // used only for v=spf1 starter
tAll // all
tA // a
tIP4 // ip4
tIP6 // ip6
tMX // mx
tPTR // ptr
tInclude // include
tExists // exists
mechanismEnd
modifierBeg
tRedirect // redirect
tExp // explanation
modifierEnd
_ // qEmpty - deadcode, not used
qPlus
qMinus
qTilde
qQuestionMark
qErr
)
var qualifiers = map[rune]tokenType{
'+': qPlus,
'-': qMinus,
'?': qQuestionMark,
'~': qTilde,
}
func (tok tokenType) String() string {
switch tok {
case tVersion:
return "v"
case tAll:
return "all"
case tIP4:
return "ip4"
case tIP6:
return "ip6"
case tMX:
return "mx"
case tPTR:
return "ptr"
case tInclude:
return "include"
case tRedirect:
return "redirect"
case tExists:
return "exists"
case tExp:
return "exp"
default:
return strconv.Itoa(int(tok))
}
}
func tokenTypeFromString(s string) tokenType {
switch s {
case "v":
return tVersion
case "all":
return tAll
case "a":
return tA
case "ip4":
return tIP4
case "ip6":
return tIP6
case "mx":
return tMX
case "ptr":
return tPTR
case "include":
return tInclude
case "redirect":
return tRedirect
case "exists":
return tExists
case "explanation", "exp":
return tExp
default:
return tErr
}
}
func (tok tokenType) isErr() bool { return tok == tErr }
func (tok tokenType) isMechanism() bool {
return tok > mechanismBeg && tok < mechanismEnd
}
func (tok tokenType) isModifier() bool {
return tok > modifierBeg && tok < modifierEnd
}
func checkTokenSyntax(tkn *token, delimiter rune) bool {
if tkn == nil {
return false
}
if tkn.mechanism == tErr && tkn.qualifier == qErr {
return true // syntax is ok
}
// special case for v=spf1 token
if tkn.mechanism == tVersion {
return true
}
//mechanism include must not have empty content
if tkn.mechanism == tInclude && tkn.value == "" {
return false
}
if tkn.mechanism.isModifier() && delimiter != '=' {
return false
}
if tkn.mechanism.isMechanism() && delimiter != ':' {
return false
}
return true
}
// token represents SPF term (modifier or mechanism) like all, include, a, mx,
// ptr, ip4, ip6, exists, redirect etc.
// It's a base structure later parsed by Parser.
type token struct {
mechanism tokenType // all, include, a, mx, ptr, ip4, ip6, exists etc.
qualifier tokenType // +, -, ~, ?, defaults to +
value string // value for a mechanism
}