|
@@ -9,6 +9,7 @@ import (
|
9
|
9
|
"bufio"
|
10
|
10
|
"crypto/tls"
|
11
|
11
|
"encoding/base64"
|
|
12
|
+ "errors"
|
12
|
13
|
"fmt"
|
13
|
14
|
"log"
|
14
|
15
|
"math/rand"
|
|
@@ -39,6 +40,8 @@ var (
|
39
|
40
|
|
40
|
41
|
// common error responses
|
41
|
42
|
couldNotParseIPMsg, _ = (&[]ircmsg.IrcMessage{ircmsg.MakeMessage(nil, "", "ERROR", "Unable to parse your IP address")}[0]).Line()
|
|
43
|
+
|
|
44
|
+ RenamePrivsNeeded = errors.New("Only chanops can rename channels")
|
42
|
45
|
)
|
43
|
46
|
|
44
|
47
|
const (
|
|
@@ -80,8 +83,7 @@ type Server struct {
|
80
|
83
|
accountRegistration *AccountRegistration
|
81
|
84
|
accounts map[string]*ClientAccount
|
82
|
85
|
channelRegistrationEnabled bool
|
83
|
|
- channels ChannelNameMap
|
84
|
|
- channelJoinPartMutex sync.Mutex // used when joining/parting channels to prevent stomping over each others' access and all
|
|
86
|
+ channels *ChannelManager
|
85
|
87
|
checkIdent bool
|
86
|
88
|
clients *ClientLookupSet
|
87
|
89
|
commands chan Command
|
|
@@ -147,7 +149,7 @@ func NewServer(config *Config, logger *logger.Manager) (*Server, error) {
|
147
|
149
|
// initialize data structures
|
148
|
150
|
server := &Server{
|
149
|
151
|
accounts: make(map[string]*ClientAccount),
|
150
|
|
- channels: *NewChannelNameMap(),
|
|
152
|
+ channels: NewChannelManager(),
|
151
|
153
|
clients: NewClientLookupSet(),
|
152
|
154
|
commands: make(chan Command),
|
153
|
155
|
connectionLimiter: connection_limits.NewLimiter(),
|
|
@@ -553,53 +555,62 @@ func pongHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
553
|
555
|
}
|
554
|
556
|
|
555
|
557
|
// RENAME <oldchan> <newchan> [<reason>]
|
556
|
|
-//TODO(dan): Clean up this function so it doesn't look like an eldrich horror... prolly by putting it into a server.renameChannel function.
|
557
|
|
-func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
558
|
|
- // get lots of locks... make sure nobody touches anything while we're doing this
|
|
558
|
+func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage) (result bool) {
|
|
559
|
+ result = false
|
|
560
|
+
|
|
561
|
+ // TODO(slingamn, #152) clean up locking here
|
559
|
562
|
server.registeredChannelsMutex.Lock()
|
560
|
563
|
defer server.registeredChannelsMutex.Unlock()
|
561
|
|
- server.channels.ChansLock.Lock()
|
562
|
|
- defer server.channels.ChansLock.Unlock()
|
|
564
|
+
|
|
565
|
+ errorResponse := func(err error, name string) {
|
|
566
|
+ // TODO: send correct error codes, e.g., ERR_CANNOTRENAME, ERR_CHANNAMEINUSE
|
|
567
|
+ var code string
|
|
568
|
+ switch err {
|
|
569
|
+ case NoSuchChannel:
|
|
570
|
+ code = ERR_NOSUCHCHANNEL
|
|
571
|
+ case RenamePrivsNeeded:
|
|
572
|
+ code = ERR_CHANOPRIVSNEEDED
|
|
573
|
+ case InvalidChannelName:
|
|
574
|
+ code = ERR_UNKNOWNERROR
|
|
575
|
+ case ChannelNameInUse:
|
|
576
|
+ code = ERR_UNKNOWNERROR
|
|
577
|
+ default:
|
|
578
|
+ code = ERR_UNKNOWNERROR
|
|
579
|
+ }
|
|
580
|
+ client.Send(nil, server.name, code, client.getNick(), "RENAME", name, err.Error())
|
|
581
|
+ }
|
563
|
582
|
|
564
|
583
|
oldName := strings.TrimSpace(msg.Params[0])
|
565
|
584
|
newName := strings.TrimSpace(msg.Params[1])
|
566
|
|
- reason := "No reason"
|
567
|
|
- if 2 < len(msg.Params) {
|
568
|
|
- reason = msg.Params[2]
|
|
585
|
+ if oldName == "" || newName == "" {
|
|
586
|
+ errorResponse(InvalidChannelName, "<empty>")
|
|
587
|
+ return
|
569
|
588
|
}
|
570
|
|
-
|
571
|
|
- // check for all the reasons why the rename couldn't happen
|
572
|
589
|
casefoldedOldName, err := CasefoldChannel(oldName)
|
573
|
590
|
if err != nil {
|
574
|
|
- //TODO(dan): Change this to ERR_CANNOTRENAME
|
575
|
|
- client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", oldName, "Old channel name is invalid")
|
576
|
|
- return false
|
|
591
|
+ errorResponse(InvalidChannelName, oldName)
|
|
592
|
+ return
|
577
|
593
|
}
|
578
|
|
-
|
579
|
|
- channel := server.channels.Chans[casefoldedOldName]
|
580
|
|
- if channel == nil {
|
581
|
|
- client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, oldName, "No such channel")
|
582
|
|
- return false
|
|
594
|
+ casefoldedNewName, err := CasefoldChannel(newName)
|
|
595
|
+ if err != nil {
|
|
596
|
+ errorResponse(InvalidChannelName, newName)
|
|
597
|
+ return
|
583
|
598
|
}
|
584
|
599
|
|
585
|
|
- //TODO(dan): allow IRCops to do this?
|
586
|
|
- if !channel.ClientIsAtLeast(client, Operator) {
|
587
|
|
- client.Send(nil, server.name, ERR_CHANOPRIVSNEEDED, client.nick, oldName, "Only chanops can rename channels")
|
588
|
|
- return false
|
|
600
|
+ reason := "No reason"
|
|
601
|
+ if 2 < len(msg.Params) {
|
|
602
|
+ reason = msg.Params[2]
|
589
|
603
|
}
|
590
|
604
|
|
591
|
|
- casefoldedNewName, err := CasefoldChannel(newName)
|
592
|
|
- if err != nil {
|
593
|
|
- //TODO(dan): Change this to ERR_CANNOTRENAME
|
594
|
|
- client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", newName, "New channel name is invalid")
|
595
|
|
- return false
|
|
605
|
+ channel := server.channels.Get(oldName)
|
|
606
|
+ if channel == nil {
|
|
607
|
+ errorResponse(NoSuchChannel, oldName)
|
|
608
|
+ return
|
596
|
609
|
}
|
597
|
|
-
|
598
|
|
- newChannel := server.channels.Chans[casefoldedNewName]
|
599
|
|
- if newChannel != nil {
|
600
|
|
- //TODO(dan): Change this to ERR_CHANNAMEINUSE
|
601
|
|
- client.Send(nil, server.name, ERR_UNKNOWNERROR, client.nick, "RENAME", newName, "New channel name is in use")
|
602
|
|
- return false
|
|
610
|
+ //TODO(dan): allow IRCops to do this?
|
|
611
|
+ if !channel.ClientIsAtLeast(client, Operator) {
|
|
612
|
+ errorResponse(RenamePrivsNeeded, oldName)
|
|
613
|
+ return
|
603
|
614
|
}
|
604
|
615
|
|
605
|
616
|
var canEdit bool
|
|
@@ -622,11 +633,11 @@ func renameHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
622
|
633
|
}
|
623
|
634
|
|
624
|
635
|
// perform the channel rename
|
625
|
|
- server.channels.Chans[casefoldedOldName] = nil
|
626
|
|
- server.channels.Chans[casefoldedNewName] = channel
|
627
|
|
-
|
628
|
|
- channel.name = strings.TrimSpace(msg.Params[1])
|
629
|
|
- channel.nameCasefolded = casefoldedNewName
|
|
636
|
+ err = server.channels.Rename(oldName, newName)
|
|
637
|
+ if err != nil {
|
|
638
|
+ errorResponse(err, newName)
|
|
639
|
+ return
|
|
640
|
+ }
|
630
|
641
|
|
631
|
642
|
// rename stored channel info if any exists
|
632
|
643
|
server.store.Update(func(tx *buntdb.Tx) error {
|
|
@@ -679,34 +690,15 @@ func joinHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
679
|
690
|
keys = strings.Split(msg.Params[1], ",")
|
680
|
691
|
}
|
681
|
692
|
|
682
|
|
- // get lock
|
683
|
|
- server.channelJoinPartMutex.Lock()
|
684
|
|
- defer server.channelJoinPartMutex.Unlock()
|
685
|
|
-
|
686
|
693
|
for i, name := range channels {
|
687
|
|
- casefoldedName, err := CasefoldChannel(name)
|
688
|
|
- if err != nil {
|
689
|
|
- if len(name) > 0 {
|
690
|
|
- client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, name, "No such channel")
|
691
|
|
- }
|
692
|
|
- continue
|
693
|
|
- }
|
694
|
|
-
|
695
|
|
- channel := server.channels.Get(casefoldedName)
|
696
|
|
- if channel == nil {
|
697
|
|
- if len(casefoldedName) > server.getLimits().ChannelLen {
|
698
|
|
- client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, name, "No such channel")
|
699
|
|
- continue
|
700
|
|
- }
|
701
|
|
- channel = NewChannel(server, name, true)
|
702
|
|
- }
|
703
|
|
-
|
704
|
694
|
var key string
|
705
|
695
|
if len(keys) > i {
|
706
|
696
|
key = keys[i]
|
707
|
697
|
}
|
708
|
|
-
|
709
|
|
- channel.Join(client, key)
|
|
698
|
+ err := server.channels.Join(client, name, key)
|
|
699
|
+ if err == NoSuchChannel {
|
|
700
|
+ client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.getNick(), name, "No such channel")
|
|
701
|
+ }
|
710
|
702
|
}
|
711
|
703
|
return false
|
712
|
704
|
}
|
|
@@ -719,22 +711,11 @@ func partHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
719
|
711
|
reason = msg.Params[1]
|
720
|
712
|
}
|
721
|
713
|
|
722
|
|
- // get lock
|
723
|
|
- server.channelJoinPartMutex.Lock()
|
724
|
|
- defer server.channelJoinPartMutex.Unlock()
|
725
|
|
-
|
726
|
714
|
for _, chname := range channels {
|
727
|
|
- casefoldedChannelName, err := CasefoldChannel(chname)
|
728
|
|
- channel := server.channels.Get(casefoldedChannelName)
|
729
|
|
-
|
730
|
|
- if err != nil || channel == nil {
|
731
|
|
- if len(chname) > 0 {
|
732
|
|
- client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel")
|
733
|
|
- }
|
734
|
|
- continue
|
|
715
|
+ err := server.channels.Part(client, chname, reason)
|
|
716
|
+ if err == NoSuchChannel {
|
|
717
|
+ client.Send(nil, server.name, ERR_NOSUCHCHANNEL, client.nick, chname, "No such channel")
|
735
|
718
|
}
|
736
|
|
-
|
737
|
|
- channel.Part(client, reason)
|
738
|
719
|
}
|
739
|
720
|
return false
|
740
|
721
|
}
|
|
@@ -1096,11 +1077,9 @@ func whoHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
1096
|
1077
|
//}
|
1097
|
1078
|
|
1098
|
1079
|
if mask == "" {
|
1099
|
|
- server.channels.ChansLock.RLock()
|
1100
|
|
- for _, channel := range server.channels.Chans {
|
|
1080
|
+ for _, channel := range server.channels.Channels() {
|
1101
|
1081
|
whoChannel(client, channel, friends)
|
1102
|
1082
|
}
|
1103
|
|
- server.channels.ChansLock.RUnlock()
|
1104
|
1083
|
} else if mask[0] == '#' {
|
1105
|
1084
|
// TODO implement wildcard matching
|
1106
|
1085
|
//TODO(dan): ^ only for opers
|
|
@@ -1859,8 +1838,7 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
1859
|
1838
|
}
|
1860
|
1839
|
|
1861
|
1840
|
if len(channels) == 0 {
|
1862
|
|
- server.channels.ChansLock.RLock()
|
1863
|
|
- for _, channel := range server.channels.Chans {
|
|
1841
|
+ for _, channel := range server.channels.Channels() {
|
1864
|
1842
|
if !client.flags[Operator] && channel.flags[Secret] {
|
1865
|
1843
|
continue
|
1866
|
1844
|
}
|
|
@@ -1868,7 +1846,6 @@ func listHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
1868
|
1846
|
client.RplList(channel)
|
1869
|
1847
|
}
|
1870
|
1848
|
}
|
1871
|
|
- server.channels.ChansLock.RUnlock()
|
1872
|
1849
|
} else {
|
1873
|
1850
|
// limit regular users to only listing one channel
|
1874
|
1851
|
if !client.flags[Operator] {
|
|
@@ -1922,11 +1899,9 @@ func namesHandler(server *Server, client *Client, msg ircmsg.IrcMessage) bool {
|
1922
|
1899
|
//}
|
1923
|
1900
|
|
1924
|
1901
|
if len(channels) == 0 {
|
1925
|
|
- server.channels.ChansLock.RLock()
|
1926
|
|
- for _, channel := range server.channels.Chans {
|
|
1902
|
+ for _, channel := range server.channels.Channels() {
|
1927
|
1903
|
channel.Names(client)
|
1928
|
1904
|
}
|
1929
|
|
- server.channels.ChansLock.RUnlock()
|
1930
|
1905
|
return false
|
1931
|
1906
|
}
|
1932
|
1907
|
|