Ping (XEP-0199/XEP-0410)

This commit is contained in:
Bohdan Horbeshko 2026-08-21 21:05:51 -04:00
parent 484743946a
commit 4566297817
3 changed files with 69 additions and 0 deletions

View file

@ -493,6 +493,21 @@ type EntityTime struct {
ResultSet *stanza.ResultSet `xml:"set,omitempty"`
}
// Ping is from XEP-0199, also used for XEP-0410 MUC self-ping
type Ping struct {
XMLName xml.Name `xml:"urn:xmpp:ping ping"`
}
// Namespace is a namespace!
func (c Ping) Namespace() string {
return c.XMLName.Space
}
// GetSet getsets!
func (c Ping) GetSet() *stanza.ResultSet {
return nil
}
// AttachTo is from XEP-0367
type AttachTo struct {
XMLName xml.Name `xml:"urn:xmpp:message-attaching:1 attach-to"`
@ -952,6 +967,12 @@ func init() {
"time",
}, EntityTime{})
// ping
stanza.TypeRegistry.MapExtension(stanza.PKTIQ, xml.Name{
"urn:xmpp:ping",
"ping",
}, Ping{})
// attach-to
stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{
"urn:xmpp:message-attaching:1",

View file

@ -1172,6 +1172,7 @@ func AddCommonDiscoFeatures(disco *stanza.DiscoInfo) {
NSCommand,
"jabber:iq:version",
"urn:xmpp:time",
"urn:xmpp:ping",
stanza.NSDiscoInfo,
NSCaps,
)

View file

@ -149,6 +149,11 @@ func HandleIq(s xmpp.Sender, p stanza.Packet) {
go handleGetEntityTime(s, iq)
return
}
_, ok = iq.Payload.(*extensions.Ping)
if ok {
go handleGetPing(s, iq)
return
}
} else if iq.Type == stanza.IQTypeSet {
queryRegister, ok := iq.Payload.(*extensions.QueryRegister)
if ok {
@ -1459,6 +1464,48 @@ func handleGetEntityTime(s xmpp.Sender, iq *stanza.IQ) {
log.Debugf("%#v", entityTime)
}
// handleGetPing answers XEP-0199 ping. When addressed to a MUC occupant JID
// (room@service/nick), it implements the XEP-0410 self-ping optimization:
// answer directly from in-memory occupant state instead of routing the ping
// to a (nonexistent) full JID for that occupant.
func handleGetPing(s xmpp.Sender, iq *stanza.IQ) {
component, answer, ok := iqResultStub(s, iq)
if !ok {
return
}
defer gateway.ResumableSend(component, answer)
toJid, err := stanza.NewJid(iq.To)
if err != nil || toJid.Resource == "" {
// plain service/entity ping, not addressed to a MUC occupant
return
}
toID, toOk, toIsGroup := toToID(iq.To)
if !toOk || !toIsGroup {
// not a MUC room JID either, treat as a plain entity ping
return
}
bare, resource, fromOk := gateway.SplitJID(iq.From)
if !fromOk {
iqAnswerSetError(answer, 400)
return
}
session, sessionOk := sessions[bare]
if !sessionOk || !session.Session.MUC {
iqAnswerSetError(answer, 403)
return
}
nick, hasNick := session.GetMyMUCNickname(toID)
if !hasNick || nick != toJid.Resource || !session.MUCHasResource(toID, resource) {
iqAnswerSetError(answer, 404)
return
}
}
func handleGetQueryMucAdmin(s xmpp.Sender, iq *stanza.IQ, query *extensions.QueryMucAdmin) {
component, answer, ok := iqResultStub(s, iq)
if !ok {