145 lines
3.5 KiB
Go
145 lines
3.5 KiB
Go
// Copyright 2014 Vic Demuzere
|
|
//
|
|
// Use of this source code is governed by the MIT license.
|
|
|
|
package ctcp
|
|
|
|
// Sources:
|
|
// http://www.irchelp.org/irchelp/rfc/ctcpspec.html
|
|
// http://www.kvirc.net/doc/doc_ctcp_handling.html
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Various constants used for formatting CTCP messages.
|
|
const (
|
|
delimiter byte = 0x01 // Prefix and suffix for CTCP tagged messages.
|
|
space byte = 0x20 // Token separator
|
|
|
|
empty = "" // The empty string
|
|
|
|
timeFormat = time.RFC1123Z
|
|
versionFormat = "Go v%s (" + runtime.GOOS + ", " + runtime.GOARCH + ")"
|
|
)
|
|
|
|
// Tags extracted from the CTCP spec.
|
|
const (
|
|
ACTION = "ACTION"
|
|
PING = "PING"
|
|
PONG = "PONG"
|
|
VERSION = "VERSION"
|
|
USERINFO = "USERINFO"
|
|
CLIENTINFO = "CLIENTINFO"
|
|
FINGER = "FINGER"
|
|
SOURCE = "SOURCE"
|
|
TIME = "TIME"
|
|
)
|
|
|
|
// Decode attempts to decode CTCP tagged data inside given message text.
|
|
//
|
|
// If the message text does not contain tagged data, ok will be false.
|
|
//
|
|
// <text> ::= <delim> <tag> [<SPACE> <message>] <delim>
|
|
// <delim> ::= 0x01
|
|
//
|
|
func Decode(text string) (tag, message string, ok bool) {
|
|
|
|
// Fast path, return if this text does not contain a CTCP message.
|
|
if len(text) < 3 || text[0] != delimiter || text[len(text)-1] != delimiter {
|
|
return empty, empty, false
|
|
}
|
|
|
|
s := strings.IndexByte(text, space)
|
|
|
|
if s < 0 {
|
|
|
|
// Messages may contain only a tag.
|
|
return text[1 : len(text)-1], empty, true
|
|
}
|
|
|
|
return text[1:s], text[s+1 : len(text)-1], true
|
|
}
|
|
|
|
// Encode returns the IRC message text for CTCP tagged data.
|
|
//
|
|
// <text> ::= <delim> <tag> [<SPACE> <message>] <delim>
|
|
// <delim> ::= 0x01
|
|
//
|
|
func Encode(tag, message string) (text string) {
|
|
|
|
switch {
|
|
|
|
// We can't build a valid CTCP tagged message without at least a tag.
|
|
case len(tag) <= 0:
|
|
return empty
|
|
|
|
// Tagged data with a message
|
|
case len(message) > 0:
|
|
return string(delimiter) + tag + string(space) + message + string(delimiter)
|
|
|
|
// Tagged data without a message
|
|
default:
|
|
return string(delimiter) + tag + string(delimiter)
|
|
|
|
}
|
|
}
|
|
|
|
// Action is a shortcut for Encode(ctcp.ACTION, message).
|
|
func Action(message string) string {
|
|
return Encode(ACTION, message)
|
|
}
|
|
|
|
// Ping is a shortcut for Encode(ctcp.PING, message).
|
|
func Ping(message string) string {
|
|
return Encode(PING, message)
|
|
}
|
|
|
|
// Pong is a shortcut for Encode(ctcp.PONG, message).
|
|
func Pong(message string) string {
|
|
return Encode(PONG, message)
|
|
}
|
|
|
|
// Version is a shortcut for Encode(ctcp.VERSION, message).
|
|
func Version(message string) string {
|
|
return Encode(VERSION, message)
|
|
}
|
|
|
|
// VersionReply is a shortcut for ENCODE(ctcp.VERSION, go version info).
|
|
func VersionReply() string {
|
|
return Encode(VERSION, fmt.Sprintf(versionFormat, runtime.Version()))
|
|
}
|
|
|
|
// UserInfo is a shortcut for Encode(ctcp.USERINFO, message).
|
|
func UserInfo(message string) string {
|
|
return Encode(USERINFO, message)
|
|
}
|
|
|
|
// ClientInfo is a shortcut for Encode(ctcp.CLIENTINFO, message).
|
|
func ClientInfo(message string) string {
|
|
return Encode(CLIENTINFO, message)
|
|
}
|
|
|
|
// Finger is a shortcut for Encode(ctcp.FINGER, message).
|
|
func Finger(message string) string {
|
|
return Encode(FINGER, message)
|
|
}
|
|
|
|
// Source is a shortcut for Encode(ctcp.SOURCE, message).
|
|
func Source(message string) string {
|
|
return Encode(SOURCE, message)
|
|
}
|
|
|
|
// Time is a shortcut for Encode(ctcp.TIME, message).
|
|
func Time(message string) string {
|
|
return Encode(TIME, message)
|
|
}
|
|
|
|
// TimeReply is a shortcut for Encode(ctcp.TIME, currenttime).
|
|
func TimeReply() string {
|
|
return Encode(TIME, time.Now().Format(timeFormat))
|
|
}
|