|
@@ -6,6 +6,7 @@ package irc
|
6
|
6
|
import (
|
7
|
7
|
"fmt"
|
8
|
8
|
"sync"
|
|
9
|
+ "sync/atomic"
|
9
|
10
|
"time"
|
10
|
11
|
|
11
|
12
|
"github.com/goshuirc/irc-go/ircfmt"
|
|
@@ -180,33 +181,50 @@ type NickTimer struct {
|
180
|
181
|
sync.Mutex // tier 1
|
181
|
182
|
|
182
|
183
|
// immutable after construction
|
183
|
|
- timeout time.Duration
|
184
|
|
- client *Client
|
|
184
|
+ client *Client
|
185
|
185
|
|
186
|
186
|
// mutable
|
187
|
|
- stopped bool
|
188
|
187
|
nick string
|
189
|
188
|
accountForNick string
|
190
|
189
|
account string
|
|
190
|
+ timeout time.Duration
|
191
|
191
|
timer *time.Timer
|
|
192
|
+ enabled uint32
|
192
|
193
|
}
|
193
|
194
|
|
194
|
|
-// NewNickTimer sets up a new nick timer (returning nil if timeout enforcement is not enabled)
|
195
|
|
-func NewNickTimer(client *Client) *NickTimer {
|
196
|
|
- config := client.server.AccountConfig().NickReservation
|
197
|
|
- if !(config.Enabled && (config.Method == NickReservationWithTimeout || config.AllowCustomEnforcement)) {
|
198
|
|
- return nil
|
|
195
|
+// Initialize sets up a NickTimer, based on server config settings.
|
|
196
|
+func (nt *NickTimer) Initialize(client *Client) {
|
|
197
|
+ if nt.client == nil {
|
|
198
|
+ nt.client = client // placate the race detector
|
199
|
199
|
}
|
200
|
200
|
|
201
|
|
- return &NickTimer{
|
202
|
|
- client: client,
|
203
|
|
- timeout: config.RenameTimeout,
|
|
201
|
+ config := &client.server.Config().Accounts.NickReservation
|
|
202
|
+ enabled := config.Enabled && (config.Method == NickReservationWithTimeout || config.AllowCustomEnforcement)
|
|
203
|
+
|
|
204
|
+ nt.Lock()
|
|
205
|
+ defer nt.Unlock()
|
|
206
|
+ nt.timeout = config.RenameTimeout
|
|
207
|
+ if enabled {
|
|
208
|
+ atomic.StoreUint32(&nt.enabled, 1)
|
|
209
|
+ } else {
|
|
210
|
+ nt.stopInternal()
|
204
|
211
|
}
|
205
|
212
|
}
|
206
|
213
|
|
|
214
|
+func (nt *NickTimer) Enabled() bool {
|
|
215
|
+ return atomic.LoadUint32(&nt.enabled) == 1
|
|
216
|
+}
|
|
217
|
+
|
|
218
|
+func (nt *NickTimer) Timeout() (timeout time.Duration) {
|
|
219
|
+ nt.Lock()
|
|
220
|
+ timeout = nt.timeout
|
|
221
|
+ nt.Unlock()
|
|
222
|
+ return
|
|
223
|
+}
|
|
224
|
+
|
207
|
225
|
// Touch records a nick change and updates the timer as necessary
|
208
|
226
|
func (nt *NickTimer) Touch() {
|
209
|
|
- if nt == nil {
|
|
227
|
+ if !nt.Enabled() {
|
210
|
228
|
return
|
211
|
229
|
}
|
212
|
230
|
|
|
@@ -215,16 +233,12 @@ func (nt *NickTimer) Touch() {
|
215
|
233
|
accountForNick, method := nt.client.server.accounts.EnforcementStatus(cfnick, skeleton)
|
216
|
234
|
enforceTimeout := method == NickReservationWithTimeout
|
217
|
235
|
|
218
|
|
- var shouldWarn bool
|
|
236
|
+ var shouldWarn, shouldRename bool
|
219
|
237
|
|
220
|
238
|
func() {
|
221
|
239
|
nt.Lock()
|
222
|
240
|
defer nt.Unlock()
|
223
|
241
|
|
224
|
|
- if nt.stopped {
|
225
|
|
- return
|
226
|
|
- }
|
227
|
|
-
|
228
|
242
|
// the timer will not reset as long as the squatter is targeting the same account
|
229
|
243
|
accountChanged := accountForNick != nt.accountForNick
|
230
|
244
|
// change state
|
|
@@ -237,38 +251,39 @@ func (nt *NickTimer) Touch() {
|
237
|
251
|
nt.timer.Stop()
|
238
|
252
|
nt.timer = nil
|
239
|
253
|
}
|
240
|
|
- if enforceTimeout && delinquent && accountChanged {
|
|
254
|
+ if enforceTimeout && delinquent && (accountChanged || nt.timer == nil) {
|
241
|
255
|
nt.timer = time.AfterFunc(nt.timeout, nt.processTimeout)
|
242
|
256
|
shouldWarn = true
|
|
257
|
+ } else if method == NickReservationStrict && delinquent {
|
|
258
|
+ shouldRename = true // this can happen if reservation was enabled by rehash
|
243
|
259
|
}
|
244
|
260
|
}()
|
245
|
261
|
|
246
|
262
|
if shouldWarn {
|
247
|
|
- nt.sendWarning()
|
|
263
|
+ nt.client.Send(nil, "NickServ", "NOTICE", nt.client.Nick(), fmt.Sprintf(ircfmt.Unescape(nt.client.t(nsTimeoutNotice)), nt.Timeout()))
|
|
264
|
+ } else if shouldRename {
|
|
265
|
+ nt.client.Notice(nt.client.t("Nickname is reserved by a different account"))
|
|
266
|
+ nt.client.server.RandomlyRename(nt.client)
|
248
|
267
|
}
|
249
|
268
|
}
|
250
|
269
|
|
251
|
270
|
// Stop stops counting time and cleans up the timer
|
252
|
271
|
func (nt *NickTimer) Stop() {
|
253
|
|
- if nt == nil {
|
254
|
|
- return
|
255
|
|
- }
|
256
|
|
-
|
257
|
272
|
nt.Lock()
|
258
|
273
|
defer nt.Unlock()
|
|
274
|
+ nt.stopInternal()
|
|
275
|
+}
|
|
276
|
+
|
|
277
|
+func (nt *NickTimer) stopInternal() {
|
259
|
278
|
if nt.timer != nil {
|
260
|
279
|
nt.timer.Stop()
|
261
|
280
|
nt.timer = nil
|
262
|
281
|
}
|
263
|
|
- nt.stopped = true
|
264
|
|
-}
|
265
|
|
-
|
266
|
|
-func (nt *NickTimer) sendWarning() {
|
267
|
|
- nt.client.Send(nil, "NickServ", "NOTICE", nt.client.Nick(), fmt.Sprintf(ircfmt.Unescape(nt.client.t(nsTimeoutNotice)), nt.timeout))
|
|
282
|
+ atomic.StoreUint32(&nt.enabled, 0)
|
268
|
283
|
}
|
269
|
284
|
|
270
|
285
|
func (nt *NickTimer) processTimeout() {
|
271
|
286
|
baseMsg := "Nick is reserved and authentication timeout expired: %v"
|
272
|
|
- nt.client.Notice(fmt.Sprintf(nt.client.t(baseMsg), nt.timeout))
|
|
287
|
+ nt.client.Notice(fmt.Sprintf(nt.client.t(baseMsg), nt.Timeout()))
|
273
|
288
|
nt.client.server.RandomlyRename(nt.client)
|
274
|
289
|
}
|