Initial commit

This commit is contained in:
Trevor Slocum 2016-08-25 22:50:24 -07:00
commit 528fd03f6f
12 changed files with 1040 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
anonircd

1
README Normal file
View File

@ -0,0 +1 @@
how do i shot web

118
anonircd.go Normal file
View File

@ -0,0 +1,118 @@
package main
import (
"net"
"log"
"sync"
"math/rand"
irc "gopkg.in/sorcix/irc.v2"
"fmt"
"time"
)
const (
MSG_RAW = 0
MSG_COMMAND = 1
MSG_PING = 2
)
type Channel struct {
clients Client
}
type Client struct {
identifier string
conn net.Conn
writebuffer chan *irc.Message
reader *irc.Decoder
writer *irc.Encoder
}
/*
func (c *Client) Send(message Message) {
c.conn.wr <- message
}*/
type Server struct {
sync.Mutex
channels map[string]Channel
clients map[string]*Client
}
const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
func randomIdentifier() string {
b := make([]byte, 10)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
func handleRead(c *Client, server *Server) {
for {
c.conn.SetDeadline(time.Now().Add(300 * time.Second))
msg, err := c.reader.Decode()
if err != nil {
//return c.Reconnect()
}
fmt.Println("%#v", msg)
fmt.Println("PREFIX: " + fmt.Sprintf("%v", msg.Prefix))
fmt.Println("COMMAND: " + fmt.Sprintf("%v", msg.Command))
fmt.Println("PARAMS: " + fmt.Sprintf("%v", msg.Params))
if (msg.Command == irc.CAP && len(msg.Params) > 0 && (msg.Params[0] == irc.CAP_LS || msg.Params[0] == irc.CAP_LIST)) {
fmt.Println("WAS CAP")
response := irc.Message{nil, irc.CAP, []string{"*", msg.Params[0], ""}}
c.writebuffer <- &response
}
prfx := irc.Prefix{Name: "tee"}
for _, sclient := range server.clients {
msgout := irc.Message{&prfx, irc.PRIVMSG, []string{"#test", msg.Trailing()}}
sclient.writebuffer <- &msgout
}
}
}
func handleWrite(c *Client, server *Server) {
for msg := range c.writebuffer {
c.writer.Encode(msg)
}
}
func handleConnection(conn net.Conn, server *Server) {
messages := make(chan *irc.Message)
client := Client{randomIdentifier(), conn, messages, irc.NewDecoder(conn), irc.NewEncoder(conn)}
server.Lock()
server.clients[client.identifier] = &client
server.Unlock()
defer conn.Close()
go handleRead(&client, server)
handleWrite(&client, server)
}
func listen(server *Server) {
ln, err := net.Listen("tcp", ":6667")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
for {
conn, err := ln.Accept()
if err != nil {
continue
}
go handleConnection(conn, server)
}
}
func main() {
server := Server{
clients: make(map[string]*Client),
channels: make(map[string]Channel)}
listen(&server)
}

22
vendor/gopkg.in/sorcix/irc.v2/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
Copyright 2014 Vic Demuzere
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

60
vendor/gopkg.in/sorcix/irc.v2/README.md generated vendored Normal file
View File

@ -0,0 +1,60 @@
# Go **irc** package
[![Build Status](https://travis-ci.org/sorcix/irc.svg?branch=v2)](https://travis-ci.org/sorcix/irc)
[![GoDoc](https://godoc.org/gopkg.in/sorcix/irc.v2?status.svg)](https://godoc.org/gopkg.in/sorcix/irc.v2)
## Features
Package irc allows your application to speak the IRC protocol.
- **Limited scope**, does one thing and does it well.
- Focus on simplicity and **speed**.
- **Stable API**: updates shouldn't break existing software.
- Well [documented][Documentation] code.
*This package does not manage your entire IRC connection. It only translates the protocol to easy to use Go types. It is meant as a single component in a larger IRC library, or for basic IRC bots for which a large IRC package would be overkill.*
## Usage
```
import "gopkg.in/sorcix/irc.v2"
```
### Message
The [Message][] and [Prefix][] types provide translation to and from IRC message format.
// Parse the IRC-encoded data and stores the result in a new struct.
message := irc.ParseMessage(raw)
// Returns the IRC encoding of the message.
raw = message.String()
### Encoder & Decoder
The [Encoder][] and [Decoder][] types allow working with IRC message streams.
// Create a decoder that reads from given io.Reader
dec := irc.NewDecoder(reader)
// Decode the next IRC message
message, err := dec.Decode()
// Create an encoder that writes to given io.Writer
enc := irc.NewEncoder(writer)
// Send a message to the writer.
enc.Encode(message)
### Conn
The [Conn][] type combines an [Encoder][] and [Decoder][] for a duplex connection.
c, err := irc.Dial("irc.server.net:6667")
// Methods from both Encoder and Decoder are available
message, err := c.Decode()
[Documentation]: https://godoc.org/gopkg.in/sorcix/irc.v2 "Package documentation by Godoc.org"
[Message]: https://godoc.org/gopkg.in/sorcix/irc.v2#Message "Message type documentation"
[Prefix]: https://godoc.org/gopkg.in/sorcix/irc.v2#Prefix "Prefix type documentation"
[Encoder]: https://godoc.org/gopkg.in/sorcix/irc.v2#Encoder "Encoder type documentation"
[Decoder]: https://godoc.org/gopkg.in/sorcix/irc.v2#Decoder "Decoder type documentation"
[Conn]: https://godoc.org/gopkg.in/sorcix/irc.v2#Conn "Conn type documentation"
[RFC1459]: https://tools.ietf.org/html/rfc1459.html "RFC 1459"

298
vendor/gopkg.in/sorcix/irc.v2/constants.go generated vendored Normal file
View File

@ -0,0 +1,298 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package irc
// Various prefixes extracted from RFC1459.
const (
Channel = '#' // Normal channel
Distributed = '&' // Distributed channel
Owner = '~' // Channel owner +q (non-standard)
Admin = '&' // Channel admin +a (non-standard)
Operator = '@' // Channel operator +o
HalfOperator = '%' // Channel half operator +h (non-standard)
Voice = '+' // User has voice +v
)
// User modes as defined by RFC1459 section 4.2.3.2.
const (
UserModeInvisible = 'i' // User is invisible
UserModeServerNotices = 's' // User wants to receive server notices
UserModeWallops = 'w' // User wants to receive Wallops
UserModeOperator = 'o' // Server operator
)
// Channel modes as defined by RFC1459 section 4.2.3.1
const (
ModeOperator = 'o' // Operator privileges
ModeVoice = 'v' // Ability to speak on a moderated channel
ModePrivate = 'p' // Private channel
ModeSecret = 's' // Secret channel
ModeInviteOnly = 'i' // Users can't join without invite
ModeTopic = 't' // Topic can only be set by an operator
ModeModerated = 'm' // Only voiced users and operators can talk
ModeLimit = 'l' // User limit
ModeKey = 'k' // Channel password
ModeOwner = 'q' // Owner privileges (non-standard)
ModeAdmin = 'a' // Admin privileges (non-standard)
ModeHalfOperator = 'h' // Half-operator privileges (non-standard)
)
// IRC commands extracted from RFC2812 section 3 and RFC2813 section 4.
const (
PASS = "PASS"
NICK = "NICK"
USER = "USER"
OPER = "OPER"
MODE = "MODE"
SERVICE = "SERVICE"
QUIT = "QUIT"
SQUIT = "SQUIT"
JOIN = "JOIN"
PART = "PART"
TOPIC = "TOPIC"
NAMES = "NAMES"
LIST = "LIST"
INVITE = "INVITE"
KICK = "KICK"
PRIVMSG = "PRIVMSG"
NOTICE = "NOTICE"
MOTD = "MOTD"
LUSERS = "LUSERS"
VERSION = "VERSION"
STATS = "STATS"
LINKS = "LINKS"
TIME = "TIME"
CONNECT = "CONNECT"
TRACE = "TRACE"
ADMIN = "ADMIN"
INFO = "INFO"
SERVLIST = "SERVLIST"
SQUERY = "SQUERY"
WHO = "WHO"
WHOIS = "WHOIS"
WHOWAS = "WHOWAS"
KILL = "KILL"
PING = "PING"
PONG = "PONG"
ERROR = "ERROR"
AWAY = "AWAY"
REHASH = "REHASH"
DIE = "DIE"
RESTART = "RESTART"
SUMMON = "SUMMON"
USERS = "USERS"
WALLOPS = "WALLOPS"
USERHOST = "USERHOST"
ISON = "ISON"
SERVER = "SERVER"
NJOIN = "NJOIN"
)
// Numeric IRC replies extracted from RFC2812 section 5.
const (
RPL_WELCOME = "001"
RPL_YOURHOST = "002"
RPL_CREATED = "003"
RPL_MYINFO = "004"
RPL_BOUNCE = "005"
RPL_ISUPPORT = "005"
RPL_USERHOST = "302"
RPL_ISON = "303"
RPL_AWAY = "301"
RPL_UNAWAY = "305"
RPL_NOWAWAY = "306"
RPL_WHOISUSER = "311"
RPL_WHOISSERVER = "312"
RPL_WHOISOPERATOR = "313"
RPL_WHOISIDLE = "317"
RPL_ENDOFWHOIS = "318"
RPL_WHOISCHANNELS = "319"
RPL_WHOWASUSER = "314"
RPL_ENDOFWHOWAS = "369"
RPL_LISTSTART = "321"
RPL_LIST = "322"
RPL_LISTEND = "323"
RPL_UNIQOPIS = "325"
RPL_CHANNELMODEIS = "324"
RPL_NOTOPIC = "331"
RPL_TOPIC = "332"
RPL_INVITING = "341"
RPL_SUMMONING = "342"
RPL_INVITELIST = "346"
RPL_ENDOFINVITELIST = "347"
RPL_EXCEPTLIST = "348"
RPL_ENDOFEXCEPTLIST = "349"
RPL_VERSION = "351"
RPL_WHOREPLY = "352"
RPL_ENDOFWHO = "315"
RPL_NAMREPLY = "353"
RPL_ENDOFNAMES = "366"
RPL_LINKS = "364"
RPL_ENDOFLINKS = "365"
RPL_BANLIST = "367"
RPL_ENDOFBANLIST = "368"
RPL_INFO = "371"
RPL_ENDOFINFO = "374"
RPL_MOTDSTART = "375"
RPL_MOTD = "372"
RPL_ENDOFMOTD = "376"
RPL_YOUREOPER = "381"
RPL_REHASHING = "382"
RPL_YOURESERVICE = "383"
RPL_TIME = "391"
RPL_USERSSTART = "392"
RPL_USERS = "393"
RPL_ENDOFUSERS = "394"
RPL_NOUSERS = "395"
RPL_TRACELINK = "200"
RPL_TRACECONNECTING = "201"
RPL_TRACEHANDSHAKE = "202"
RPL_TRACEUNKNOWN = "203"
RPL_TRACEOPERATOR = "204"
RPL_TRACEUSER = "205"
RPL_TRACESERVER = "206"
RPL_TRACESERVICE = "207"
RPL_TRACENEWTYPE = "208"
RPL_TRACECLASS = "209"
RPL_TRACERECONNECT = "210"
RPL_TRACELOG = "261"
RPL_TRACEEND = "262"
RPL_STATSLINKINFO = "211"
RPL_STATSCOMMANDS = "212"
RPL_ENDOFSTATS = "219"
RPL_STATSUPTIME = "242"
RPL_STATSOLINE = "243"
RPL_UMODEIS = "221"
RPL_SERVLIST = "234"
RPL_SERVLISTEND = "235"
RPL_LUSERCLIENT = "251"
RPL_LUSEROP = "252"
RPL_LUSERUNKNOWN = "253"
RPL_LUSERCHANNELS = "254"
RPL_LUSERME = "255"
RPL_ADMINME = "256"
RPL_ADMINLOC1 = "257"
RPL_ADMINLOC2 = "258"
RPL_ADMINEMAIL = "259"
RPL_TRYAGAIN = "263"
ERR_NOSUCHNICK = "401"
ERR_NOSUCHSERVER = "402"
ERR_NOSUCHCHANNEL = "403"
ERR_CANNOTSENDTOCHAN = "404"
ERR_TOOMANYCHANNELS = "405"
ERR_WASNOSUCHNICK = "406"
ERR_TOOMANYTARGETS = "407"
ERR_NOSUCHSERVICE = "408"
ERR_NOORIGIN = "409"
ERR_NORECIPIENT = "411"
ERR_NOTEXTTOSEND = "412"
ERR_NOTOPLEVEL = "413"
ERR_WILDTOPLEVEL = "414"
ERR_BADMASK = "415"
ERR_UNKNOWNCOMMAND = "421"
ERR_NOMOTD = "422"
ERR_NOADMININFO = "423"
ERR_FILEERROR = "424"
ERR_NONICKNAMEGIVEN = "431"
ERR_ERRONEUSNICKNAME = "432"
ERR_NICKNAMEINUSE = "433"
ERR_NICKCOLLISION = "436"
ERR_UNAVAILRESOURCE = "437"
ERR_USERNOTINCHANNEL = "441"
ERR_NOTONCHANNEL = "442"
ERR_USERONCHANNEL = "443"
ERR_NOLOGIN = "444"
ERR_SUMMONDISABLED = "445"
ERR_USERSDISABLED = "446"
ERR_NOTREGISTERED = "451"
ERR_NEEDMOREPARAMS = "461"
ERR_ALREADYREGISTRED = "462"
ERR_NOPERMFORHOST = "463"
ERR_PASSWDMISMATCH = "464"
ERR_YOUREBANNEDCREEP = "465"
ERR_YOUWILLBEBANNED = "466"
ERR_KEYSET = "467"
ERR_CHANNELISFULL = "471"
ERR_UNKNOWNMODE = "472"
ERR_INVITEONLYCHAN = "473"
ERR_BANNEDFROMCHAN = "474"
ERR_BADCHANNELKEY = "475"
ERR_BADCHANMASK = "476"
ERR_NOCHANMODES = "477"
ERR_BANLISTFULL = "478"
ERR_NOPRIVILEGES = "481"
ERR_CHANOPRIVSNEEDED = "482"
ERR_CANTKILLSERVER = "483"
ERR_RESTRICTED = "484"
ERR_UNIQOPPRIVSNEEDED = "485"
ERR_NOOPERHOST = "491"
ERR_UMODEUNKNOWNFLAG = "501"
ERR_USERSDONTMATCH = "502"
)
// IRC commands extracted from the IRCv3 spec at http://www.ircv3.org/.
const (
CAP = "CAP"
CAP_LS = "LS" // Subcommand (param)
CAP_LIST = "LIST" // Subcommand (param)
CAP_REQ = "REQ" // Subcommand (param)
CAP_ACK = "ACK" // Subcommand (param)
CAP_NAK = "NAK" // Subcommand (param)
CAP_CLEAR = "CLEAR" // Subcommand (param)
CAP_END = "END" // Subcommand (param)
AUTHENTICATE = "AUTHENTICATE"
)
// Numeric IRC replies extracted from the IRCv3 spec.
const (
RPL_LOGGEDIN = "900"
RPL_LOGGEDOUT = "901"
RPL_NICKLOCKED = "902"
RPL_SASLSUCCESS = "903"
ERR_SASLFAIL = "904"
ERR_SASLTOOLONG = "905"
ERR_SASLABORTED = "906"
ERR_SASLALREADY = "907"
RPL_SASLMECHS = "908"
)
// RFC2812, section 5.3
const (
RPL_STATSCLINE = "213"
RPL_STATSNLINE = "214"
RPL_STATSILINE = "215"
RPL_STATSKLINE = "216"
RPL_STATSQLINE = "217"
RPL_STATSYLINE = "218"
RPL_SERVICEINFO = "231"
RPL_ENDOFSERVICES = "232"
RPL_SERVICE = "233"
RPL_STATSVLINE = "240"
RPL_STATSLLINE = "241"
RPL_STATSHLINE = "244"
RPL_STATSSLINE = "245"
RPL_STATSPING = "246"
RPL_STATSBLINE = "247"
RPL_STATSDLINE = "250"
RPL_NONE = "300"
RPL_WHOISCHANOP = "316"
RPL_KILLDONE = "361"
RPL_CLOSING = "362"
RPL_CLOSEEND = "363"
RPL_INFOSTART = "373"
RPL_MYPORTIS = "384"
ERR_NOSERVICEHOST = "492"
)
// Other constants
const (
ERR_TOOMANYMATCHES = "416" // Used on IRCNet
RPL_TOPICWHOTIME = "333" // From ircu, in use on Freenode
RPL_LOCALUSERS = "265" // From aircd, Hybrid, Hybrid, Bahamut, in use on Freenode
RPL_GLOBALUSERS = "266" // From aircd, Hybrid, Hybrid, Bahamut, in use on Freenode
)

36
vendor/gopkg.in/sorcix/irc.v2/doc.go generated vendored Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
// Package irc allows your application to speak the IRC protocol.
//
// The Message and Prefix structs provide translation to and from raw IRC messages:
//
// // Parse the IRC-encoded data and store the result in a new struct:
// message := irc.ParseMessage(raw)
//
// // Translate back to a raw IRC message string:
// raw = message.String()
//
// Decoder and Encoder can be used to decode and encode messages in a stream:
//
// // Create a decoder that reads from given io.Reader
// dec := irc.NewDecoder(reader)
//
// // Decode the next IRC message
// message, err := dec.Decode()
//
// // Create an encoder that writes to given io.Writer
// enc := irc.NewEncoder(writer)
//
// // Send a message to the writer.
// enc.Encode(message)
//
// The Conn type combines an Encoder and Decoder for a duplex connection.
//
// c, err := irc.Dial("irc.server.net:6667")
//
// // Methods from both Encoder and Decoder are available
// message, err := c.Decode()
//
package irc // import "gopkg.in/sorcix/irc.v2"

19
vendor/gopkg.in/sorcix/irc.v2/internal/strings.go generated vendored Normal file
View File

@ -0,0 +1,19 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
// +build go1.2
// Documented in strings_legacy.go
package internal
import (
"strings"
)
// IndexByte is a compatibility function so strings.IndexByte can be used in
// older versions of go.
func IndexByte(s string, c byte) int {
return strings.IndexByte(s, c)
}

View File

@ -0,0 +1,22 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
// +build !go1.2
// Debian Wheezy only ships Go 1.0:
// https://github.com/sorcix/irc/issues/4
//
// This code may be removed when Wheezy is no longer supported.
package internal
// IndexByte implements strings.IndexByte for Go versions < 1.2.
func IndexByte(s string, c byte) int {
for i := range s {
if s[i] == c {
return i
}
}
return -1
}

309
vendor/gopkg.in/sorcix/irc.v2/message.go generated vendored Normal file
View File

@ -0,0 +1,309 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package irc
import (
"bytes"
"strings"
"gopkg.in/sorcix/irc.v2/internal"
)
// Various constants used for formatting IRC messages.
const (
prefix byte = 0x3A // Prefix or last argument
prefixUser byte = 0x21 // Username
prefixHost byte = 0x40 // Hostname
space byte = 0x20 // Separator
maxLength = 510 // Maximum length is 512 - 2 for the line endings.
)
func cutsetFunc(r rune) bool {
// Characters to trim from prefixes/messages.
return r == '\r' || r == '\n'
}
// Sender represents objects that are able to send messages to an IRC server.
//
// As there might be a message queue, it is possible that Send returns a nil
// error, but the message is not sent (yet). The error value is only used when
// it is certain that sending the message is impossible.
//
// This interface is not used inside this package, and shouldn't have been
// defined here in the first place. For backwards compatibility only.
type Sender interface {
Send(*Message) error
}
// Prefix represents the prefix (sender) of an IRC message.
// See RFC1459 section 2.3.1.
//
// <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
//
type Prefix struct {
Name string // Nick- or servername
User string // Username
Host string // Hostname
}
// ParsePrefix takes a string and attempts to create a Prefix struct.
func ParsePrefix(raw string) (p *Prefix) {
p = new(Prefix)
user := internal.IndexByte(raw, prefixUser)
host := internal.IndexByte(raw, prefixHost)
switch {
case user > 0 && host > user:
p.Name = raw[:user]
p.User = raw[user+1 : host]
p.Host = raw[host+1:]
case user > 0:
p.Name = raw[:user]
p.User = raw[user+1:]
case host > 0:
p.Name = raw[:host]
p.Host = raw[host+1:]
default:
p.Name = raw
}
return p
}
// Len calculates the length of the string representation of this prefix.
func (p *Prefix) Len() (length int) {
length = len(p.Name)
if len(p.User) > 0 {
length = length + len(p.User) + 1
}
if len(p.Host) > 0 {
length = length + len(p.Host) + 1
}
return
}
// Bytes returns a []byte representation of this prefix.
func (p *Prefix) Bytes() []byte {
buffer := new(bytes.Buffer)
p.writeTo(buffer)
return buffer.Bytes()
}
// String returns a string representation of this prefix.
func (p *Prefix) String() (s string) {
// Benchmarks revealed that in this case simple string concatenation
// is actually faster than using a ByteBuffer as in (*Message).String()
s = p.Name
if len(p.User) > 0 {
s = s + string(prefixUser) + p.User
}
if len(p.Host) > 0 {
s = s + string(prefixHost) + p.Host
}
return
}
// IsHostmask returns true if this prefix looks like a user hostmask.
func (p *Prefix) IsHostmask() bool {
return len(p.User) > 0 && len(p.Host) > 0
}
// IsServer returns true if this prefix looks like a server name.
func (p *Prefix) IsServer() bool {
return len(p.User) <= 0 && len(p.Host) <= 0 // && internal.IndexByte(p.Name, '.') > 0
}
// writeTo is an utility function to write the prefix to the bytes.Buffer in Message.String().
func (p *Prefix) writeTo(buffer *bytes.Buffer) {
buffer.WriteString(p.Name)
if len(p.User) > 0 {
buffer.WriteByte(prefixUser)
buffer.WriteString(p.User)
}
if len(p.Host) > 0 {
buffer.WriteByte(prefixHost)
buffer.WriteString(p.Host)
}
return
}
// Message represents an IRC protocol message.
// See RFC1459 section 2.3.1.
//
// <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
// <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
// <command> ::= <letter> { <letter> } | <number> <number> <number>
// <SPACE> ::= ' ' { ' ' }
// <params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
//
// <middle> ::= <Any *non-empty* sequence of octets not including SPACE
// or NUL or CR or LF, the first of which may not be ':'>
// <trailing> ::= <Any, possibly *empty*, sequence of octets not including
// NUL or CR or LF>
//
// <crlf> ::= CR LF
type Message struct {
*Prefix
Command string
Params []string
}
func (m *Message) Trailing() string {
if len(m.Params) > 0 {
return m.Params[len(m.Params)-1]
}
return ""
}
// ParseMessage takes a string and attempts to create a Message struct.
// Returns nil if the Message is invalid.
func ParseMessage(raw string) (m *Message) {
// Ignore empty messages.
if raw = strings.TrimFunc(raw, cutsetFunc); len(raw) < 2 {
return nil
}
i, j := 0, 0
m = new(Message)
if raw[0] == prefix {
// Prefix ends with a space.
i = internal.IndexByte(raw, space)
// Prefix string must not be empty if the indicator is present.
if i < 2 {
return nil
}
m.Prefix = ParsePrefix(raw[1:i])
// Skip space at the end of the prefix
i++
}
// Find end of command
j = i + internal.IndexByte(raw[i:], space)
// Extract command
if j > i {
m.Command = strings.ToUpper(raw[i:j])
} else {
m.Command = strings.ToUpper(raw[i:])
// We're done here!
return m
}
// Find prefix for trailer. Note that because we need to match the trailing
// argument even if it's the only one, we can't skip the space until we've
// searched for it.
i = strings.Index(raw[j:], " :")
// Skip the space
j++
if i < 0 {
// There is no trailing argument!
m.Params = strings.Split(raw[j:], string(space))
// We're done here!
return m
}
// Compensate for index on substring. Note that we skipped the space after
// looking for i, so we need to subtract 1 to account for that.
i = i + j - 1
// Check if we need to parse arguments.
if i > j {
m.Params = strings.Split(raw[j:i], string(space))
}
m.Params = append(m.Params, raw[i+2:])
return m
}
// Len calculates the length of the string representation of this message.
func (m *Message) Len() (length int) {
if m.Prefix != nil {
length = m.Prefix.Len() + 2 // Include prefix and trailing space
}
length = length + len(m.Command)
if len(m.Params) > 0 {
length = length + len(m.Params)
for _, param := range m.Params {
length = length + len(param)
}
// Add one for the colon in the trailing parameter
length++
}
return
}
// Bytes returns a []byte representation of this message.
//
// As noted in rfc2812 section 2.3, messages should not exceed 512 characters
// in length. This method forces that limit by discarding any characters
// exceeding the length limit.
func (m *Message) Bytes() []byte {
buffer := new(bytes.Buffer)
// Message prefix
if m.Prefix != nil {
buffer.WriteByte(prefix)
m.Prefix.writeTo(buffer)
buffer.WriteByte(space)
}
// Command is required
buffer.WriteString(m.Command)
// Space separated list of arguments
if len(m.Params) > 1 {
buffer.WriteByte(space)
buffer.WriteString(strings.Join(m.Params[:len(m.Params)-1], string(space)))
}
if len(m.Params) > 0 {
buffer.WriteByte(space)
buffer.WriteByte(prefix)
buffer.WriteString(m.Trailing())
}
// We need the limit the buffer length.
if buffer.Len() > (maxLength) {
buffer.Truncate(maxLength)
}
return buffer.Bytes()
}
// String returns a string representation of this message.
//
// As noted in rfc2812 section 2.3, messages should not exceed 512 characters
// in length. This method forces that limit by discarding any characters
// exceeding the length limit.
func (m *Message) String() string {
return string(m.Bytes())
}

134
vendor/gopkg.in/sorcix/irc.v2/stream.go generated vendored Normal file
View File

@ -0,0 +1,134 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package irc
import (
"bufio"
"io"
"net"
"sync"
)
// Messages are delimited with CR and LF line endings,
// we're using the last one to split the stream. Both are removed
// during message parsing.
const delim byte = '\n'
var endline = []byte("\r\n")
// A Conn represents an IRC network protocol connection.
// It consists of an Encoder and Decoder to manage I/O.
type Conn struct {
Encoder
Decoder
conn io.ReadWriteCloser
}
// NewConn returns a new Conn using rwc for I/O.
func NewConn(rwc io.ReadWriteCloser) *Conn {
return &Conn{
Encoder: Encoder{
writer: rwc,
},
Decoder: Decoder{
reader: bufio.NewReader(rwc),
},
conn: rwc,
}
}
// Dial connects to the given address using net.Dial and
// then returns a new Conn for the connection.
func Dial(addr string) (*Conn, error) {
c, err := net.Dial("tcp", addr)
if err != nil {
return nil, err
}
return NewConn(c), nil
}
// Close closes the underlying ReadWriteCloser.
func (c *Conn) Close() error {
return c.conn.Close()
}
// A Decoder reads Message objects from an input stream.
type Decoder struct {
reader *bufio.Reader
line string
mu sync.Mutex
}
// NewDecoder returns a new Decoder that reads from r.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{
reader: bufio.NewReader(r),
}
}
// Decode attempts to read a single Message from the stream.
//
// Returns a non-nil error if the read failed.
func (dec *Decoder) Decode() (m *Message, err error) {
dec.mu.Lock()
dec.line, err = dec.reader.ReadString(delim)
dec.mu.Unlock()
if err != nil {
return nil, err
}
return ParseMessage(dec.line), nil
}
// An Encoder writes Message objects to an output stream.
type Encoder struct {
writer io.Writer
mu sync.Mutex
}
// NewEncoder returns a new Encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{
writer: w,
}
}
// Encode writes the IRC encoding of m to the stream.
//
// This method may be used from multiple goroutines.
//
// Returns an non-nil error if the write to the underlying stream stopped early.
func (enc *Encoder) Encode(m *Message) (err error) {
_, err = enc.Write(m.Bytes())
return
}
// Write writes len(p) bytes from p followed by CR+LF.
//
// This method can be used simultaneously from multiple goroutines,
// it guarantees to serialize access. However, writing a single IRC message
// using multiple Write calls will cause corruption.
func (enc *Encoder) Write(p []byte) (n int, err error) {
enc.mu.Lock()
n, err = enc.writer.Write(p)
if err != nil {
enc.mu.Unlock()
return
}
_, err = enc.writer.Write(endline)
enc.mu.Unlock()
return
}

19
vendor/vendor.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"comment": "",
"ignore": "test",
"package": [
{
"checksumSHA1": "mRNv6NTAfGphwvF7YzNk8XOhX10=",
"path": "gopkg.in/sorcix/irc.v2",
"revision": "63b1858457fa9439c5f37124100605a0b0d98bd8",
"revisionTime": "2016-05-13T12:23:15Z"
},
{
"checksumSHA1": "745d6gaBv5Ni3YrPvslpM4BoU6A=",
"path": "gopkg.in/sorcix/irc.v2/internal",
"revision": "63b1858457fa9439c5f37124100605a0b0d98bd8",
"revisionTime": "2016-05-13T12:23:15Z"
}
],
"rootPath": "anonircd"
}