1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
// 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))
}
|