diff --git a/component.go b/component.go
index 7bd6a1b..c1d41c3 100644
--- a/component.go
+++ b/component.go
@@ -216,6 +216,40 @@ func (handshakeDecoder) decode(p *xml.Decoder, se xml.StartElement) (Handshake,
return packet, err
}
+// ============================================================================
+// Component delegation
+// XEP-0355
+
+// Delegation can be used both on message (for delegated) and IQ (for Forwarded),
+// depending on the context.
+type Delegation struct {
+ MsgExtension
+ XMLName xml.Name `xml:"urn:xmpp:delegation:1 delegation"`
+ Forwarded Forwarded // This is used in iq to wrap delegated iqs
+ Delegated Delegated // This is used in a message to confirm delegated namespace
+}
+
+func (d *Delegation) Namespace() string {
+ return d.XMLName.Space
+}
+
+type Forwarded struct {
+ XMLName xml.Name `xml:"urn:xmpp:forward:0 forwarded"`
+ IQ IQ
+ Message Message
+ Presence Presence
+}
+
+type Delegated struct {
+ XMLName xml.Name `xml:"delegated"`
+ Namespace string `xml:"namespace,attr,omitempty"`
+}
+
+func init() {
+ TypeRegistry.MapExtension(PKTMessage, xml.Name{"urn:xmpp:delegation:1", "delegation"}, Delegation{})
+ TypeRegistry.MapExtension(PKTIQ, xml.Name{"urn:xmpp:delegation:1", "delegation"}, Delegation{})
+}
+
/*
TODO: Add support for discovery management directly in component
TODO: Support multiple identities on disco info
diff --git a/component_test.go b/component_test.go
index 20e3772..ee933aa 100644
--- a/component_test.go
+++ b/component_test.go
@@ -1,6 +1,9 @@
package xmpp // import "gosrc.io/xmpp"
-import "testing"
+import (
+ "encoding/xml"
+ "testing"
+)
func TestHandshake(t *testing.T) {
opts := ComponentOptions{
@@ -21,3 +24,72 @@ func TestHandshake(t *testing.T) {
func TestGenerateHandshake(t *testing.T) {
// TODO
}
+
+// We should be able to properly parse delegation confirmation messages
+func TestParsingDelegationMessage(t *testing.T) {
+ packetStr := `
+
+
+
+`
+ var msg Message
+ data := []byte(packetStr)
+ if err := xml.Unmarshal(data, &msg); err != nil {
+ t.Errorf("Unmarshal(%s) returned error", data)
+ }
+
+ // Check that we have extracted the delegation info as MsgExtension
+ var nsDelegated string
+ for _, ext := range msg.Extensions {
+ if delegation, ok := ext.(*Delegation); ok {
+ nsDelegated = delegation.Delegated.Namespace
+ }
+ }
+ if nsDelegated != "http://jabber.org/protocol/pubsub" {
+ t.Errorf("Could not find delegated namespace in delegation: %#v\n", msg)
+ }
+}
+
+// Check that we can parse a delegation IQ.
+// The most important thing is to be able to
+func TestParsingDelegationIQ(t *testing.T) {
+ packetStr := `
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+`
+ var iq IQ
+ data := []byte(packetStr)
+ if err := xml.Unmarshal(data, &iq); err != nil {
+ t.Errorf("Unmarshal(%s) returned error", data)
+ }
+
+ // Check that we have extracted the delegation info as IQPayload
+ var node string
+ for _, ext := range iq.Payload {
+ if delegation, ok := ext.(*Delegation); ok {
+ payload := delegation.Forwarded.IQ.Payload
+ if len(payload) > 0 {
+ payload := delegation.Forwarded.IQ.Payload[0]
+ if pubsub, ok := payload.(*PubSub); ok {
+ node = pubsub.Publish.Node
+ }
+ }
+ }
+ }
+ if node != "http://jabber.org/protocol/mood" {
+ t.Errorf("Could not find mood node name on delegated publish: %#v\n", iq)
+ }
+}
diff --git a/pep.go b/pep.go
index 6ead8ae..91c0188 100644
--- a/pep.go
+++ b/pep.go
@@ -1,25 +1,11 @@
package xmpp // import "gosrc.io/xmpp"
+// TODO: Move to a pubsub file
+
import (
"encoding/xml"
)
-type PubSub struct {
- XMLName xml.Name `xml:"http://jabber.org/protocol/pubsub pubsub"`
- Publish Publish
-}
-
-type Publish struct {
- XMLName xml.Name `xml:"publish"`
- Node string `xml:"node,attr"`
- Item Item
-}
-
-type Item struct {
- XMLName xml.Name `xml:"item"`
- Tune Tune
-}
-
type Tune struct {
XMLName xml.Name `xml:"http://jabber.org/protocol/tune tune"`
Artist string `xml:"artist,omitempty"`
@@ -31,53 +17,9 @@ type Tune struct {
Uri string `xml:"uri,omitempty"`
}
-/*
-type PubsubPublish struct {
- XMLName xml.Name `xml:"publish"`
- node string `xml:"node,attr"`
- item PubSubItem
+type Mood struct {
+ XMLName xml.Name `xml:"http://jabber.org/protocol/mood mood"`
+ // TODO: Custom parsing to extract mood type from tag name
+ // Mood type
+ Text string `xml:"text,omitempty"`
}
-
-type PubSubItem struct {
- xmlName xml.Name `xml:"item"`
-}
-
-type Thing2 struct {
- XMLName xml.Name `xml:"publish"`
- node string `xml:"node,attr"`
- tune string `xml:"http://jabber.org/protocol/tune item>tune"`
-}
-
-type Tune struct {
- artist string
- length int
- rating int
- source string
- title string
- track string
- uri string
-}
-*/
-
-/*
-func (*Tune) XMPPFormat() string {
- return fmt.Sprintf(
- `
-
-
- -
-
- %s
- %i
- %i
-
- %s
-
- %s
-
-
-
-
-`)
-}
-*/
diff --git a/pubsub.go b/pubsub.go
new file mode 100644
index 0000000..341c54f
--- /dev/null
+++ b/pubsub.go
@@ -0,0 +1,39 @@
+package xmpp // import "gosrc.io/xmpp"
+
+import (
+ "encoding/xml"
+)
+
+type PubSub struct {
+ XMLName xml.Name `xml:"http://jabber.org/protocol/pubsub pubsub"`
+ Publish Publish
+ Retract Retract
+ // TODO
+}
+
+func (p *PubSub) Namespace() string {
+ return p.XMLName.Space
+}
+
+type Publish struct {
+ XMLName xml.Name `xml:"publish"`
+ Node string `xml:"node,attr"`
+ Item Item
+}
+
+type Item struct {
+ XMLName xml.Name `xml:"item"`
+ Id string `xml:"id,attr,omitempty"`
+ Tune Tune
+}
+
+type Retract struct {
+ XMLName xml.Name `xml:"retract"`
+ Node string `xml:"node,attr"`
+ Notify string `xml:"notify,attr"`
+ Item Item
+}
+
+func init() {
+ TypeRegistry.MapExtension(PKTIQ, xml.Name{"http://jabber.org/protocol/pubsub", "pubsub"}, PubSub{})
+}
diff --git a/router.go b/router.go
index b1286f2..92b1594 100644
--- a/router.go
+++ b/router.go
@@ -8,6 +8,11 @@ import (
The XMPP router helps client and component developers select which XMPP they would like to process,
and associate processing code depending on the router configuration.
+Here are important rules to keep in mind while setting your routes and matchers:
+- Routes are evaluated in the order they are set.
+- When a route matches, it is executed and all others routes are ignored. For each packet, only a single
+ route is executed.
+
TODO: Automatically reply to IQ that do not match any route, to comply to XMPP standard.
*/