-
Notifications
You must be signed in to change notification settings - Fork 179
/
list.go
152 lines (123 loc) · 3.33 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
// Copyright (c) 2016 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package isupport
import (
"fmt"
"sort"
"strings"
)
const (
maxLastArgLength = 400
)
// List holds a list of ISUPPORT tokens
type List struct {
Tokens map[string]*string
CachedReply [][]string
}
// NewList returns a new List
func NewList() *List {
var il List
il.Initialize()
return &il
}
func (il *List) Initialize() {
il.Tokens = make(map[string]*string)
il.CachedReply = make([][]string, 0)
}
// Add adds an RPL_ISUPPORT token to our internal list
func (il *List) Add(name string, value string) {
il.Tokens[name] = &value
}
// AddNoValue adds an RPL_ISUPPORT token that does not have a value
func (il *List) AddNoValue(name string) {
il.Tokens[name] = nil
}
// getTokenString gets the appropriate string for a token+value.
func getTokenString(name string, value *string) string {
if value == nil {
return name
}
return fmt.Sprintf("%s=%s", name, *value)
}
// GetDifference returns the difference between two token lists.
func (il *List) GetDifference(newil *List) [][]string {
var outTokens sort.StringSlice
// append removed tokens
for name := range il.Tokens {
_, exists := newil.Tokens[name]
if exists {
continue
}
token := fmt.Sprintf("-%s", name)
outTokens = append(outTokens, token)
}
// append added tokens
for name, value := range newil.Tokens {
newval, exists := il.Tokens[name]
if exists && ((value == nil && newval == nil) || (value != nil && newval != nil && *value == *newval)) {
continue
}
token := getTokenString(name, value)
outTokens = append(outTokens, token)
}
sort.Sort(outTokens)
// create output list
replies := make([][]string, 0)
var length int // Length of the current cache
var cache []string // Token list cache
for _, token := range outTokens {
if len(token)+length <= maxLastArgLength {
// account for the space separating tokens
if len(cache) > 0 {
length++
}
cache = append(cache, token)
length += len(token)
}
if len(cache) == 13 || len(token)+length >= maxLastArgLength {
replies = append(replies, cache)
cache = make([]string, 0)
length = 0
}
}
if len(cache) > 0 {
replies = append(replies, cache)
}
return replies
}
// RegenerateCachedReply regenerates the cached RPL_ISUPPORT reply
func (il *List) RegenerateCachedReply() (err error) {
il.CachedReply = make([][]string, 0)
var length int // Length of the current cache
var cache []string // Token list cache
// make sure we get a sorted list of tokens, needed for tests and looks nice
var tokens sort.StringSlice
for name := range il.Tokens {
tokens = append(tokens, name)
}
sort.Sort(tokens)
for _, name := range tokens {
token := getTokenString(name, il.Tokens[name])
if token[0] == ':' || strings.Contains(token, " ") {
err = fmt.Errorf("bad isupport token (cannot contain spaces or start with :): %s", token)
continue
}
if len(token)+length <= maxLastArgLength {
// account for the space separating tokens
if len(cache) > 0 {
length++
}
cache = append(cache, token)
length += len(token)
}
if len(cache) == 13 || len(token)+length >= maxLastArgLength {
il.CachedReply = append(il.CachedReply, cache)
cache = make([]string, 0)
length = 0
}
}
if len(cache) > 0 {
il.CachedReply = append(il.CachedReply, cache)
}
return
}