mirror of
https://github.com/42wim/matterbridge.git
synced 2024-11-24 11:42:03 -08:00
04567c765e
This uses our own gomatrix lib with the SendHTML function which adds HTML to formatted_body in matrix. golang-commonmark is used to convert markdown into valid HTML.
288 lines
5.5 KiB
Go
288 lines
5.5 KiB
Go
// Copyright 2015 The Authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
// Package puny provides functions for encoding/decoding to/from punycode.
|
||
package puny
|
||
|
||
import (
|
||
"errors"
|
||
"strings"
|
||
"unicode/utf8"
|
||
)
|
||
|
||
const (
|
||
maxInt32 int32 = 2147483647
|
||
base int32 = 36
|
||
tMin int32 = 1
|
||
baseMinusTMin = base - tMin
|
||
tMax int32 = 26
|
||
skew int32 = 38
|
||
damp int32 = 700
|
||
initialBias int32 = 72
|
||
initialN int32 = 128
|
||
)
|
||
|
||
var (
|
||
ErrOverflow = errors.New("overflow: input needs wider integers to process")
|
||
ErrNotBasic = errors.New("illegal input >= 0x80 (not a basic code point)")
|
||
ErrInvalidInput = errors.New("invalid input")
|
||
)
|
||
|
||
func adapt(delta, numPoints int32, firstTime bool) int32 {
|
||
if firstTime {
|
||
delta /= damp
|
||
} else {
|
||
delta /= 2
|
||
}
|
||
delta += delta / numPoints
|
||
k := int32(0)
|
||
for delta > baseMinusTMin*tMax/2 {
|
||
delta = delta / baseMinusTMin
|
||
k += base
|
||
}
|
||
return k + (baseMinusTMin+1)*delta/(delta+skew)
|
||
}
|
||
|
||
func basicToDigit(b byte) int32 {
|
||
switch {
|
||
case b >= '0' && b <= '9':
|
||
return int32(b - 22)
|
||
case b >= 'A' && b <= 'Z':
|
||
return int32(b - 'A')
|
||
case b >= 'a' && b <= 'z':
|
||
return int32(b - 'a')
|
||
}
|
||
return base
|
||
}
|
||
|
||
func digitToBasic(digit int32) byte {
|
||
switch {
|
||
case digit >= 0 && digit <= 25:
|
||
return byte(digit) + 'a'
|
||
case digit >= 26 && digit <= 35:
|
||
return byte(digit) - 26 + '0'
|
||
}
|
||
panic("unreachable")
|
||
}
|
||
|
||
func lastIndex(s string, c byte) int {
|
||
for i := len(s) - 1; i >= 0; i-- {
|
||
if s[i] == c {
|
||
return i
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
|
||
func ascii(s string) bool {
|
||
for _, r := range s {
|
||
if r > 0x7e {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|
||
|
||
// Decode converts a Punycode string of ASCII-only symbols to a string of Unicode symbols.
|
||
func Decode(s string) (string, error) {
|
||
basic := lastIndex(s, '-')
|
||
output := make([]rune, 0, len(s))
|
||
for i := 0; i < basic; i++ {
|
||
b := s[i]
|
||
if b >= 0x80 {
|
||
return "", ErrNotBasic
|
||
}
|
||
output = append(output, rune(b))
|
||
}
|
||
|
||
i, n, bias, pos := int32(0), initialN, initialBias, basic+1
|
||
|
||
for pos < len(s) {
|
||
oldi, w, k := i, int32(1), base
|
||
for {
|
||
digit := basicToDigit(s[pos])
|
||
pos++
|
||
|
||
if digit >= base || digit > (maxInt32-i)/w {
|
||
return "", ErrOverflow
|
||
}
|
||
|
||
i += digit * w
|
||
|
||
t := k - bias
|
||
if t < tMin {
|
||
t = tMin
|
||
} else if t > tMax {
|
||
t = tMax
|
||
}
|
||
|
||
if digit < t {
|
||
break
|
||
}
|
||
|
||
if pos == len(s) {
|
||
return "", ErrInvalidInput
|
||
}
|
||
|
||
baseMinusT := base - t
|
||
if w > maxInt32/baseMinusT {
|
||
return "", ErrOverflow
|
||
}
|
||
|
||
w *= baseMinusT
|
||
k += base
|
||
}
|
||
|
||
out := int32(len(output) + 1)
|
||
bias = adapt(i-oldi, out, oldi == 0)
|
||
|
||
if i/out > maxInt32-n {
|
||
return "", ErrOverflow
|
||
}
|
||
|
||
n += i / out
|
||
i %= out
|
||
|
||
output = append(output, 0)
|
||
copy(output[i+1:], output[i:])
|
||
output[i] = rune(n)
|
||
|
||
i++
|
||
}
|
||
|
||
return string(output), nil
|
||
}
|
||
|
||
// Encode converts a string of Unicode symbols (e.g. a domain name label) to a
|
||
// Punycode string of ASCII-only symbols.
|
||
func Encode(input string) (string, error) {
|
||
n := initialN
|
||
delta := int32(0)
|
||
bias := initialBias
|
||
|
||
var output []byte
|
||
runes := 0
|
||
for _, r := range input {
|
||
if r >= 0x80 {
|
||
runes++
|
||
continue
|
||
}
|
||
output = append(output, byte(r))
|
||
}
|
||
|
||
basicLength := len(output)
|
||
handledCPCount := basicLength
|
||
|
||
if basicLength > 0 {
|
||
output = append(output, '-')
|
||
}
|
||
|
||
for runes > 0 {
|
||
m := maxInt32
|
||
for _, r := range input {
|
||
if r >= n && r < m {
|
||
m = r
|
||
}
|
||
}
|
||
|
||
handledCPCountPlusOne := int32(handledCPCount + 1)
|
||
if m-n > (maxInt32-delta)/handledCPCountPlusOne {
|
||
return "", ErrOverflow
|
||
}
|
||
|
||
delta += (m - n) * handledCPCountPlusOne
|
||
n = m
|
||
|
||
for _, r := range input {
|
||
if r < n {
|
||
delta++
|
||
if delta < 0 {
|
||
return "", ErrOverflow
|
||
}
|
||
continue
|
||
}
|
||
if r > n {
|
||
continue
|
||
}
|
||
q := delta
|
||
for k := base; ; k += base {
|
||
t := k - bias
|
||
if t < tMin {
|
||
t = tMin
|
||
} else if t > tMax {
|
||
t = tMax
|
||
}
|
||
if q < t {
|
||
break
|
||
}
|
||
qMinusT := q - t
|
||
baseMinusT := base - t
|
||
output = append(output, digitToBasic(t+qMinusT%baseMinusT))
|
||
q = qMinusT / baseMinusT
|
||
}
|
||
|
||
output = append(output, digitToBasic(q))
|
||
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength)
|
||
delta = 0
|
||
handledCPCount++
|
||
runes--
|
||
}
|
||
delta++
|
||
n++
|
||
}
|
||
return string(output), nil
|
||
}
|
||
|
||
func sep(r rune) bool { return r == '.' || r == '。' || r == '.' || r == '。' }
|
||
|
||
func mapLabels(s string, fn func(string) string) string {
|
||
var result string
|
||
i := strings.IndexByte(s, '@')
|
||
if i != -1 {
|
||
result = s[:i+1]
|
||
s = s[i+1:]
|
||
}
|
||
var labels []string
|
||
start := 0
|
||
for i, r := range s {
|
||
if !sep(r) {
|
||
continue
|
||
}
|
||
labels = append(labels, fn(s[start:i]))
|
||
start = i + utf8.RuneLen(r)
|
||
}
|
||
labels = append(labels, fn(s[start:]))
|
||
return result + strings.Join(labels, ".")
|
||
}
|
||
|
||
// ToUnicode converts a Punycode string representing a domain name or an email address
|
||
// to Unicode. Only the Punycoded parts of the input will be converted.
|
||
func ToUnicode(s string) string {
|
||
return mapLabels(s, func(s string) string {
|
||
if !strings.HasPrefix(s, "xn--") {
|
||
return s
|
||
}
|
||
d, err := Decode(strings.ToLower(s[4:]))
|
||
if err != nil {
|
||
return s
|
||
}
|
||
return d
|
||
})
|
||
}
|
||
|
||
// ToASCII converts a Unicode string representing a domain name or an email address to
|
||
// Punycode. Only the non-ASCII parts of the domain name will be converted.
|
||
func ToASCII(s string) string {
|
||
return mapLabels(s, func(s string) string {
|
||
if ascii(s) {
|
||
return s
|
||
}
|
||
d, err := Encode(s)
|
||
if err != nil {
|
||
return s
|
||
}
|
||
return "xn--" + d
|
||
})
|
||
}
|