2026-01-29 21:35:36 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
2026-08-16 20:07:53 +01:00
|
|
|
"context"
|
2026-07-17 17:15:41 +01:00
|
|
|
"fmt"
|
2026-01-29 21:35:36 +00:00
|
|
|
"gosrc.io/xmpp"
|
|
|
|
|
"gosrc.io/xmpp/stanza"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// This file has small functions that can be used to do XMPP stuff without writing tons of boilerplate
|
|
|
|
|
|
|
|
|
|
// Basic message sender. Anything more complex should be written by hand
|
2026-03-10 16:35:56 +00:00
|
|
|
func sendMessage(c xmpp.Sender, sendTo string, msgType stanza.StanzaType, body string, subject string, thread string, exts []stanza.MsgExtension) error {
|
2026-01-29 21:35:36 +00:00
|
|
|
m := stanza.Message{
|
|
|
|
|
Attrs: stanza.Attrs{
|
|
|
|
|
To: sendTo,
|
|
|
|
|
Type: msgType,
|
|
|
|
|
},
|
2026-03-10 16:48:10 +00:00
|
|
|
Body: body,
|
|
|
|
|
Subject: subject,
|
|
|
|
|
Thread: thread,
|
2026-03-10 16:35:56 +00:00
|
|
|
Extensions: exts,
|
2026-01-29 21:35:36 +00:00
|
|
|
}
|
|
|
|
|
err := c.Send(m)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Joins a MUC
|
2026-04-26 10:40:13 +01:00
|
|
|
func joinMuc(c xmpp.Sender, jid string, muc string, nick string, password string) error {
|
|
|
|
|
var joinPresence stanza.Presence
|
2026-01-29 21:35:36 +00:00
|
|
|
addr := muc + "/" + nick
|
2026-04-26 10:40:13 +01:00
|
|
|
if password == "" {
|
|
|
|
|
joinPresence = stanza.Presence{
|
|
|
|
|
Attrs: stanza.Attrs{
|
|
|
|
|
From: jid,
|
|
|
|
|
To: addr,
|
|
|
|
|
},
|
|
|
|
|
Extensions: []stanza.PresExtension{
|
|
|
|
|
&stanza.MucPresence{},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
joinPresence = stanza.Presence{
|
|
|
|
|
Attrs: stanza.Attrs{
|
|
|
|
|
From: jid,
|
|
|
|
|
To: addr,
|
|
|
|
|
},
|
|
|
|
|
Extensions: []stanza.PresExtension{
|
|
|
|
|
&stanza.MucPresence{
|
|
|
|
|
Password: password,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
2026-01-29 21:35:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := client.Send(joinPresence)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2026-02-01 13:49:30 +00:00
|
|
|
|
2026-04-30 14:55:17 +01:00
|
|
|
func joinMucWithoutHistory(c xmpp.Sender, jid string, muc string, nick string, password string) error {
|
|
|
|
|
var joinPresence stanza.Presence
|
|
|
|
|
addr := muc + "/" + nick
|
|
|
|
|
if password == "" {
|
|
|
|
|
joinPresence = stanza.Presence{
|
|
|
|
|
Attrs: stanza.Attrs{
|
|
|
|
|
From: jid,
|
|
|
|
|
To: addr,
|
|
|
|
|
},
|
|
|
|
|
Extensions: []stanza.PresExtension{
|
|
|
|
|
&stanza.MucPresence{
|
|
|
|
|
History: stanza.History{
|
|
|
|
|
MaxChars: stanza.NewNullableInt(0),
|
|
|
|
|
MaxStanzas: stanza.NewNullableInt(0),
|
|
|
|
|
Seconds: stanza.NewNullableInt(0),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
joinPresence = stanza.Presence{
|
|
|
|
|
Attrs: stanza.Attrs{
|
|
|
|
|
From: jid,
|
|
|
|
|
To: addr,
|
|
|
|
|
},
|
|
|
|
|
Extensions: []stanza.PresExtension{
|
|
|
|
|
&stanza.MucPresence{
|
|
|
|
|
Password: password,
|
|
|
|
|
History: stanza.History{
|
|
|
|
|
MaxChars: stanza.NewNullableInt(0),
|
|
|
|
|
MaxStanzas: stanza.NewNullableInt(0),
|
|
|
|
|
Seconds: stanza.NewNullableInt(0),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := client.Send(joinPresence)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:49:30 +00:00
|
|
|
// jid MustParse but using gosrc's instead of mellium
|
|
|
|
|
// This function will panic if its an invalid JID
|
|
|
|
|
|
2026-02-16 09:54:37 +00:00
|
|
|
func JidMustParse(s string) *stanza.Jid {
|
2026-02-01 13:49:30 +00:00
|
|
|
j, err := stanza.NewJid(s)
|
|
|
|
|
if err != nil {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
return j
|
|
|
|
|
}
|
2026-07-14 16:25:18 +01:00
|
|
|
|
|
|
|
|
func sendVoiceRequest(c xmpp.Sender, sendTo string) error {
|
|
|
|
|
err := c.SendRaw(fmt.Sprintf(`
|
|
|
|
|
<message from='%s'
|
|
|
|
|
id='yd53c486'
|
|
|
|
|
to='%s'>
|
|
|
|
|
<x xmlns='jabber:x:data' type='submit'>
|
|
|
|
|
<field var='FORM_TYPE'>
|
|
|
|
|
<value>http://jabber.org/protocol/muc#request</value>
|
|
|
|
|
</field>
|
|
|
|
|
<field var='muc#role'
|
|
|
|
|
type='list-single'
|
|
|
|
|
label='Requested role'>
|
|
|
|
|
<value>participant</value>
|
|
|
|
|
</field>
|
|
|
|
|
</x>
|
|
|
|
|
</message>
|
|
|
|
|
`, clientroot.Session.BindJid, sendTo))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2026-08-16 20:07:53 +01:00
|
|
|
|
|
|
|
|
func addPEPBookmark(c xmpp.Sender, jid string, name string, nick string, autojoin bool, password string) (stanza.IQ, error) {
|
|
|
|
|
item := new(stanza.Item)
|
|
|
|
|
item.Id = jid
|
|
|
|
|
|
|
|
|
|
bookmark := Bookmark{}
|
|
|
|
|
bookmark.Name = name
|
|
|
|
|
bookmark.Autojoin = autojoin
|
|
|
|
|
bookmark.Nick = nick
|
|
|
|
|
bookmark.Password = password
|
|
|
|
|
node := bookmark.ToNode()
|
|
|
|
|
|
|
|
|
|
options_form := new(stanza.Form)
|
|
|
|
|
options_form.Type = "submit"
|
|
|
|
|
|
|
|
|
|
persist := new(stanza.Field)
|
|
|
|
|
persist.Type = "boolean"
|
|
|
|
|
persist.Var = "pubsub#persist_items"
|
|
|
|
|
persist.ValuesList = []string{"true"}
|
|
|
|
|
options_form.Fields = append(options_form.Fields, persist)
|
|
|
|
|
|
|
|
|
|
max_items := new(stanza.Field)
|
|
|
|
|
max_items.Type = "text-single"
|
|
|
|
|
max_items.Var = "pubsub#max_items"
|
|
|
|
|
max_items.ValuesList = []string{"max"}
|
|
|
|
|
options_form.Fields = append(options_form.Fields, max_items)
|
|
|
|
|
|
|
|
|
|
send_last_published_item := new(stanza.Field)
|
|
|
|
|
send_last_published_item.Type = "text-single"
|
|
|
|
|
send_last_published_item.Var = "pubsub#send_last_published_item"
|
|
|
|
|
send_last_published_item.ValuesList = []string{"never"}
|
|
|
|
|
options_form.Fields = append(options_form.Fields, send_last_published_item)
|
|
|
|
|
|
|
|
|
|
access_model := new(stanza.Field)
|
|
|
|
|
access_model.Type = "text-single"
|
|
|
|
|
access_model.Var = "pubsub#access_model"
|
|
|
|
|
access_model.ValuesList = []string{"whitelist"}
|
|
|
|
|
options_form.Fields = append(options_form.Fields, access_model)
|
|
|
|
|
|
|
|
|
|
options := new(stanza.PublishOptions)
|
|
|
|
|
options.Form = options_form
|
|
|
|
|
|
|
|
|
|
item.Any = node
|
|
|
|
|
items := []stanza.Item{*item}
|
|
|
|
|
pubsub, err := stanza.NewPublishItemOptsRq("", "urn:xmpp:bookmarks:1", items, options)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return stanza.IQ{}, err
|
|
|
|
|
}
|
|
|
|
|
ctx := context.TODO()
|
|
|
|
|
|
|
|
|
|
channel, err := c.SendIQ(ctx, pubsub)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return stanza.IQ{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result := <-channel
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|