diff --git a/xmpp.go b/xmpp.go
index 6998f732..cefbd53f 100644
--- a/xmpp.go
+++ b/xmpp.go
@@ -30,7 +30,6 @@ import (
"fmt"
"hash"
"io"
- "log"
"math/big"
"net"
"net/http"
@@ -95,11 +94,7 @@ func getCookie() Cookie {
func getUUID() string {
// Use github.com/google/uuid as XEP-0359 requires an UUID according to
// RFC 4122.
- id, err := uuid.NewV7()
- if err != nil {
- log.Fatal(err)
- }
- return id.String()
+ return uuid.Must(uuid.NewV7()).String()
}
// Fast holds the XEP-0484 fast token, mechanism and expiry date
@@ -1451,6 +1446,7 @@ func (c *Client) IsEncrypted() bool {
// Chat is an incoming or outgoing XMPP chat message.
type Chat struct {
+ ID string // if unset, will be generated on send
Remote string
Type string
Text string
@@ -1462,10 +1458,11 @@ type Chat struct {
Ooburl string
Oobdesc string
Lang string
- // Only for incoming messages, ID for outgoing messages will be generated.
- OriginID string
- // Only for incoming messages, ID for outgoing messages will be generated.
- StanzaID StanzaID
+ // XEP-0359
+ StanzaID StanzaID // only for incoming messages
+ OriginID string // if unset, will be generated on send
+ // XEP-0461
+ Reply *Reply
Roster Roster
Other []string
OtherElem []XMLElement
@@ -1550,6 +1547,7 @@ func (c *Client) Recv() (stanza interface{}, err error) {
v.Delay.Stamp,
)
chat := Chat{
+ ID: v.ID,
Remote: v.From,
Type: v.Type,
Text: v.Body,
@@ -1561,6 +1559,7 @@ func (c *Client) Recv() (stanza interface{}, err error) {
Lang: v.Lang,
OriginID: v.OriginID.ID,
StanzaID: v.StanzaID,
+ Reply: v.Reply,
Oob: v.Oob,
}
return chat, nil
@@ -1852,12 +1851,28 @@ func (c *Client) Send(chat Chat) (n int, err error) {
oobtext += ``
}
+ var replytext string
+ if chat.Reply != nil {
+ replytext = ``
+ }
+
chat.Text = validUTF8(chat.Text)
- id := getUUID()
+
+ if chat.OriginID == "" {
+ chat.OriginID = getUUID()
+ }
+ if chat.ID == "" {
+ chat.ID = chat.OriginID
+ }
+
stanza := fmt.Sprintf("%s%s"+
- "%s%s\n",
- xmlEscape(chat.Remote), xmlEscape(chat.Type), id, subtext, xmlEscape(chat.Text),
- XMPPNS_SID_0, id, oobtext, thdtext)
+ "%s%s%s\n",
+ xmlEscape(chat.Remote), xmlEscape(chat.Type), chat.ID, subtext, xmlEscape(chat.Text),
+ replytext, XMPPNS_SID_0, chat.OriginID, oobtext, thdtext)
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
return 0, fmt.Errorf("stanza size (%v bytes) exceeds server limit (%v bytes)",
len(stanza), c.LimitMaxBytes)
@@ -2166,6 +2181,13 @@ type StanzaID struct {
By string `xml:"by,attr"`
}
+// XEP-0461 Message Replies
+type Reply struct {
+ XMLName xml.Name `xml:"urn:xmpp:reply:0 reply"`
+ ID string `xml:"id,attr"`
+ To string `xml:"to,attr"`
+}
+
// RFC 3921 B.1 jabber:client
type clientMessage struct {
XMLName xml.Name `xml:"jabber:client message"`
@@ -2184,6 +2206,9 @@ type clientMessage struct {
OriginID originID `xml:"origin-id"`
StanzaID StanzaID `xml:"stanza-id"`
+ // XEP-0461
+ Reply *Reply `xml:"reply"`
+
// Pubsub
Event clientPubsubEvent `xml:"event"`