-
Notifications
You must be signed in to change notification settings - Fork 178
/
isupport.go
147 lines (122 loc) · 3.73 KB
/
isupport.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
// Copyright (c) 2016- Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package irc
import "fmt"
const isupportSupportedString = "are supported by this server"
const maxISupportLength = 400 // Max length of a single ISUPPORT token line
// ISupportList holds a list of ISUPPORT tokens
type ISupportList struct {
Tokens map[string]*string
CachedReply [][]string
}
// NewISupportList returns a new ISupportList
func NewISupportList() *ISupportList {
var il ISupportList
il.Tokens = make(map[string]*string)
il.CachedReply = make([][]string, 0)
return &il
}
// Add adds an RPL_ISUPPORT token to our internal list
func (il *ISupportList) Add(name string, value string) {
il.Tokens[name] = &value
}
// AddNoValue adds an RPL_ISUPPORT token that does not have a value
func (il *ISupportList) 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 *ISupportList) GetDifference(newil *ISupportList) [][]string {
replies := make([][]string, 0)
var length int // Length of the current cache
var cache []string // Token list cache
// append removed tokens
for name := range il.Tokens {
_, exists := newil.Tokens[name]
if exists {
continue
}
token := fmt.Sprintf("-%s", name)
if len(token)+length <= maxISupportLength {
// 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 >= maxISupportLength {
cache = append(cache, isupportSupportedString)
replies = append(replies, cache)
cache = make([]string, 0)
length = 0
}
}
// append added tokens
for name, value := range newil.Tokens {
newval, exists := il.Tokens[name]
if exists && *value == *newval {
continue
}
token := getTokenString(name, value)
if len(token)+length <= maxISupportLength {
// 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 >= maxISupportLength {
cache = append(cache, isupportSupportedString)
replies = append(replies, cache)
cache = make([]string, 0)
length = 0
}
}
if len(cache) > 0 {
cache = append(cache, isupportSupportedString)
replies = append(replies, cache)
}
return replies
}
// RegenerateCachedReply regenerates the cached RPL_ISUPPORT reply
func (il *ISupportList) RegenerateCachedReply() {
il.CachedReply = make([][]string, 0)
var length int // Length of the current cache
var cache []string // Token list cache
for name, value := range il.Tokens {
token := getTokenString(name, value)
if len(token)+length <= maxISupportLength {
// 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 >= maxISupportLength {
cache = append(cache, isupportSupportedString)
il.CachedReply = append(il.CachedReply, cache)
cache = make([]string, 0)
length = 0
}
}
if len(cache) > 0 {
cache = append(cache, isupportSupportedString)
il.CachedReply = append(il.CachedReply, cache)
}
}
// RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
func (client *Client) RplISupport() {
for _, tokenline := range client.server.isupport.CachedReply {
// ugly trickery ahead
client.Send(nil, client.server.name, RPL_ISUPPORT, append([]string{client.nick}, tokenline...)...)
}
}