2024-04-03 07:48:47 +02:00
|
|
|
/* Copyright Martin Dosch
|
|
|
|
Licensed under the "MIT License" */
|
|
|
|
|
2019-05-31 23:45:29 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"strings"
|
|
|
|
|
2024-01-11 15:54:06 +01:00
|
|
|
"github.com/xmppo/go-xmpp"
|
2019-05-31 23:45:29 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func processStanzas(client *xmpp.Client, muc string, mucNick string, feeds []string, quiet bool, contact string) {
|
|
|
|
for {
|
|
|
|
// Receive stanzas.
|
|
|
|
stanza, err := client.Recv()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed receiving Stanzas:", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check stanzas, maybe we want to reply.
|
|
|
|
switch v := stanza.(type) {
|
|
|
|
// Reply to requests for source and feeds.
|
|
|
|
case xmpp.Chat:
|
|
|
|
var command string
|
|
|
|
|
2024-10-05 15:20:57 +02:00
|
|
|
switch v.Type {
|
2019-05-31 23:45:29 +02:00
|
|
|
// Check for room mention of the bots nick if the the message type is groupchat.
|
2024-10-05 15:20:57 +02:00
|
|
|
case "groupchat":
|
2019-05-31 23:45:29 +02:00
|
|
|
// Leave if option quiet is set.
|
2019-05-31 12:36:30 +02:00
|
|
|
if quiet {
|
2019-05-31 23:45:29 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
// Get first word of the message and transform it to lower case.
|
|
|
|
mention := strings.ToLower(strings.Split(v.Text, " ")[0])
|
|
|
|
|
|
|
|
// If it is not the bots nick remove one trailing character as
|
|
|
|
// a lot of clients append `:` or `,` to mentions.
|
|
|
|
if mention != strings.ToLower(mucNick) {
|
|
|
|
mentionLength := len(mention)
|
|
|
|
// Leave if mentionLength is <= 0
|
|
|
|
if mentionLength <= 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
mention = mention[:mentionLength-1]
|
|
|
|
// Leave if the message is not addressed to the bot.
|
|
|
|
if mention != strings.ToLower(mucNick) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// As the first word is the mention of the bots nickname, the command is
|
|
|
|
// the second word in a groupchat message.
|
|
|
|
command = strings.ToLower(strings.Split(v.Text, " ")[1])
|
|
|
|
// If the message type is chat (e.g. private message), the command is the
|
|
|
|
// first word.
|
2024-10-05 15:20:57 +02:00
|
|
|
case "chat":
|
2019-05-31 23:45:29 +02:00
|
|
|
command = strings.ToLower(strings.Split(v.Text, " ")[0])
|
2024-10-05 15:20:57 +02:00
|
|
|
default:
|
2019-05-31 23:45:29 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for the command.
|
|
|
|
switch command {
|
|
|
|
|
|
|
|
// Reply with a short summary of available commands for `help`.
|
|
|
|
case "help":
|
|
|
|
|
|
|
|
reply := "The following commands are available:\n" +
|
|
|
|
"\"contact\": Show contact for this bot.\n" +
|
|
|
|
"\"feeds\": List feeds I'm following.\n" +
|
|
|
|
"\"ping\": Sends back a pong.\n" +
|
|
|
|
"\"source\": Show source code URL."
|
|
|
|
|
|
|
|
if v.Type == "groupchat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: muc,
|
|
|
|
Type: "groupchat", Text: strings.Split(v.Remote, "/")[1] + ": " + reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to MUC:", err)
|
|
|
|
}
|
|
|
|
} else if v.Type == "chat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: v.Remote,
|
|
|
|
Type: "chat", Text: reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to ", v.Remote, ": ", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reply with repo address for `source`.
|
|
|
|
case "source":
|
|
|
|
|
|
|
|
reply := "My source can be found at " +
|
2020-05-14 16:09:08 +02:00
|
|
|
"https://salsa.debian.org/mdosch/feed-to-muc"
|
2019-05-31 23:45:29 +02:00
|
|
|
|
|
|
|
if v.Type == "groupchat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: muc,
|
|
|
|
Type: "groupchat", Text: strings.Split(v.Remote, "/")[1] + ": " + reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to MUC:", err)
|
|
|
|
}
|
|
|
|
} else if v.Type == "chat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: v.Remote,
|
|
|
|
Type: "chat", Text: reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to ", v.Remote, ": ", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Reply with the list of monitored feeds for `feeds`.
|
|
|
|
case "feeds":
|
|
|
|
var feedList string
|
|
|
|
for _, feed := range feeds {
|
|
|
|
// Add next feed element and a newline.
|
|
|
|
feedList = feedList + feed + "\n"
|
|
|
|
}
|
|
|
|
|
|
|
|
reply := "Feeds I'm following:\n" + feedList
|
|
|
|
|
|
|
|
if v.Type == "groupchat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: muc,
|
|
|
|
Type: "groupchat", Text: strings.Split(v.Remote, "/")[1] + ": " + reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to MUC:", err)
|
|
|
|
}
|
|
|
|
} else if v.Type == "chat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: v.Remote,
|
|
|
|
Type: "chat", Text: reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to ", v.Remote, ": ", err)
|
|
|
|
}
|
|
|
|
}
|
2019-05-31 23:50:51 +02:00
|
|
|
// Reply with pong to ping requests.
|
2023-04-06 17:51:14 +02:00
|
|
|
case "ping", "bing":
|
|
|
|
var reply string
|
|
|
|
if command == "bing" {
|
|
|
|
reply = "bong"
|
|
|
|
} else {
|
|
|
|
reply = "pong"
|
|
|
|
}
|
2019-05-31 23:45:29 +02:00
|
|
|
|
|
|
|
if v.Type == "groupchat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: muc,
|
|
|
|
Type: "groupchat", Text: strings.Split(v.Remote, "/")[1] + ": " + reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to MUC:", err)
|
|
|
|
}
|
|
|
|
} else if v.Type == "chat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: v.Remote,
|
|
|
|
Type: "chat", Text: reply,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to ", v.Remote, ": ", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-31 23:50:51 +02:00
|
|
|
// Reply with contact address if set.
|
2019-05-31 23:45:29 +02:00
|
|
|
case "contact":
|
|
|
|
|
|
|
|
if contact == "" {
|
|
|
|
contact = "Sorry, no contact information provided."
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.Type == "groupchat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: muc,
|
|
|
|
Type: "groupchat", Text: strings.Split(v.Remote, "/")[1] + ": " + contact,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to MUC:", err)
|
|
|
|
}
|
|
|
|
} else if v.Type == "chat" {
|
2023-09-30 20:42:07 +02:00
|
|
|
_, err = client.Send(xmpp.Chat{
|
|
|
|
Remote: v.Remote,
|
|
|
|
Type: "chat", Text: contact,
|
|
|
|
})
|
2019-05-31 23:45:29 +02:00
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed sending message to ", v.Remote, ": ", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reply to pings and disco queries.
|
|
|
|
case xmpp.IQ:
|
|
|
|
|
|
|
|
if (v.Type == "error") && (v.ID == ID) {
|
|
|
|
log.Fatal("MUC not available. processStanza")
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v.Type == "result") && (v.ID == ID) {
|
|
|
|
pingReceived = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if v.Type == "get" {
|
|
|
|
// Reply to disco#info requests according to https://xmpp.org/extensions/xep-0030.html.
|
2024-10-05 15:20:57 +02:00
|
|
|
switch {
|
|
|
|
case strings.Contains(string(v.Query),
|
|
|
|
"<query xmlns='http://jabber.org/protocol/disco#info'/>"):
|
2019-05-31 23:45:29 +02:00
|
|
|
_, err := client.RawInformation(client.JID(), v.From, v.ID,
|
|
|
|
"result", "<query xmlns='http://jabber.org/protocol/disco#info'>"+
|
|
|
|
"<identity category='client' type='bot' name='feedbot'/>"+
|
|
|
|
"<feature var='http://jabber.org/protocol/disco#info'/></query>")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed to reply to disco#info:", err)
|
|
|
|
}
|
2024-10-05 15:20:57 +02:00
|
|
|
case strings.Contains(string(v.Query), "<ping xmlns='urn:xmpp:ping'/>"):
|
2019-05-31 23:45:29 +02:00
|
|
|
// Reply to pings.
|
|
|
|
_, err := client.RawInformation(client.JID(), v.From, v.ID, "result", "")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed to reply to ping:", err)
|
|
|
|
}
|
2024-10-05 15:20:57 +02:00
|
|
|
default:
|
2019-05-31 23:45:29 +02:00
|
|
|
// Send error replies for all other IQs.
|
|
|
|
_, err := client.RawInformation(client.JID(), v.From, v.ID, "error",
|
|
|
|
"<error type='cancel'><service-unavailable "+
|
|
|
|
"xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal("Error: Failed to send error IQ:", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|