ergo/irc/utils/text.go

135 lines
3.0 KiB
Go
Raw Normal View History

// Copyright (c) 2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package utils
2019-12-23 21:26:37 +01:00
import (
"strings"
"time"
)
func IsRestrictedCTCPMessage(message string) bool {
// block all CTCP privmsgs to Tor clients except for ACTION
// DCC can potentially be used for deanonymization, the others for fingerprinting
return strings.HasPrefix(message, "\x01") && !strings.HasPrefix(message, "\x01ACTION")
}
type MessagePair struct {
Message string
2019-12-23 21:26:37 +01:00
Concat bool // should be relayed with the multiline-concat tag
}
// SplitMessage represents a message that's been split for sending.
2020-01-19 05:47:05 +01:00
// Two possibilities:
2019-12-23 21:26:37 +01:00
// (a) Standard message that can be relayed on a single 512-byte line
// (MessagePair contains the message, Split == nil)
2020-01-19 05:47:05 +01:00
// (b) multiline message that was split on the client side
// (Message == "", Split contains the split lines)
type SplitMessage struct {
2020-01-19 05:47:05 +01:00
Message string
Msgid string
Split []MessagePair
2019-05-07 05:17:57 +02:00
Time time.Time
}
2020-01-19 05:47:05 +01:00
func MakeMessage(original string) (result SplitMessage) {
result.Message = original
result.Msgid = GenerateSecretToken()
result.SetTime()
return
}
2019-11-10 02:31:39 +01:00
2019-12-23 21:26:37 +01:00
func (sm *SplitMessage) Append(message string, concat bool) {
if sm.Msgid == "" {
sm.Msgid = GenerateSecretToken()
}
2020-01-19 05:47:05 +01:00
sm.Split = append(sm.Split, MessagePair{
2019-12-23 21:26:37 +01:00
Message: message,
Concat: concat,
})
}
func (sm *SplitMessage) SetTime() {
// strip the monotonic time, it's a potential source of problems:
sm.Time = time.Now().UTC().Round(0)
}
2019-12-23 21:26:37 +01:00
func (sm *SplitMessage) LenLines() int {
2020-01-19 05:47:05 +01:00
if sm.Split == nil {
if sm.Message == "" {
2019-12-23 21:26:37 +01:00
return 0
} else {
return 1
}
}
2020-01-19 05:47:05 +01:00
return len(sm.Split)
2019-12-23 21:26:37 +01:00
}
2020-05-14 18:58:49 +02:00
func (sm *SplitMessage) ValidMultiline() bool {
// must contain at least one nonblank line
for i := 0; i < len(sm.Split); i++ {
if len(sm.Split[i].Message) != 0 {
return true
}
}
return false
}
2019-12-23 21:26:37 +01:00
func (sm *SplitMessage) IsRestrictedCTCPMessage() bool {
if IsRestrictedCTCPMessage(sm.Message) {
return true
}
2020-01-19 05:47:05 +01:00
for i := 0; i < len(sm.Split); i++ {
if IsRestrictedCTCPMessage(sm.Split[i].Message) {
2019-12-23 21:26:37 +01:00
return true
}
}
return false
}
func (sm *SplitMessage) Is512() bool {
return sm.Split == nil
2019-12-23 21:26:37 +01:00
}
2019-11-10 02:31:39 +01:00
// TokenLineBuilder is a helper for building IRC lines composed of delimited tokens,
// with a maximum line length.
type TokenLineBuilder struct {
lineLen int
delim string
buf strings.Builder
2019-11-10 02:31:39 +01:00
result []string
}
func (t *TokenLineBuilder) Initialize(lineLen int, delim string) {
t.lineLen = lineLen
t.delim = delim
}
// Add adds a token to the line, creating a new line if necessary.
func (t *TokenLineBuilder) Add(token string) {
tokenLen := len(token)
if t.buf.Len() != 0 {
tokenLen += len(t.delim)
}
if t.lineLen < t.buf.Len()+tokenLen {
t.result = append(t.result, t.buf.String())
t.buf.Reset()
}
if t.buf.Len() != 0 {
t.buf.WriteString(t.delim)
}
t.buf.WriteString(token)
}
// Lines terminates the line-building and returns all the lines.
func (t *TokenLineBuilder) Lines() (result []string) {
result = t.result
t.result = nil
if t.buf.Len() != 0 {
result = append(result, t.buf.String())
t.buf.Reset()
}
return
}