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/>.
42 type ClientAlivenessState struct {
47 func (client Client) String() string {
48 return client.nickname + "!" + client.username + "@" + client.conn.RemoteAddr().String()
51 func NewClient(hostname string, conn net.Conn) *Client {
52 return &Client{hostname: hostname, conn: conn, nickname: "*"}
55 // Client processor blockingly reads everything remote client sends,
56 // splits messages by CRLF and send them to Daemon gorouting for processing
57 // it futher. Also it can signalize that client is unavailable (disconnected).
58 func (client *Client) Processor(sink chan<- ClientEvent) {
60 buf := make([]byte, 0)
61 log.Println(client, "New client")
62 sink <- ClientEvent{client, EVENT_NEW, ""}
64 buf_net = make([]byte, BUF_SIZE)
65 _, err := client.conn.Read(buf_net)
67 log.Println(client, "connection lost", err)
68 sink <- ClientEvent{client, EVENT_DEL, ""}
71 buf_net = bytes.TrimRight(buf_net, "\x00")
72 buf = append(buf, buf_net...)
73 if !bytes.HasSuffix(buf, []byte(CRLF)) {
76 for _, msg := range bytes.Split(buf[:len(buf)-2], []byte(CRLF)) {
78 sink <- ClientEvent{client, EVENT_MSG, string(msg)}
85 // Send message as is with CRLF appended.
86 func (client *Client) Msg(text string) {
87 client.conn.Write([]byte(text + CRLF))
90 // Send message from server. It has ": servername" prefix.
91 func (client *Client) Reply(text string) {
92 client.Msg(":" + client.hostname + " " + text)
95 // Send server message, concatenating all provided text parts and
96 // prefix the last one with ":".
97 func (client *Client) ReplyParts(code string, text ...string) {
98 parts := []string{code}
99 for _, t := range text {
100 parts = append(parts, t)
102 parts[len(parts)-1] = ":" + parts[len(parts)-1]
103 client.Reply(strings.Join(parts, " "))
106 // Send nicknamed server message. After servername it always has target
107 // client's nickname. The last part is prefixed with ":".
108 func (client *Client) ReplyNicknamed(code string, text ...string) {
109 client.ReplyParts(code, append([]string{client.nickname}, text...)...)
112 // Reply "461 not enough parameters" error for given command.
113 func (client *Client) ReplyNotEnoughParameters(command string) {
114 client.ReplyNicknamed("461", command, "Not enough parameters")
117 // Reply "403 no such channel" error for specified channel.
118 func (client *Client) ReplyNoChannel(channel string) {
119 client.ReplyNicknamed("403", channel, "No such channel")
122 func (client *Client) ReplyNoNickChan(channel string) {
123 client.ReplyNicknamed("401", channel, "No such nick/channel")