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") { + t.Errorf("Send() output missing body element.\nGot: %s", output) + } +}