anonircd/client.go

207 lines
4.0 KiB
Go

package main
import (
"log"
"net"
"sync"
"strings"
"fmt"
irc "gopkg.in/sorcix/irc.v2"
)
type Client struct {
Entity
iphash string
ssl bool
nick string
user string
host string
account int64
conn net.Conn
writebuffer chan *irc.Message
reader *irc.Decoder
writer *irc.Encoder
capHostInNames bool
wg sync.WaitGroup
}
func NewClient(identifier string, conn net.Conn, ssl bool) *Client {
c := &Client{}
c.Initialize(ENTITY_CLIENT, identifier)
ip, _, err := net.SplitHostPort(conn.RemoteAddr().String())
if err != nil {
return nil
}
c.iphash = generateHash(ip)
c.ssl = ssl
c.nick = "*"
c.conn = conn
c.writebuffer = make(chan *irc.Message, writebuffersize)
c.reader = irc.NewDecoder(conn)
c.writer = irc.NewEncoder(conn)
return c
}
func (c *Client) getAccount() (*DBAccount, error) {
if c.account == 0 {
return nil, nil
}
acc, err := db.Account(c.account)
if err != nil {
return nil, err
}
return &acc, nil
}
func (c *Client) registered() bool {
// TODO get account and check if it is valid
return c.account > 0
}
func (c *Client) getPrefix() *irc.Prefix {
return &irc.Prefix{Name: c.nick, User: c.user, Host: c.host}
}
func (c *Client) write(prefix *irc.Prefix, command string, params []string) {
if c.state == ENTITY_STATE_TERMINATING {
return
}
c.wg.Add(1)
c.writebuffer <- &irc.Message{Prefix: prefix, Command: command, Params: params}
}
func (c *Client) writeMessage(command string, params []string) {
c.write(&prefixAnonIRC, command, params)
}
func (c *Client) sendMessage(message string) {
c.writeMessage(irc.PRIVMSG, []string{c.nick, message})
}
func (c *Client) sendPasswordIncorrect() {
c.writeMessage(irc.ERR_PASSWDMISMATCH, []string{"Password incorrect"})
}
func (c *Client) sendError(message string) {
c.sendMessage("Error! " + message)
}
func (c *Client) sendNotice(message string) {
c.sendMessage("*** " + message)
}
func (c *Client) sendBanned(reason string) {
if reason != "" {
reason = fmt.Sprintf(" (%s)", reason)
}
c.writeMessage(irc.ERR_YOUREBANNEDCREEP, []string{"You are banned from this server" + reason})
}
func (c *Client) accessDenied(permissionRequired int) {
ex := ""
if permissionRequired > PERMISSION_CLIENT {
ex = fmt.Sprintf(", that command is available to %ss only", strings.ToLower(permissionLabels[permissionRequired]))
if permissionRequired == PERMISSION_REGISTERED {
ex += " - Reply HELP for more info (see REGISTER and IDENTIFY)"
}
}
c.sendNotice("Access denied" + ex)
}
func (c *Client) identify(username string, password string) bool {
accountid, err := db.Auth(username, password)
if err != nil {
log.Panicf("%+v", err)
}
account, err := db.Account(accountid)
if err != nil {
log.Panicf("%+v", err)
} else if account.ID == 0 {
return false
}
c.account = accountid
return true
}
func (c *Client) getPermission(channel string) int {
if c.account == 0 {
return PERMISSION_CLIENT
}
p, err := db.GetPermission(c.account, channel)
if err != nil {
log.Panicf("%+v", err)
}
return p.Permission
}
func (c *Client) globalPermission() int {
return c.getPermission(CHANNEL_SERVER)
}
func (c *Client) canUse(command string, channel string) bool {
command = strings.ToUpper(command)
req := c.permissionRequired(command)
globalPermission := c.globalPermission()
if globalPermission >= req {
return true
} else if containsString(serverCommands, command) {
return false
}
return c.getPermission(channel) >= req
}
func (c *Client) permissionRequired(command string) int {
command = strings.ToUpper(command)
for permissionRequired, commands := range commandRestrictions {
for _, cmd := range commands {
if cmd == command {
return permissionRequired
}
}
}
return 0
}
func (c *Client) isBanned(channel string) (bool, string) {
b, err := db.BanAddr(c.iphash, channel)
if err != nil {
log.Panicf("%+v", err)
}
if b.Channel == "" && c.account > 0 {
b, err = db.BanAccount(c.account, channel)
if err != nil {
log.Panicf("%+v", err)
}
}
if b.Channel != "" {
return true, b.Reason
}
return false, ""
}