gosora/plugin_bbcode.go
Azareal ca7c369e9e Added numeric mentions. Username mentions will be automatically pre-parsed into numeric mentions in a future commit.
Added #rid for linking to a specific post.

Added a forum_exists function.
Removed the null bytes from the posts
The report system now uses #rid, #tid and numeric mentions instead of raw HTML.
Improved the custom parser to take control characters into account. It also now parses items at the start of the post.
Fixed the padding on the buttons on the profiles.
#tid now takes into account whether the topic it links to exists.
2017-03-14 10:57:40 +00:00

371 lines
11 KiB
Go

package main
//import "log"
//import "fmt"
import "bytes"
//import "strings"
import "strconv"
import "regexp"
import "time"
import "math/rand"
var random *rand.Rand
var bbcode_invalid_number []byte
var bbcode_missing_tag []byte
var bbcode_bold *regexp.Regexp
var bbcode_italic *regexp.Regexp
var bbcode_underline *regexp.Regexp
var bbcode_strikethrough *regexp.Regexp
var bbcode_url *regexp.Regexp
var bbcode_url_label *regexp.Regexp
var bbcode_quotes *regexp.Regexp
func init() {
plugins["bbcode"] = NewPlugin("bbcode","BBCode","Azareal","http://github.com/Azareal","","","",init_bbcode,nil,deactivate_bbcode)
}
func init_bbcode() {
//plugins["bbcode"].AddHook("parse_assign", bbcode_parse_without_code)
plugins["bbcode"].AddHook("parse_assign", bbcode_full_parse)
bbcode_invalid_number = []byte("<span style='color: red;'>[Invalid Number]</span>")
bbcode_missing_tag = []byte("<span style='color: red;'>[Missing Tag]</span>")
bbcode_bold = regexp.MustCompile(`(?s)\[b\](.*)\[/b\]`)
bbcode_italic = regexp.MustCompile(`(?s)\[i\](.*)\[/i\]`)
bbcode_underline = regexp.MustCompile(`(?s)\[u\](.*)\[/u\]`)
bbcode_strikethrough = regexp.MustCompile(`(?s)\[s\](.*)\[/s\]`)
urlpattern := `(http|https|ftp|mailto*)(:??)\/\/([\.a-zA-Z\/]+)`
bbcode_url = regexp.MustCompile(`\[url\]` + urlpattern + `\[/url\]`)
bbcode_url_label = regexp.MustCompile(`(?s)\[url=` + urlpattern + `\](.*)\[/url\]`)
bbcode_quotes = regexp.MustCompile(`\[quote\](.*)\[/quote\]`)
random = rand.New(rand.NewSource(time.Now().UnixNano()))
}
func deactivate_bbcode() {
//plugins["bbcode"].RemoveHook("parse_assign", bbcode_parse_without_code)
plugins["bbcode"].RemoveHook("parse_assign", bbcode_full_parse)
}
func bbcode_regex_parse(data interface{}) interface{} {
msg := data.(string)
msg = bbcode_bold.ReplaceAllString(msg,"<b>$1</b>")
msg = bbcode_italic.ReplaceAllString(msg,"<i>$1</i>")
msg = bbcode_underline.ReplaceAllString(msg,"<u>$1</u>")
msg = bbcode_strikethrough.ReplaceAllString(msg,"<s>$1</s>")
msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
msg = bbcode_quotes.ReplaceAllString(msg,"<span class=\"postQuote\">$1</span>")
return msg
}
// Only does the simple BBCode like [u], [b], [i] and [s]
func bbcode_simple_parse(data interface{}) interface{} {
msg := data.(string)
msgbytes := []byte(msg)
has_u := false
has_b := false
has_i := false
has_s := false
for i := 0; (i + 2) < len(msgbytes); i++ {
if msgbytes[i] == '[' && msgbytes[i + 2] == ']' {
if msgbytes[i + 1] == 'b' && !has_b {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_b = true
} else if msgbytes[i + 1] == 'i' && !has_i {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_i = true
} else if msgbytes[i + 1] == 'u' && !has_u {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_u = true
} else if msgbytes[i + 1] == 's' && !has_s {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_s = true
}
i += 2
}
}
// There's an unclosed tag in there x.x
if has_i || has_u || has_b || has_s {
closer := []byte("</u></i></b></s>")
msgbytes = append(msgbytes, closer...)
}
return string(msgbytes)
}
// Here for benchmarking purposes. Might add a plugin setting for disabling [code] as it has it's paws everywhere
func bbcode_parse_without_code(data interface{}) interface{} {
msg := data.(string)
msgbytes := []byte(msg)
has_u := false
has_b := false
has_i := false
has_s := false
complex_bbc := false
for i := 0; (i + 3) < len(msgbytes); i++ {
if msgbytes[i] == '[' {
if msgbytes[i + 2] != ']' {
if msgbytes[i + 1] == '/' {
if msgbytes[i + 3] == ']' {
if msgbytes[i + 2] == 'b' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_b = false
} else if msgbytes[i + 2] == 'i' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_i = false
} else if msgbytes[i + 2] == 'u' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_u = false
} else if msgbytes[i + 2] == 's' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_s = false
}
i += 3
} else {
complex_bbc = true
}
} else {
complex_bbc = true
}
} else {
if msgbytes[i + 1] == 'b' && !has_b {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_b = true
} else if msgbytes[i + 1] == 'i' && !has_i {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_i = true
} else if msgbytes[i + 1] == 'u' && !has_u {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_u = true
} else if msgbytes[i + 1] == 's' && !has_s {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_s = true
}
i += 2
}
}
}
// There's an unclosed tag in there x.x
if has_i || has_u || has_b || has_s {
closer := []byte("</u></i></b></s>")
msgbytes = append(msgbytes, closer...)
}
// Copy the new complex parser over once the rough edges have been smoothed over
if complex_bbc {
msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
msg = bbcode_quotes.ReplaceAllString(msg,"<span class=\"postQuote\">$1</span>")
}
return string(msgbytes)
}
// Does every type of BBCode
func bbcode_full_parse(data interface{}) interface{} {
msg := data.(string)
//fmt.Println("BBCode PrePre String:")
//fmt.Println("`"+msg+"`")
//fmt.Println("----")
msgbytes := []byte(msg)
has_u := false
has_b := false
has_i := false
has_s := false
has_c := false
complex_bbc := false
msgbytes = append(msgbytes,space_gap...)
//fmt.Println("BBCode Simple Pre:")
//fmt.Println("`"+string(msgbytes)+"`")
//fmt.Println("----")
for i := 0; i < len(msgbytes); i++ {
if msgbytes[i] == '[' {
if msgbytes[i + 2] != ']' {
if msgbytes[i + 1] == '/' {
if msgbytes[i + 3] == ']' {
if !has_c {
if msgbytes[i + 2] == 'b' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_b = false
} else if msgbytes[i + 2] == 'i' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_i = false
} else if msgbytes[i + 2] == 'u' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_u = false
} else if msgbytes[i + 2] == 's' {
msgbytes[i] = '<'
msgbytes[i + 3] = '>'
has_s = false
}
i += 3
}
} else {
if msgbytes[i+2] == 'c' && msgbytes[i+3] == 'o' && msgbytes[i+4] == 'd' && msgbytes[i+5] == 'e' && msgbytes[i+6] == ']' {
has_c = false
i += 7
}
//if msglen >= (i+6) {
// fmt.Println("boo")
// fmt.Println(msglen)
// fmt.Println(i+6)
// fmt.Println(string(msgbytes[i:i+6]))
//}
complex_bbc = true
}
} else {
if msgbytes[i+1] == 'c' && msgbytes[i+2] == 'o' && msgbytes[i+3] == 'd' && msgbytes[i+4] == 'e' && msgbytes[i+5] == ']' {
has_c = true
i += 6
}
//if msglen >= (i+5) {
// fmt.Println("boo2")
// fmt.Println(string(msgbytes[i:i+5]))
//}
complex_bbc = true
}
} else if !has_c {
if msgbytes[i + 1] == 'b' && !has_b {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_b = true
} else if msgbytes[i + 1] == 'i' && !has_i {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_i = true
} else if msgbytes[i + 1] == 'u' && !has_u {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_u = true
} else if msgbytes[i + 1] == 's' && !has_s {
msgbytes[i] = '<'
msgbytes[i + 2] = '>'
has_s = true
}
i += 2
}
}
}
// There's an unclosed tag in there x.x
if has_i || has_u || has_b || has_s {
closer := []byte("</u></i></b></s>")
msgbytes = append(msgbytes, closer...)
}
if complex_bbc {
i := 0
var start int
var lastTag int
var outbytes []byte
//fmt.Println("BBCode Pre:")
//fmt.Println("`"+string(msgbytes)+"`")
//fmt.Println("----")
for ; i < len(msgbytes); i++ {
MainLoop:
if msgbytes[i] == '[' {
OuterComplex:
if msgbytes[i + 1] == 'u' {
if msgbytes[i+2] == 'r' && msgbytes[i+3] == 'l' && msgbytes[i+4] == ']' {
start = i + 5
outbytes = append(outbytes, msgbytes[lastTag:i]...)
i = start
i += partial_url_bytes_len(msgbytes[start:])
//fmt.Println("Partial Bytes:")
//fmt.Println(string(msgbytes[start:]))
//fmt.Println("-----")
if !bytes.Equal(msgbytes[i:i+6],[]byte("[/url]")) {
//fmt.Println("Invalid Bytes:")
//fmt.Println(string(msgbytes[i:i+6]))
//fmt.Println("-----")
outbytes = append(outbytes, invalid_url...)
goto MainLoop
}
outbytes = append(outbytes, url_open...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, url_open2...)
outbytes = append(outbytes, msgbytes[start:i]...)
outbytes = append(outbytes, url_close...)
i += 6
lastTag = i
}
} else if msgbytes[i + 1] == 'r' {
if bytes.Equal(msgbytes[i+2:i+6],[]byte("and]")) {
outbytes = append(outbytes, msgbytes[lastTag:i]...)
start = i + 6
i = start
for ;; i++ {
if msgbytes[i] == '[' {
if !bytes.Equal(msgbytes[i+1:i+7],[]byte("/rand]")) {
outbytes = append(outbytes, bbcode_missing_tag...)
goto OuterComplex
}
break
} else if (len(msgbytes) - 1) < (i + 10) {
outbytes = append(outbytes, bbcode_missing_tag...)
goto OuterComplex
}
}
number, err := strconv.ParseInt(string(msgbytes[start:i]),10,64)
if err != nil {
outbytes = append(outbytes, bbcode_invalid_number...)
goto MainLoop
}
dat := []byte(strconv.FormatInt((random.Int63n(number)),10))
outbytes = append(outbytes, dat...)
//log.Print("Outputted the random number")
i += 7
lastTag = i
}
}
}
}
//fmt.Println(string(outbytes))
if lastTag != i {
outbytes = append(outbytes, msgbytes[lastTag:]...)
//fmt.Println("Outbytes:")
//fmt.Println(`"`+string(outbytes)+`"`)
//fmt.Println("----")
}
if len(outbytes) != 0 {
//fmt.Println("BBCode Post:")
//fmt.Println(`"`+string(outbytes[0:len(outbytes) - 10])+`"`)
//fmt.Println("----")
msg = string(outbytes[0:len(outbytes) - 10])
} else {
msg = string(msgbytes[0:len(msgbytes) - 10])
}
//msg = bbcode_url.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$1$2//$3</i>")
msg = bbcode_url_label.ReplaceAllString(msg,"<a href=\"$1$2//$3\" rel=\"nofollow\">$4</i>")
msg = bbcode_quotes.ReplaceAllString(msg,"<span class=\"postQuote\">$1</span>")
// Convert [code] into class="codequotes"
//fmt.Println("guuuaaaa")
} else {
msg = string(msgbytes[0:len(msgbytes) - 10])
}
return msg
}