forked from jshiffer/go-xmpp
Add support for XEP-0478: Stream Limits Advertisement.
This commit is contained in:
parent
bbd90cc04b
commit
07196efcf3
62
xmpp.go
62
xmpp.go
@ -53,6 +53,7 @@ const (
|
||||
nsSASLCB = "urn:xmpp:sasl-cb:0"
|
||||
nsClient = "jabber:client"
|
||||
nsSession = "urn:ietf:params:xml:ns:xmpp-session"
|
||||
nsStreamLimits = "urn:xmpp:stream-limits:0"
|
||||
)
|
||||
|
||||
// Default TLS configuration options
|
||||
@ -80,6 +81,8 @@ type Client struct {
|
||||
nextMutex sync.Mutex // Mutex to prevent multiple access to xml.Decoder
|
||||
p *xml.Decoder
|
||||
stanzaWriter io.Writer
|
||||
LimitMaxBytes int // Maximum stanza size (XEP-0478: Stream Limits Advertisement)
|
||||
LimitIdleSeconds int // Maximum idle seconds (XEP-0478: Stream Limits Advertisement)
|
||||
Mechanism string
|
||||
}
|
||||
|
||||
@ -392,6 +395,20 @@ func (c *Client) init(o *Options) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make the max. stanza size limit available.
|
||||
if f.Limits.MaxBytes != "" {
|
||||
c.LimitMaxBytes, err = strconv.Atoi(f.Limits.MaxBytes)
|
||||
if err != nil {
|
||||
c.LimitMaxBytes = 0
|
||||
}
|
||||
}
|
||||
// Make the servers time limit after which it might consider the stream idle available.
|
||||
if f.Limits.IdleSeconds != "" {
|
||||
c.LimitIdleSeconds, err = strconv.Atoi(f.Limits.IdleSeconds)
|
||||
if err != nil {
|
||||
c.LimitIdleSeconds = 0
|
||||
}
|
||||
}
|
||||
|
||||
// If the server requires we STARTTLS, attempt to do so.
|
||||
if f, err = c.startTLSIfRequired(f, o, domain); err != nil {
|
||||
@ -1179,11 +1196,14 @@ func (c *Client) Send(chat Chat) (n int, err error) {
|
||||
oobtext += `</x>`
|
||||
}
|
||||
|
||||
stanza := "<message to='%s' type='%s' id='%s' xml:lang='en'>" + subtext + "<body>%s</body>" + oobtext + thdtext + "</message>\n"
|
||||
|
||||
chat.Text = validUTF8(chat.Text)
|
||||
return fmt.Fprintf(c.stanzaWriter, stanza,
|
||||
stanza := fmt.Sprintf("<message to='%s' type='%s' id='%s' xml:lang='en'>"+subtext+"<body>%s</body>"+oobtext+thdtext+"</message>\n",
|
||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), cnonce(), xmlEscape(chat.Text))
|
||||
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
|
||||
return 0, errors.New("max. stanza size exceeded")
|
||||
}
|
||||
|
||||
return fmt.Fprint(c.stanzaWriter, stanza)
|
||||
}
|
||||
|
||||
// SendOOB sends OOB data wrapped inside an XMPP message stanza, without actual body.
|
||||
@ -1199,13 +1219,21 @@ func (c *Client) SendOOB(chat Chat) (n int, err error) {
|
||||
}
|
||||
oobtext += `</x>`
|
||||
}
|
||||
return fmt.Fprintf(c.stanzaWriter, "<message to='%s' type='%s' id='%s' xml:lang='en'>"+oobtext+thdtext+"</message>\n",
|
||||
stanza := fmt.Sprintf("<message to='%s' type='%s' id='%s' xml:lang='en'>"+oobtext+thdtext+"</message>\n",
|
||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), cnonce())
|
||||
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
|
||||
return 0, errors.New("max. stanza size exceeded")
|
||||
}
|
||||
return fmt.Fprint(c.stanzaWriter, stanza)
|
||||
}
|
||||
|
||||
// SendOrg sends the original text without being wrapped in an XMPP message stanza.
|
||||
func (c *Client) SendOrg(org string) (n int, err error) {
|
||||
return fmt.Fprint(c.stanzaWriter, org+"\n")
|
||||
stanza := fmt.Sprint(org + "\n")
|
||||
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
|
||||
return 0, errors.New("max. stanza size exceeded")
|
||||
}
|
||||
return fmt.Fprint(c.stanzaWriter, stanza)
|
||||
}
|
||||
|
||||
// SendPresence sends Presence wrapped inside XMPP presence stanza.
|
||||
@ -1249,9 +1277,11 @@ func (c *Client) SendPresence(presence Presence) (n int, err error) {
|
||||
buf = buf + fmt.Sprintf("<status>%s</status>", xmlEscape(presence.Status))
|
||||
}
|
||||
|
||||
buf = buf + "</presence>"
|
||||
|
||||
return fmt.Fprint(c.stanzaWriter, buf)
|
||||
stanza := fmt.Sprintf(buf + "</presence>")
|
||||
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
|
||||
return 0, errors.New("max. stanza size exceeded")
|
||||
}
|
||||
return fmt.Fprint(c.stanzaWriter, stanza)
|
||||
}
|
||||
|
||||
// SendKeepAlive sends a "whitespace keepalive" as described in chapter 4.6.1 of RFC6120.
|
||||
@ -1261,10 +1291,13 @@ func (c *Client) SendKeepAlive() (n int, err error) {
|
||||
|
||||
// SendHtml sends the message as HTML as defined by XEP-0071
|
||||
func (c *Client) SendHtml(chat Chat) (n int, err error) {
|
||||
return fmt.Fprintf(c.stanzaWriter, "<message to='%s' type='%s' xml:lang='en'>"+
|
||||
"<body>%s</body>"+
|
||||
stanza := fmt.Sprintf("<message to='%s' type='%s' xml:lang='en'><body>%s</body>"+
|
||||
"<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html></message>\n",
|
||||
xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text), chat.Text)
|
||||
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
|
||||
return 0, errors.New("max. stanza size exceeded")
|
||||
}
|
||||
return fmt.Fprint(c.stanzaWriter, stanza)
|
||||
}
|
||||
|
||||
// Roster asks for the chat roster.
|
||||
@ -1281,6 +1314,7 @@ type streamFeatures struct {
|
||||
ChannelBindings saslChannelBindings
|
||||
Bind bindBind
|
||||
Session bool
|
||||
Limits streamLimits
|
||||
}
|
||||
|
||||
type streamError struct {
|
||||
@ -1343,6 +1377,14 @@ type saslChallenge struct {
|
||||
Text string `xml:",chardata"`
|
||||
}
|
||||
|
||||
type streamLimits struct {
|
||||
XMLName xml.Name `xml:"limits"`
|
||||
Text string `xml:",chardata"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
MaxBytes string `xml:"max-bytes"`
|
||||
IdleSeconds string `xml:"idle-seconds"`
|
||||
}
|
||||
|
||||
// RFC 3920 C.5 Resource binding name space
|
||||
type bindBind struct {
|
||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
|
||||
|
Loading…
Reference in New Issue
Block a user