~samwhited/xmpp

384b0641fa9a2538a998304495408b7336caf067 — Sam Whited 9 months ago 85b7a77
forward: new package implementing forwarding

Signed-off-by: Sam Whited <sam@samwhited.com>
4 files changed, 125 insertions(+), 3 deletions(-)

A forward/forward.go
A forward/forward_test.go
M go.mod
M go.sum
A forward/forward.go => forward/forward.go +66 -0
@@ 0,0 1,66 @@
// Copyright 2021 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.

// Package forward implements forwarding messages.
package forward // import "mellium.im/xmpp/forward"

import (
	"encoding/xml"
	"time"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/delay"
	"mellium.im/xmpp/stanza"
)

// Namespaces used by this package, provided as a convenience.
const (
	NS = "urn:xmpp:forward:0"
)

// Forwarded can be embedded into another struct along with a stanza to wrap the
// stanza for forwarding.
type Forwarded struct {
	XMLName xml.Name    `xml:"urn:xmpp:forward:0 forwarded"`
	Delay   delay.Delay `xml:"urn:xmpp:delay delay"`
}

// Wrap wraps the provided token reader (which should be a stanza, but this is
// not enforced) to prepare it for forwarding.
func (f Forwarded) Wrap(r xml.TokenReader) xml.TokenReader {
	return xmlstream.Wrap(
		xmlstream.MultiReader(
			f.Delay.TokenReader(),
			r,
		),
		xml.StartElement{Name: xml.Name{Space: NS, Local: "forwarded"}},
	)
}

// TokenReader implements xmlstream.Marshaler.
func (f Forwarded) TokenReader() xml.TokenReader {
	return f.Wrap(nil)
}

// WriteXML implements xmlstream.WriterTo.
func (f Forwarded) WriteXML(w xmlstream.TokenWriter) (int, error) {
	return xmlstream.Copy(w, f.TokenReader())
}

// Wrap forwards the provided token stream by wrapping it in a new message
// stanza and recording the original delivery time of the stanza.
// The body is in addition to the forwarded stanza and is not meant as a
// fallback in case the forwarded message cannot be displayed.
//
// The token stream is expected to be a stanza, but this is not enforced.
func Wrap(msg stanza.Message, body string, received time.Time, r xml.TokenReader) xml.TokenReader {
	return msg.Wrap(xmlstream.MultiReader(
		xmlstream.Wrap(xmlstream.Token(xml.CharData(body)), xml.StartElement{Name: xml.Name{Local: "body"}}),
		Forwarded{
			Delay: delay.Delay{
				Time: received,
			},
		}.Wrap(r),
	))
}

A forward/forward_test.go => forward/forward_test.go +56 -0
@@ 0,0 1,56 @@
// Copyright 2021 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.

package forward_test

import (
	"encoding/xml"
	"strings"
	"testing"
	"time"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/forward"
	"mellium.im/xmpp/stanza"
)

func TestWrap(t *testing.T) {
	r := forward.Wrap(stanza.Message{
		Type: stanza.NormalMessage,
	}, "foo", time.Time{},
		xmlstream.Wrap(nil, xml.StartElement{Name: xml.Name{Local: "foo"}}),
	)
	var buf strings.Builder
	e := xml.NewEncoder(&buf)
	_, err := xmlstream.Copy(e, r)
	if err != nil {
		t.Fatalf("error encoding: %v", err)
	}
	err = e.Flush()
	if err != nil {
		t.Fatalf("error flushing: %v", err)
	}
	const expected = `<message type="normal"><body>foo</body><forwarded xmlns="urn:xmpp:forward:0"><delay xmlns="urn:xmpp:delay" stamp="0001-01-01T00:00:00Z"></delay><foo></foo></forwarded></message>`
	if out := buf.String(); out != expected {
		t.Fatalf("wrong output:\nwant=%s,\n got=%s", expected, out)
	}
}

func TestMarshal(t *testing.T) {
	f := forward.Forwarded{}
	var buf strings.Builder
	e := xml.NewEncoder(&buf)
	_, err := f.WriteXML(e)
	if err != nil {
		t.Fatalf("error encoding: %v", err)
	}
	err = e.Flush()
	if err != nil {
		t.Fatalf("error flushing: %v", err)
	}
	const expected = `<forwarded xmlns="urn:xmpp:forward:0"><delay xmlns="urn:xmpp:delay" stamp="0001-01-01T00:00:00Z"></delay></forwarded>`
	if out := buf.String(); out != expected {
		t.Fatalf("wrong output:\nwant=%s,\n got=%s", expected, out)
	}
}

M go.mod => go.mod +1 -1
@@ 9,5 9,5 @@ require (
	golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061
	golang.org/x/text v0.3.2
	mellium.im/sasl v0.2.1
	mellium.im/xmlstream v0.15.3-0.20210217040345-cc2ffc655204
	mellium.im/xmlstream v0.15.3-0.20210221202126-7cc1407dad4c
)

M go.sum => go.sum +2 -2
@@ 19,5 19,5 @@ mellium.im/reader v0.1.0 h1:UUEMev16gdvaxxZC7fC08j7IzuDKh310nB6BlwnxTww=
mellium.im/reader v0.1.0/go.mod h1:F+X5HXpkIfJ9EE1zHQG9lM/hO946iYAmU7xjg5dsQHI=
mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w=
mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ=
mellium.im/xmlstream v0.15.3-0.20210217040345-cc2ffc655204 h1:T/ggGyWYtK8D6BrzyqV6bGRLE1n74ckvQU8laOlPChE=
mellium.im/xmlstream v0.15.3-0.20210217040345-cc2ffc655204/go.mod h1:7SUlP7f2qnMczK+Cu/OFgqaIhldMolVjo8np7xG41D0=
mellium.im/xmlstream v0.15.3-0.20210221202126-7cc1407dad4c h1:1RCzOXu94kvNjuCC89G+5XTP6GOdoDrLsYdGIryyc2Y=
mellium.im/xmlstream v0.15.3-0.20210221202126-7cc1407dad4c/go.mod h1:7SUlP7f2qnMczK+Cu/OFgqaIhldMolVjo8np7xG41D0=