diff options
author | Bohdan Horbeshko <bodqhrohro@gmail.com> | 2023-09-18 06:21:57 +0300 |
---|---|---|
committer | Bohdan Horbeshko <bodqhrohro@gmail.com> | 2023-09-18 06:21:57 +0300 |
commit | f99f4f6acc6734ecbd0da80015285e6b3d39fdd8 (patch) | |
tree | 1edb75e85dab67337cc4d795cb66677242df1d55 /xmpp | |
parent | 776993894ad780f1500c139aff85378c8a1d22f5 (diff) |
Send memberlist on MUC join, suppress PM statuses for MUC JIDs
Diffstat (limited to 'xmpp')
-rw-r--r-- | xmpp/extensions/extensions.go | 24 | ||||
-rw-r--r-- | xmpp/gateway/gateway.go | 24 | ||||
-rw-r--r-- | xmpp/handlers.go | 86 |
3 files changed, 134 insertions, 0 deletions
diff --git a/xmpp/extensions/extensions.go b/xmpp/extensions/extensions.go index 8e2f743..0b7269f 100644 --- a/xmpp/extensions/extensions.go +++ b/xmpp/extensions/extensions.go @@ -213,6 +213,19 @@ type QueryRegisterRemove struct { XMLName xml.Name `xml:"remove"` } +// PresenceXMucUserExtension is from XEP-0045 +type PresenceXMucUserExtension struct { + XMLName xml.Name `xml:"http://jabber.org/protocol/muc#user x"` + Item PresenceXMucUserItem +} + +// PresenceXMucUserItem is from XEP-0045 +type PresenceXMucUserItem struct { + XMLName xml.Name `xml:"item"` + Affiliation string `xml:"affiliation,attr"` + Role string `xml:"role,attr"` +} + // Namespace is a namespace! func (c PresenceNickExtension) Namespace() string { return c.XMLName.Space @@ -278,6 +291,11 @@ func (c QueryRegister) GetSet() *stanza.ResultSet { return c.ResultSet } +// Namespace is a namespace! +func (c PresenceXMucUserExtension) Namespace() string { + return c.XMLName.Space +} + // Name is a packet name func (ClientMessage) Name() string { return "message" @@ -362,4 +380,10 @@ func init() { "jabber:iq:register", "query", }, QueryRegister{}) + + // presence muc user + stanza.TypeRegistry.MapExtension(stanza.PKTPresence, xml.Name{ + "http://jabber.org/protocol/muc#user", + "x", + }, PresenceXMucUserExtension{}) } diff --git a/xmpp/gateway/gateway.go b/xmpp/gateway/gateway.go index dfe2ebf..c09a061 100644 --- a/xmpp/gateway/gateway.go +++ b/xmpp/gateway/gateway.go @@ -240,6 +240,9 @@ var SPResource = args.NewString() // SPImmed skips queueing var SPImmed = args.NewBool(args.Default(true)) +// SPAffiliation is a XEP-0045 MUC affiliation +var SPAffiliation = args.NewString() + func newPresence(bareJid string, to string, args ...args.V) stanza.Presence { var presenceFrom string if SPFrom.IsSet(args) { @@ -295,6 +298,17 @@ func newPresence(bareJid string, to string, args ...args.V) stanza.Presence { }) } } + if SPAffiliation.IsSet(args) { + affiliation := SPAffiliation.Get(args) + if affiliation != "" { + presence.Extensions = append(presence.Extensions, extensions.PresenceXMucUserExtension{ + Item: extensions.PresenceXMucUserItem{ + Affiliation: affiliation, + Role: affilationToRole(affiliation), + }, + }) + } + } return presence } @@ -377,3 +391,13 @@ func SplitJID(from string) (string, string, bool) { } return fromJid.Bare(), fromJid.Resource, true } + +func affilationToRole(affilation string) string { + switch affilation { + case "owner", "admin": + return "moderator" + case "member": + return "participant" + } + return "none" +} diff --git a/xmpp/handlers.go b/xmpp/handlers.go index 6f51427..a1f6d74 100644 --- a/xmpp/handlers.go +++ b/xmpp/handlers.go @@ -287,6 +287,12 @@ func HandlePresence(s xmpp.Sender, p stanza.Packet) { } if prs.To == gateway.Jid.Bare() { handlePresence(s, prs) + return + } + var mucExt stanza.MucPresence + prs.Get(&mucExt) + if mucExt.XMLName.Space != "" { + handleMUCPresence(s, prs) } } @@ -397,6 +403,64 @@ func handlePresence(s xmpp.Sender, p stanza.Presence) { } } +func handleMUCPresence(s xmpp.Sender, p stanza.Presence) { + log.WithFields(log.Fields{ + "type": p.Type, + "from": p.From, + "to": p.To, + }).Warn("MUC presence") + log.Debugf("%#v", p) + + if p.Type == "" { + toBare, nickname, ok := gateway.SplitJID(p.To) + if ok { + component, ok := s.(*xmpp.Component) + if !ok { + log.Error("Not a component") + return + } + + reply := stanza.Presence{Attrs: stanza.Attrs{ + From: toBare, + To: p.From, + Id: p.Id, + }} + defer gateway.ResumableSend(component, reply) + + if nickname == "" { + presenceReplySetError(&reply, 400) + return + } + + chatId, ok := toToID(toBare) + if !ok { + presenceReplySetError(&reply, 404) + return + } + + fromBare, _, ok := gateway.SplitJID(p.From) + if !ok { + presenceReplySetError(&reply, 400) + return + } + + session, ok := sessions[fromBare] + if !ok || !session.Session.MUC { + presenceReplySetError(&reply, 401) + return + } + + chat, _, err := session.GetContactByID(chatId, nil) + if err != nil || !session.IsGroup(chat) { + presenceReplySetError(&reply, 404) + return + } + + session.SendMUCStatuses(chatId) + } + } +} + func handleGetVcardIq(s xmpp.Sender, iq *stanza.IQ, typ byte) { log.WithFields(log.Fields{ "from": iq.From, @@ -711,6 +775,28 @@ func iqAnswerSetError(answer *stanza.IQ, payload *extensions.QueryRegister, code } } +func presenceReplySetError(reply *stanza.Presence, code int) { + reply.Type = stanza.PresenceTypeError + reply.Error = stanza.Err{ + Code: code, + } + switch code { + case 400: + reply.Error.Type = stanza.ErrorTypeModify + reply.Error.Reason = "jid-malformed" + case 401: + reply.Error.Type = stanza.ErrorTypeAuth + reply.Error.Reason = "not-authorized" + case 404: + reply.Error.Type = stanza.ErrorTypeCancel + reply.Error.Reason = "item-not-found" + default: + log.Error("Unknown error code, falling back with empty reason") + reply.Error.Type = stanza.ErrorTypeCancel + reply.Error.Reason = "undefined-condition" + } +} + func toToID(to string) (int64, bool) { toParts := strings.Split(to, "@") if len(toParts) < 2 { |