2 goircd -- minimalistic simple Internet Relay Chat (IRC) server
3 Copyright (C) 2014 Sergey Matveev <stargrave@stargrave.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 // Sanitize room's name. It can consist of 1 to 50 ASCII symbols
29 // with some exclusions. All room names will have "#" prefix.
30 func RoomNameSanitize(name string) (n string, valid bool) {
31 n = strings.TrimLeft(strings.ToLower(name), "&#+!")
32 valid, _ = regexp.MatchString("^[^\x00\x07\x0a\x0d ,:/]{1,50}$", n)
40 members map[*Client]bool
42 log_sink chan LogEvent
43 state_sink chan StateEvent
46 func NewRoom(hostname, name string, log_sink chan LogEvent, state_sink chan StateEvent) *Room {
47 room := Room{name: name}
48 room.members = make(map[*Client]bool)
51 room.hostname = hostname
52 room.log_sink = log_sink
53 room.state_sink = state_sink
57 func (room *Room) SendTopic(client *Client) {
59 client.ReplyNicknamed("331", room.name, "No topic is set")
61 client.ReplyNicknamed("332", room.name, room.topic)
65 // Send message to all room's subscribers, possibly excluding someone
66 func (room *Room) Broadcast(msg string, client_to_ignore ...*Client) {
67 for member := range room.members {
68 if (len(client_to_ignore) > 0) && member == client_to_ignore[0] {
75 func (room *Room) StateSave() {
76 room.state_sink <- StateEvent{room.name, room.topic, room.key}
79 func (room *Room) Processor(events chan ClientEvent) {
81 for event := range events {
83 switch event.event_type {
85 room.members[client] = true
86 log.Println(client, "joined", room.name)
87 room.SendTopic(client)
88 go room.Broadcast(fmt.Sprintf(":%s JOIN %s", client, room.name))
89 room.log_sink <- LogEvent{room.name, client.nickname, "joined", true}
90 nicknames := []string{}
91 for member := range room.members {
92 nicknames = append(nicknames, member.nickname)
94 sort.Strings(nicknames)
95 client.ReplyNicknamed("353", "=", room.name, strings.Join(nicknames, " "))
96 client.ReplyNicknamed("366", room.name, "End of NAMES list")
98 if _, subscribed := room.members[client]; !subscribed {
99 client.ReplyNicknamed("442", room.name, "You are not on that channel")
102 delete(room.members, client)
103 msg := fmt.Sprintf(":%s PART %s :%s", client, room.name, client.nickname)
104 go room.Broadcast(msg)
105 room.log_sink <- LogEvent{room.name, client.nickname, "left", true}
107 if _, subscribed := room.members[client]; !subscribed {
108 client.ReplyParts("442", room.name, "You are not on that channel")
111 if event.text == "" {
112 go room.SendTopic(client)
115 room.topic = strings.TrimLeft(event.text, ":")
116 msg := fmt.Sprintf(":%s TOPIC %s :%s", client, room.name, room.topic)
117 go room.Broadcast(msg)
118 room.log_sink <- LogEvent{room.name, client.nickname, "set topic to " + room.topic, true}
121 for m := range room.members {
122 client.ReplyNicknamed("352", room.name, m.username, m.conn.RemoteAddr().String(), room.hostname, m.nickname, "H", "0 "+m.realname)
124 client.ReplyNicknamed("315", room.name, "End of WHO list")
126 if event.text == "" {
131 client.Msg(fmt.Sprintf("324 %s %s %s", client.nickname, room.name, mode))
134 if strings.HasPrefix(event.text, "-k") || strings.HasPrefix(event.text, "+k") {
135 if _, subscribed := room.members[client]; !subscribed {
136 client.ReplyParts("442", room.name, "You are not on that channel")
140 client.ReplyNicknamed("472", event.text, "Unknown MODE flag")
145 if strings.HasPrefix(event.text, "+k") {
146 cols := strings.Split(event.text, " ")
148 client.ReplyNotEnoughParameters("MODE")
152 msg = fmt.Sprintf(":%s MODE %s +k %s", client, room.name, room.key)
153 msg_log = "set channel key to " + room.key
154 } else if strings.HasPrefix(event.text, "-k") {
156 msg = fmt.Sprintf(":%s MODE %s -k", client, room.name)
157 msg_log = "removed channel key"
159 go room.Broadcast(msg)
160 room.log_sink <- LogEvent{room.name, client.nickname, msg_log, true}
163 sep := strings.Index(event.text, " ")
164 go room.Broadcast(fmt.Sprintf(":%s %s %s :%s", client, event.text[:sep], room.name, event.text[sep+1:]), client)
165 room.log_sink <- LogEvent{room.name, client.nickname, event.text[sep+1:], false}