-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathlist.go
178 lines (153 loc) · 3.64 KB
/
list.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
package mailaddress
import (
"encoding/json"
"fmt"
"sort"
"strings"
multierror "github.com/hashicorp/go-multierror"
)
// List of zero or more addresses.
type List []Address
// String formats all addresses. It is *not* RFC 2047 encoded!
func (l List) String() string {
var out []string
for _, a := range l {
out = append(out, a.String())
}
return strings.Join(out, ", ")
}
// UnmarshalJSON allows accepting several different formats for a list of mail
// addresses, which are (in order):
//
// 1. Standard List struct JSON string output.
// 2. Slice of strings containing emails.
// 3. Comma-separated string of emails, as accepted by ParseList().
func (l *List) UnmarshalJSON(data []byte) error {
type Alias List
var alias Alias
err := json.Unmarshal(data, &alias)
if err == nil {
*l = List(alias)
return nil
}
var slice []string
err = json.Unmarshal(data, &slice)
if err != nil {
var str string
err = json.Unmarshal(data, &str)
if err != nil {
return err
}
*l, _ = ParseList(str)
*l = l.uniq()
return nil
}
*l = FromSlice(slice).uniq()
return nil
}
// uniq returns only the unique addresses from a list. Order is preserved
func (l List) uniq() List {
a := List{}
for _, addr := range l {
found := false
for _, add := range a {
if strings.EqualFold(add.Address, addr.Address) {
found = true
break
}
}
if found {
continue
}
a = append(a, addr)
}
return a
}
// StringEncoded makes a string that *is* RFC 2047 encoded. Duplicates are ignored.
func (l List) StringEncoded() string {
var out []string
for _, a := range l {
val := a.StringEncoded()
out = append(out, val)
}
return strings.Join(out, ", ")
}
// Append adds a new Address to the list. If the address already exists in the
// list this will be a noop.
func (l *List) Append(name, address string) {
e := New(name, address)
for _, addr := range *l {
if strings.EqualFold(addr.Address, e.Address) {
return
}
}
*l = append(*l, e)
}
// Slice gets all valid addresses in a []string slice. The names are lost and
// invalid addresses are skipped. Duplicates are ignored.
func (l List) Slice() []string {
mails := []string{}
for _, e := range l {
if e.Valid() {
mails = append(mails, e.Address)
}
}
return mails
}
// Errors gets a list of all errors. The returned error is a multierror
// (github.com/hashicorp/go-multierror).
func (l List) Errors() (errs error) {
for _, a := range l {
if !a.Valid() {
errs = multierror.Append(errs, a.err)
}
}
return errs
}
// ValidAddresses returns a copy of the list which only includes valid email
// addresses.
func (l List) ValidAddresses() (valid List) {
for _, addr := range l {
if addr.Valid() {
valid = append(valid, addr)
}
}
return valid
}
// ContainsAddress reports if the list contains the specified email address.
func (l List) ContainsAddress(address string) bool {
for _, addr := range l {
if strings.EqualFold(addr.Address, address) {
return true
}
}
return false
}
// ContainsDomain reports if the list contains one or more addresses with the
// given domain.
func (l List) ContainsDomain(domain string) bool {
for _, addr := range l {
if strings.EqualFold(addr.Domain(), domain) {
return true
}
}
return false
}
// Sort keys
const (
ByAddress = iota
ByName
)
// Sort the list in-place using one of the By* keys.
func (l List) Sort(key int8) {
var sortFunc func(int, int) bool
switch key {
case ByAddress:
sortFunc = func(i, j int) bool { return l[i].Address < l[j].Address }
case ByName:
sortFunc = func(i, j int) bool { return l[i].Name < l[j].Name }
default:
panic(fmt.Sprintf("invalid sort key: %v", key))
}
sort.Slice(l, sortFunc)
}