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"`