diff --git a/xmpp.go b/xmpp.go
index 30a7ff74..eeb3503c 100644
--- a/xmpp.go
+++ b/xmpp.go
@@ -609,6 +609,10 @@ type Chat struct {
Oobdesc string
ID string
ReplaceID string
+ ReplyID string // XEP-0461: id of the message being replied to (use stanza-id for groupchat)
+ ReplyTo string // XEP-0461: JID of the author of the message being replied to
+ StanzaID string // XEP-0359: refers to stanza-id but named Stanza for brevity
+ StanzaBy string // XEP-0359: refers to stanza-id but named Stanza for brevity
Roster Roster
Other []string
OtherElem []XMLElement
@@ -684,6 +688,10 @@ func (c *Client) Recv() (stanza interface{}, err error) {
Thread: v.Thread,
ID: v.ID,
ReplaceID: v.ReplaceID.ID,
+ ReplyID: v.Reply.ID,
+ ReplyTo: v.Reply.To,
+ StanzaID: v.StanzaID.ID,
+ StanzaBy: v.StanzaID.By,
Other: v.OtherStrings(),
OtherElem: v.Other,
Stamp: stamp,
@@ -892,7 +900,16 @@ func (c *Client) Send(chat Chat) (n int, err error) {
msgcorrecttext = ``
}
- stanza := "" + subtext + "%s" + msgcorrecttext + oobtext + thdtext + ""
+ var replytext string
+ if chat.ReplyID != `` {
+ replytext = ``
+ }
+
+ stanza := "" + subtext + "%s" + replytext + msgcorrecttext + oobtext + thdtext + ""
return fmt.Fprintf(c.conn, stanza, xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
}
@@ -1014,6 +1031,18 @@ type clientMessageCorrect struct {
ID string `xml:"id,attr"`
}
+type clientReply struct {
+ XMLName xml.Name `xml:"urn:xmpp:reply:0 reply"`
+ ID string `xml:"id,attr"`
+ To string `xml:"to,attr"`
+}
+
+type clientStanzaID struct {
+ XMLName xml.Name `xml:"urn:xmpp:sid:0 stanza-id"`
+ ID string `xml:"id,attr"`
+ By string `xml:"by,attr"`
+}
+
// RFC 3921 B.1 jabber:client
type clientMessage struct {
XMLName xml.Name `xml:"jabber:client message"`
@@ -1027,6 +1056,8 @@ type clientMessage struct {
Body string `xml:"body"`
Thread string `xml:"thread"`
ReplaceID clientMessageCorrect
+ Reply clientReply
+ StanzaID clientStanzaID
// Pubsub
Event clientPubsubEvent `xml:"event"`
diff --git a/xmpp_test.go b/xmpp_test.go
index 2966d98e..b5f7420a 100644
--- a/xmpp_test.go
+++ b/xmpp_test.go
@@ -56,7 +56,7 @@ func (*testConn) SetWriteDeadline(time.Time) error {
}
var text = strings.TrimSpace(`
-
+
{"random": "<text>"}
@@ -122,12 +122,13 @@ var emptyPubSub = strings.TrimSpace(`
`)
+
func TestEmptyPubsub(t *testing.T) {
var c Client
c.conn = tConnect(emptyPubSub)
c.p = xml.NewDecoder(c.conn)
m, err := c.Recv()
-
+
switch m.(type) {
case AvatarData:
if err == nil {
@@ -138,3 +139,74 @@ func TestEmptyPubsub(t *testing.T) {
t.Errorf("Expected a return value of AvatarData")
}
}
+
+func TestSendReply(t *testing.T) {
+ var c Client
+ buf := &bytes.Buffer{}
+ c.conn = &testConn{buf}
+
+ chat := Chat{
+ Remote: "room@conference.example.com",
+ Type: "groupchat",
+ Text: "This is a reply",
+ ID: "msg-123",
+ ReplyTo: "original-msg-456",
+ ReplyID: "reply-id-789",
+ }
+
+ _, err := c.Send(chat)
+ if err != nil {
+ t.Fatalf("Send() returned error: %v", err)
+ }
+
+ output := buf.String()
+
+ // Check that the reply element is present with correct namespace
+ expectedReply := ``
+ if !strings.Contains(output, expectedReply) {
+ t.Errorf("Send() output missing XEP-0461 reply element.\nGot: %s\nExpected to contain: %s", output, expectedReply)
+ }
+
+ // Check that the body is present
+ if !strings.Contains(output, "This is a reply") {
+ t.Errorf("Send() output missing body element.\nGot: %s", output)
+ }
+
+ // Check message attributes
+ if !strings.Contains(output, "to='room@conference.example.com'") {
+ t.Errorf("Send() output missing 'to' attribute.\nGot: %s", output)
+ }
+ if !strings.Contains(output, "type='groupchat'") {
+ t.Errorf("Send() output missing 'type' attribute.\nGot: %s", output)
+ }
+}
+
+func TestSendWithoutReply(t *testing.T) {
+ var c Client
+ buf := &bytes.Buffer{}
+ c.conn = &testConn{buf}
+
+ chat := Chat{
+ Remote: "room@conference.example.com",
+ Type: "groupchat",
+ Text: "Regular message",
+ ID: "msg-789",
+ }
+
+ _, err := c.Send(chat)
+ if err != nil {
+ t.Fatalf("Send() returned error: %v", err)
+ }
+
+ output := buf.String()
+
+ // Check that no reply element is present when ReplyTo is empty
+ if strings.Contains(output, "Regular message