forked from jshiffer/go-xmpp
Add support for XEP-0478: Stream Limits Advertisement.
This commit is contained in:
parent
bbd90cc04b
commit
07196efcf3
90
xmpp.go
90
xmpp.go
@ -46,13 +46,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nsStream = "http://etherx.jabber.org/streams"
|
nsStream = "http://etherx.jabber.org/streams"
|
||||||
nsTLS = "urn:ietf:params:xml:ns:xmpp-tls"
|
nsTLS = "urn:ietf:params:xml:ns:xmpp-tls"
|
||||||
nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
|
nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
|
||||||
nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
|
nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
|
||||||
nsSASLCB = "urn:xmpp:sasl-cb:0"
|
nsSASLCB = "urn:xmpp:sasl-cb:0"
|
||||||
nsClient = "jabber:client"
|
nsClient = "jabber:client"
|
||||||
nsSession = "urn:ietf:params:xml:ns:xmpp-session"
|
nsSession = "urn:ietf:params:xml:ns:xmpp-session"
|
||||||
|
nsStreamLimits = "urn:xmpp:stream-limits:0"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default TLS configuration options
|
// Default TLS configuration options
|
||||||
@ -74,13 +75,15 @@ func getCookie() Cookie {
|
|||||||
|
|
||||||
// Client holds XMPP connection options
|
// Client holds XMPP connection options
|
||||||
type Client struct {
|
type Client struct {
|
||||||
conn net.Conn // connection to server
|
conn net.Conn // connection to server
|
||||||
jid string // Jabber ID for our connection
|
jid string // Jabber ID for our connection
|
||||||
domain string
|
domain string
|
||||||
nextMutex sync.Mutex // Mutex to prevent multiple access to xml.Decoder
|
nextMutex sync.Mutex // Mutex to prevent multiple access to xml.Decoder
|
||||||
p *xml.Decoder
|
p *xml.Decoder
|
||||||
stanzaWriter io.Writer
|
stanzaWriter io.Writer
|
||||||
Mechanism string
|
LimitMaxBytes int // Maximum stanza size (XEP-0478: Stream Limits Advertisement)
|
||||||
|
LimitIdleSeconds int // Maximum idle seconds (XEP-0478: Stream Limits Advertisement)
|
||||||
|
Mechanism string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) JID() string {
|
func (c *Client) JID() string {
|
||||||
@ -392,6 +395,20 @@ func (c *Client) init(o *Options) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 the server requires we STARTTLS, attempt to do so.
|
||||||
if f, err = c.startTLSIfRequired(f, o, domain); err != nil {
|
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>`
|
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)
|
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))
|
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.
|
// 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>`
|
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())
|
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.
|
// SendOrg sends the original text without being wrapped in an XMPP message stanza.
|
||||||
func (c *Client) SendOrg(org string) (n int, err error) {
|
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.
|
// 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 + fmt.Sprintf("<status>%s</status>", xmlEscape(presence.Status))
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = buf + "</presence>"
|
stanza := fmt.Sprintf(buf + "</presence>")
|
||||||
|
if c.LimitMaxBytes != 0 && len(stanza) > c.LimitMaxBytes {
|
||||||
return fmt.Fprint(c.stanzaWriter, buf)
|
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.
|
// 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
|
// SendHtml sends the message as HTML as defined by XEP-0071
|
||||||
func (c *Client) SendHtml(chat Chat) (n int, err error) {
|
func (c *Client) SendHtml(chat Chat) (n int, err error) {
|
||||||
return fmt.Fprintf(c.stanzaWriter, "<message to='%s' type='%s' xml:lang='en'>"+
|
stanza := fmt.Sprintf("<message to='%s' type='%s' xml:lang='en'><body>%s</body>"+
|
||||||
"<body>%s</body>"+
|
|
||||||
"<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html></message>\n",
|
"<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)
|
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.
|
// Roster asks for the chat roster.
|
||||||
@ -1281,6 +1314,7 @@ type streamFeatures struct {
|
|||||||
ChannelBindings saslChannelBindings
|
ChannelBindings saslChannelBindings
|
||||||
Bind bindBind
|
Bind bindBind
|
||||||
Session bool
|
Session bool
|
||||||
|
Limits streamLimits
|
||||||
}
|
}
|
||||||
|
|
||||||
type streamError struct {
|
type streamError struct {
|
||||||
@ -1343,6 +1377,14 @@ type saslChallenge struct {
|
|||||||
Text string `xml:",chardata"`
|
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
|
// RFC 3920 C.5 Resource binding name space
|
||||||
type bindBind struct {
|
type bindBind struct {
|
||||||
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
|
||||||
|
Loading…
Reference in New Issue
Block a user