Basic CTCP handling (#5) * Implemented basic CTCP recognition and handling * implemented additional CTCP-related calls, implemented CTCP ping Co-authored-by: nojusr @office <nojus.raskevicius@teltonika.lt>
Nojus nojusr@gmail.com
Sun, 21 Nov 2021 17:41:22 +0200
1 files changed,
93 insertions(+),
10 deletions(-)
jump to
M
main.go
→
main.go
@@ -1,31 +1,114 @@
package main import ( + "fmt" "log" "net" + "strings" "git.icyphox.sh/paprika/database" "git.icyphox.sh/paprika/plugins" "gopkg.in/irc.v3" ) +// A simple check func to find out if an incoming irc message +// is supposed to be a CTCP message +func isCTCPmessage(m *irc.Message) bool { + // CTCP messages are identified by their first character byte + // being equal to 0x01. + return m.Params[1][0] == 0x01 +} + +// CTCP responses are sent with a NOTICE, instead of a PRIVMSG +func sendCTCPResponse(c *irc.Client, m *irc.Message, command string, message string) { + c.WriteMessage(&irc.Message{ + Command: "NOTICE", + Params: []string{ + m.Prefix.Name, + fmt.Sprintf("\x01%s %s\x01", command, message), + }, + }) +} + +// for future use. Perhaps move all of this CTCP stuff out another file? +func sendCTCPRequest(c *irc.Client, m *irc.Message, command string, message string) { + c.WriteMessage(&irc.Message{ + Command: "PRIVMSG", + Params: []string{ + m.Prefix.Name, + fmt.Sprintf("\x01%s %s\x01", command, message), + }, + }) +} + +func handleCTCPMessage(c *irc.Client, m *irc.Message) { + + // Refer to for further commands to implement and as a general + // guide on how CTCP works: + // https://tools.ietf.org/id/draft-oakley-irc-ctcp-01.html + + var ctcpCommand = m.Params[1] // var might be named wrong + + // start of the main if/else tree for CTCP checking. idk why, but + // for some reason a straight switch/case comparison simply did not work + if strings.Contains(ctcpCommand, "VERSION") { + sendCTCPResponse(c, m, "VERSION", "Paprika v0.0.1") + } else if strings.Contains(ctcpCommand, "PING") { + // lotsa ugly string processing here, but w/e + + // split the incoming ping by word, strip out the first word (the command) + output := strings.Split(m.Params[1], " ")[1:] + outputStr := strings.Join(output, " ") // re-join + + // send response while stripping out the last char, + // somehwere deep in the wirting a random char gets added + // to the start and end of the incomming message. + // the first char gets stripped out along with the command word. + // the last char gets stripped out here. + sendCTCPResponse(c, m, "PING", outputStr[0:len(outputStr)-1]) + } else if strings.Contains(ctcpCommand, "CLIENTINFO") { + + // UPDATE THIS WITH ANY NEW CTCP COMMAND YOU IMPLEMENT + sendCTCPResponse( + c, m, + "CLIENTINFO", + "VERSION PING", + ) + } +} + +func handleChatMessage(c *irc.Client, m *irc.Message) { + response, err := plugins.ProcessTrigger(m) + if err != nil { + log.Printf("error: %v", err) + } + + // split the plugin output by it's newlines, send every line + // as a separate PRIVMSG + split := strings.Split(response, "\n") + + for _, line := range split { + c.WriteMessage(&irc.Message{ + Command: "PRIVMSG", + Params: []string{ + m.Params[0], + line, + }, + }) + } +} + func ircHandler(c *irc.Client, m *irc.Message) { switch m.Command { case "001": // TODO: load this from config c.Write("JOIN #taigobot-test") case "PRIVMSG": - response, err := plugins.ProcessTrigger(m) - if err != nil { - log.Printf("error: %v", err) + if isCTCPmessage(m) { + handleCTCPMessage(c, m) + } else { + handleChatMessage(c, m) } - c.WriteMessage(&irc.Message{ - Command: "PRIVMSG", - Params: []string{ - m.Params[0], - response, - }, - }) } }