...
1
2
3
4
5 package packet
6
7 import (
8 "io"
9 "io/ioutil"
10 "strings"
11 )
12
13
14
15
16 type UserId struct {
17 Id string
18
19 Name, Comment, Email string
20 }
21
22 func hasInvalidCharacters(s string) bool {
23 for _, c := range s {
24 switch c {
25 case '(', ')', '<', '>', 0:
26 return true
27 }
28 }
29 return false
30 }
31
32
33
34 func NewUserId(name, comment, email string) *UserId {
35
36
37
38
39
40
41 if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
42 return nil
43 }
44
45 uid := new(UserId)
46 uid.Name, uid.Comment, uid.Email = name, comment, email
47 uid.Id = name
48 if len(comment) > 0 {
49 if len(uid.Id) > 0 {
50 uid.Id += " "
51 }
52 uid.Id += "("
53 uid.Id += comment
54 uid.Id += ")"
55 }
56 if len(email) > 0 {
57 if len(uid.Id) > 0 {
58 uid.Id += " "
59 }
60 uid.Id += "<"
61 uid.Id += email
62 uid.Id += ">"
63 }
64 return uid
65 }
66
67 func (uid *UserId) parse(r io.Reader) (err error) {
68
69 b, err := ioutil.ReadAll(r)
70 if err != nil {
71 return
72 }
73 uid.Id = string(b)
74 uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
75 return
76 }
77
78
79
80 func (uid *UserId) Serialize(w io.Writer) error {
81 err := serializeHeader(w, packetTypeUserId, len(uid.Id))
82 if err != nil {
83 return err
84 }
85 _, err = w.Write([]byte(uid.Id))
86 return err
87 }
88
89
90
91 func parseUserId(id string) (name, comment, email string) {
92 var n, c, e struct {
93 start, end int
94 }
95 var state int
96
97 for offset, rune := range id {
98 switch state {
99 case 0:
100
101 n.start = offset
102 state = 1
103 fallthrough
104 case 1:
105
106 if rune == '(' {
107 state = 2
108 n.end = offset
109 } else if rune == '<' {
110 state = 5
111 n.end = offset
112 }
113 case 2:
114
115 c.start = offset
116 state = 3
117 fallthrough
118 case 3:
119
120 if rune == ')' {
121 state = 4
122 c.end = offset
123 }
124 case 4:
125
126 if rune == '<' {
127 state = 5
128 }
129 case 5:
130
131 e.start = offset
132 state = 6
133 fallthrough
134 case 6:
135
136 if rune == '>' {
137 state = 7
138 e.end = offset
139 }
140 default:
141
142 }
143 }
144 switch state {
145 case 1:
146
147 n.end = len(id)
148 case 3:
149
150 c.end = len(id)
151 case 6:
152
153 e.end = len(id)
154 }
155
156 name = strings.TrimSpace(id[n.start:n.end])
157 comment = strings.TrimSpace(id[c.start:c.end])
158 email = strings.TrimSpace(id[e.start:e.end])
159
160
161 if email == "" && strings.ContainsRune(name, '@') {
162 email = name
163 name = ""
164 }
165
166 return
167 }
168
View as plain text