From 33969ac86eb925c1fa52ba58315d0b381799724e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?=
Date: Tue, 31 Jul 2018 21:13:30 +0200 Subject: [PATCH] hid: bringup of what we have this far --- hid/main.go | 60 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/hid/main.go b/hid/main.go index 2c34f08..5e99a85 100644 --- a/hid/main.go +++ b/hid/main.go @@ -421,7 +421,7 @@ func ircFnmatch(pattern string, s string) bool { } var reMsg = regexp.MustCompile( - `^(?:@[^ ]* +)(?::([^! ]*)(?:!([^@]*)@([^ ]*))? +)?([^ ]+)(.*)?$`) + `^(@[^ ]* +)?(?::([^! ]*)(?:!([^@]*)@([^ ]*))? +)?([^ ]+)(.*)?$`) var reArgs = regexp.MustCompile(`:.*| [^: ][^ ]*`) type message struct { @@ -514,7 +514,7 @@ var ( // behaviour seems to be unstated in the documentation. reUsername = regexp.MustCompile(`^[^\0\r\n @]+$`) - reChannelName = regexp.MustCompile(`^[^\0\7\r\n ,:]+$`) + reChannelName = regexp.MustCompile(`^[^\0\007\r\n ,:]+$`) reKey = regexp.MustCompile(`^[^\r\n\f\t\v ]{1,23}$`) reUserMask = regexp.MustCompile(`^[^!@]+![^!@]+@[^@!]+$`) reFingerprint = regexp.MustCompile(`^[a-fA-F0-9]{64}$`) @@ -754,17 +754,16 @@ type writeEvent struct { var ( started time.Time // when has the server been started - users map[string]*client // maps nicknames to clients - channels map[string]*channel // maps channel names to data + users = make(map[string]*client) // maps nicknames to clients + channels = make(map[string]*channel) // maps channel names to data + whowas = make(map[string]*whowasInfo) // WHOWAS registry - whowas map[string]*whowasInfo // WHOWAS registry - - config simpleConfig // server configuration - serverName string // our server name - pingInterval uint // ping interval in seconds - maxConnections int // max connections allowed or 0 - motd []string // MOTD (none if empty) - operators map[string]bool // TLS certificate fingerprints for IRCops + config simpleConfig // server configuration + serverName string // our server name + pingInterval uint // ping interval in seconds + maxConnections int // max connections allowed or 0 + motd []string // MOTD (none if empty) + operators = make(map[string]bool) // TLS cert. fingerprints for IRCops ) var ( @@ -814,8 +813,9 @@ func initiateQuit() { func ircChannelCreate(name string) *channel { ch := &channel{ name: name, - created: time.Now(), userLimit: -1, + created: time.Now(), + userModes: make(map[*client]uint), } channels[ircToCanon(name)] = ch return ch @@ -1046,10 +1046,15 @@ func (c *client) sendReplyVector(id int, items []string, args ...interface{}) { // We always send at least one message (there might be a client that // expects us to send this message at least once). + if len(items) == 0 { + items = append(items, "") + } + for len(items) > 0 { // If not even a single item fits in the limit (which may happen, // in theory) it just gets cropped. We could also skip it. reply := append([]byte(common), items[0]...) + items = items[1:] // Append as many items as fits in a single message. for len(items) > 0 && @@ -1120,10 +1125,10 @@ func isThisMe(target string) bool { } func (c *client) sendISUPPORT() { - // Only # channels, +e supported, +I supported, unlimited arguments to MODE - c.sendReply(RPL_ISUPPORT, "CHANTYPES=# EXCEPTS INVEX MODES"+ + // Only # channels, +e supported, +I supported, unlimited arguments to MODE. + c.sendReply(RPL_ISUPPORT, fmt.Sprintf("CHANTYPES=# EXCEPTS INVEX MODES"+ " TARGMAX=WHOIS:,LIST:,NAMES:,PRIVMSG:1,NOTICE:1,KICK:"+ - " NICKLEN=%d CHANNELLEN=%d", ircMaxNickname, ircMaxChannelName) + " NICKLEN=%d CHANNELLEN=%d", ircMaxNickname, ircMaxChannelName)) } func (c *client) tryFinishRegistration() { @@ -2170,8 +2175,7 @@ func ircSendWHOISReply(c, target *client) { nick := target.nickname c.sendReply(RPL_WHOISUSER, nick, target.username, target.hostname, target.realname) - c.sendReply(RPL_WHOISSERVER, nick, - serverName, "TODO server_info from configuration") + c.sendReply(RPL_WHOISSERVER, nick, serverName, config["server_info"]) if 0 != target.mode&ircUserModeOperator { c.sendReply(RPL_WHOISOPERATOR, nick) } @@ -2257,7 +2261,7 @@ func ircHandleWHOWAS(msg *message, c *client) { c.sendReply(RPL_WHOWASUSER, nick, info.username, info.hostname, info.realname) c.sendReply(RPL_WHOISSERVER, nick, - serverName, "TODO server_info from configuration") + serverName, config["server_info"]) } c.sendReply(RPL_ENDOFWHOWAS, nick) } @@ -2689,7 +2693,7 @@ func ircHandleLINKS(msg *message, c *client) { if ircFnmatch(mask, serverName) { c.sendReply(RPL_LINKS, mask, serverName, - 0 /* hop count */, "TODO server_info from configuration") + 0 /* hop count */, config["server_info"]) } c.sendReply(RPL_ENDOFLINKS, mask) } @@ -2799,11 +2803,16 @@ func ircProcessMessage(c *client, msg *message, raw string) { // Handle the results from initializing the client's connection. func (c *client) onPrepared(host string, isTLS bool) { - if isTLS { + if !isTLS { + c.conn = c.transport.(connCloseWrite) + } else if tlsConf != nil { c.tls = tls.Server(c.transport, tlsConf) c.conn = c.tls } else { - c.conn = c.transport.(connCloseWrite) + log.Printf("could not initialize TLS for %s: TLS support disabled\n", + c.address) + c.kill("TLS support disabled") + return } c.hostname = host @@ -2949,7 +2958,7 @@ func prepare(client *client) { // This is just for the TLS detection and doesn't need to be fatal. log.Println(err) } else { - isTLS = tlsConf != nil && detectTLS(sysconn) + isTLS = detectTLS(sysconn) } // FIXME: When the client sends no data, we still initialize its conn. @@ -2993,7 +3002,7 @@ func processOneEvent() { forceQuit("timeout") case conn := <-conns: - if len(clients) >= maxConnections { + if maxConnections > 0 && len(clients) >= maxConnections { log.Println("connection limit reached, refusing connection") conn.Close() break @@ -3014,6 +3023,8 @@ func processOneEvent() { hostname: host, port: port, capVersion: 301, + opened: time.Now(), + lastActive: time.Now(), // TODO: Make this configurable and more fine-grained. antiflood: newFloodDetector(10*time.Second, 20), } @@ -3223,6 +3234,7 @@ func main() { } config = make(simpleConfig) + config.loadDefaults(configTable) if err := config.updateFromFile(); err != nil && !os.IsNotExist(err) { log.Println("error loading configuration", err) os.Exit(1)