--- a/stream.go Mon Jan 23 21:58:53 2012 -0700
+++ b/stream.go Sun Apr 15 11:20:55 2012 -0600
@@ -19,7 +19,6 @@
"encoding/xml"
"fmt"
"io"
- "log/syslog"
"math/big"
"net"
"regexp"
@@ -52,11 +51,17 @@
func (cl *Client) readTransport(w io.WriteCloser) {
defer w.Close()
- cl.socket.SetReadTimeout(1e8)
+ readDelay, _ := time.ParseDuration("1s")
p := make([]byte, 1024)
for {
if cl.socket == nil {
cl.waitForSocket()
+ readDelay = 0
+ }
+ if readDelay != 0 {
+ readTimeout := time.Now()
+ readTimeout.Add(readDelay)
+ cl.socket.SetReadDeadline(readTimeout)
}
nr, err := cl.socket.Read(p)
if nr == 0 {
@@ -103,14 +108,14 @@
func readXml(r io.Reader, ch chan<- interface{},
extStanza map[string]func(*xml.Name) interface{}) {
- if Loglevel >= syslog.LOG_DEBUG {
+ if Loglevel >= LOG_DEBUG {
pr, pw := io.Pipe()
go tee(r, pw, "S: ")
r = pr
}
defer close(ch)
- p := xml.NewParser(r)
+ p := xml.NewDecoder(r)
Loop:
for {
// Sniff the next token on the stream.
@@ -162,14 +167,14 @@
obj = &Presence{}
default:
obj = &Generic{}
- if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+ if Log != nil && Loglevel >= LOG_NOTICE {
Log.Printf("Ignoring unrecognized: %s %s",
se.Name.Space, se.Name.Local)
}
}
// Read the complete XML stanza.
- err = p.Unmarshal(obj, &se)
+ err = p.DecodeElement(obj, &se)
if err != nil {
if Log != nil {
Log.Println("unmarshal: " + err.Error())
@@ -200,7 +205,7 @@
// Now parse the stanza's innerxml to find the string that we
// can unmarshal this nested element from.
reader := strings.NewReader(st.innerxml())
- p := xml.NewParser(reader)
+ p := xml.NewDecoder(reader)
for {
t, err := p.Token()
if err == io.EOF {
@@ -216,7 +221,7 @@
// Unmarshal the nested element and
// stuff it back into the stanza.
- err := p.Unmarshal(nested, &se)
+ err := p.DecodeElement(nested, &se)
if err != nil {
return err
}
@@ -229,7 +234,7 @@
}
func writeXml(w io.Writer, ch <-chan interface{}) {
- if Loglevel >= syslog.LOG_DEBUG {
+ if Loglevel >= LOG_DEBUG {
pr, pw := io.Pipe()
go tee(pr, w, "C: ")
w = pw
@@ -241,7 +246,7 @@
}(w)
for obj := range ch {
- err := xml.Marshal(w, obj)
+ err := xml.NewEncoder(w).Encode(obj)
if err != nil {
if Log != nil {
Log.Println("write: " + err.Error())
@@ -284,7 +289,7 @@
}
st, ok := x.(Stanza)
if !ok {
- if Log != nil && Loglevel >= syslog.LOG_WARNING {
+ if Log != nil && Loglevel >= LOG_WARNING {
Log.Printf(
"Unhandled non-stanza: %v", x)
}
@@ -328,7 +333,7 @@
break Loop
}
if x == nil {
- if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+ if Log != nil && Loglevel >= LOG_NOTICE {
Log.Println("Refusing to send" +
" nil stanza")
}
@@ -349,7 +354,7 @@
select {
case newFilterOut := <-filterOut:
if newFilterOut == nil {
- if Log != nil && Loglevel >= syslog.LOG_WARNING {
+ if Log != nil && Loglevel >= LOG_WARNING {
Log.Println("Received nil filter")
}
filterIn <- nil
@@ -378,7 +383,7 @@
}
func (cl *Client) handleStreamError(se *streamError) {
- if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+ if Log != nil && Loglevel >= LOG_NOTICE {
Log.Printf("Received stream error: %v", se)
}
close(cl.Out)
@@ -428,11 +433,7 @@
cl.socket = tls
cl.socketSync.Wait()
- // Reset the read timeout on the (underlying) socket so the
- // reader doesn't get woken up unnecessarily.
- tcp.SetReadTimeout(0)
-
- if Log != nil && Loglevel >= syslog.LOG_INFO {
+ if Log != nil && Loglevel >= LOG_INFO {
Log.Println("TLS negotiation succeeded.")
}
cl.Features = nil
@@ -470,8 +471,7 @@
}
if external {
- auth := &auth{XMLName: xml.Name{Space: NsSASL, Local:
- "auth"}, Mechanism: "EXTERNAL"}
+ auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "EXTERNAL"}
cl.xmlOut <- auth
} else if digestMd5 {
auth := &auth{XMLName: xml.Name{Space: NsSASL, Local: "auth"}, Mechanism: "DIGEST-MD5"}
@@ -479,17 +479,15 @@
} else {
if Log != nil {
buf := bytes.NewBuffer(nil)
- xml.Marshal(buf, fe)
+ xml.NewEncoder(buf).Encode(fe)
Log.Printf("No supported mechanisms: %s",
buf.String())
}
abort := Generic{XMLName: xml.Name{Local: "abort",
Space: NsSASL}}
cl.xmlOut <- abort
- se := streamError{Any: Generic{XMLName:
- xml.Name{Local: "undefined-condition",
- Space: NsStreams}}, Text:
- &errText{Lang: "en", Text: "No supported mechs"}}
+ se := streamError{Any: Generic{XMLName: xml.Name{Local: "undefined-condition",
+ Space: NsStreams}}, Text: &errText{Lang: "en", Text: "No supported mechs"}}
cl.xmlOut <- se
close(cl.xmlOut)
}
@@ -515,11 +513,11 @@
cl.saslDigest2(srvMap)
}
case "failure":
- if Log != nil && Loglevel >= syslog.LOG_NOTICE {
+ if Log != nil && Loglevel >= LOG_NOTICE {
Log.Println("SASL authentication failed")
}
case "success":
- if Log != nil && Loglevel >= syslog.LOG_INFO {
+ if Log != nil && Loglevel >= LOG_INFO {
Log.Println("Sasl authentication succeeded")
}
cl.Features = nil
@@ -708,7 +706,7 @@
return false
}
cl.Jid = *jid
- if Log != nil && Loglevel >= syslog.LOG_INFO {
+ if Log != nil && Loglevel >= LOG_INFO {
Log.Println("Bound resource: " + cl.Jid.String())
}
cl.bindDone()
--- a/structs.go Mon Jan 23 21:58:53 2012 -0700
+++ b/structs.go Sun Apr 15 11:20:55 2012 -0600
@@ -31,6 +31,7 @@
// XMPP's <stream:stream> XML element
type stream struct {
+ XMLName xml.Name `xml:"stream stream"`
To string `xml:"to,attr"`
From string `xml:"from,attr"`
Id string `xml:"id,attr"`
@@ -38,30 +39,26 @@
Version string `xml:"version,attr"`
}
-var _ xml.Marshaler = &stream{}
var _ fmt.Stringer = &stream{}
// <stream:error>
type streamError struct {
- Any Generic `xml:",any"`
+ Any Generic `xml:",any"`
Text *errText `xml:"text"`
}
-var _ xml.Marshaler = &streamError{}
-
type errText struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-streams text"`
Lang string `xml:"lang,attr"`
Text string `xml:",chardata"`
}
-var _ xml.Marshaler = &errText{}
-
type Features struct {
Starttls *starttls `xml:"starttls"`
- Mechanisms mechs `xml:"mechanisms"`
- Bind *bindIq `xml:"bind"`
- Session *Generic `xml:"session"`
- Any *Generic `xml:",any"`
+ Mechanisms mechs `xml:"mechanisms"`
+ Bind *bindIq `xml:"bind"`
+ Session *Generic `xml:"session"`
+ Any *Generic `xml:",any"`
}
type starttls struct {
@@ -75,8 +72,8 @@
type auth struct {
XMLName xml.Name
- Chardata string `xml:",chardata"`
- Mechanism string `xml:"mechanism,attr"`
+ Chardata string `xml:",chardata"`
+ Mechanism string `xml:"mechanism,attr"`
Any *Generic `xml:",any"`
}
@@ -106,53 +103,53 @@
// message stanza
type Message struct {
- To string `xml:"to,attr"`
- From string `xml:"from,attr"`
- Id string `xml:"id,attr"`
- Type string `xml:"type,attr"`
- Lang string `xml:"lang,attr"`
- Innerxml string `xml:",innerxml"`
- Error *Error `xml:"error"`
+ XMLName xml.Name `xml:"message"`
+ To string `xml:"to,attr,omitempty"`
+ From string `xml:"from,attr,omitempty"`
+ Id string `xml:"id,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Lang string `xml:"lang,attr,omitempty"`
+ Innerxml string `xml:",innerxml"`
+ Error *Error `xml:"error"`
Subject *Generic `xml:"subject"`
Body *Generic `xml:"body"`
Thread *Generic `xml:"thread"`
Nested []interface{}
}
-var _ xml.Marshaler = &Message{}
var _ Stanza = &Message{}
// presence stanza
type Presence struct {
- To string `xml:"to,attr"`
- From string `xml:"from,attr"`
- Id string `xml:"id,attr"`
- Type string `xml:"type,attr"`
- Lang string `xml:"lang,attr"`
- Innerxml string `xml:",innerxml"`
- Error *Error `xml:"error"`
+ XMLName xml.Name `xml:"presence"`
+ To string `xml:"to,attr,omitempty"`
+ From string `xml:"from,attr,omitempty"`
+ Id string `xml:"id,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Lang string `xml:"lang,attr,omitempty"`
+ Innerxml string `xml:",innerxml"`
+ Error *Error `xml:"error"`
Show *Generic `xml:"show"`
Status *Generic `xml:"status"`
Priority *Generic `xml:"priority"`
Nested []interface{}
}
-var _ xml.Marshaler = &Presence{}
var _ Stanza = &Presence{}
// iq stanza
type Iq struct {
- To string `xml:"to,attr"`
- From string `xml:"from,attr"`
- Id string `xml:"id,attr"`
- Type string `xml:"type,attr"`
- Lang string `xml:"lang,attr"`
+ XMLName xml.Name `xml:"iq"`
+ To string `xml:"to,attr,omitempty"`
+ From string `xml:"from,attr,omitempty"`
+ Id string `xml:"id,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+ Lang string `xml:"xml lang,attr,omitempty"`
Innerxml string `xml:",innerxml"`
Error *Error `xml:"error"`
Nested []interface{}
}
-var _ xml.Marshaler = &Iq{}
var _ Stanza = &Iq{}
// Describes an XMPP stanza error. See RFC 3920, Section 9.3.
@@ -177,7 +174,7 @@
type Generic struct {
XMLName xml.Name
Any *Generic `xml:",any"`
- Chardata string `xml:",chardata"`
+ Chardata string `xml:",chardata"`
}
var _ fmt.Stringer = &Generic{}
@@ -207,24 +204,16 @@
return nil
}
-func (s *stream) MarshalXML() ([]byte, error) {
+func (s *stream) String() string {
buf := bytes.NewBuffer(nil)
buf.WriteString("<stream:stream")
- writeField(buf, "xmlns", "jabber:client")
- writeField(buf, "xmlns:stream", NsStream)
writeField(buf, "to", s.To)
writeField(buf, "from", s.From)
writeField(buf, "id", s.Id)
writeField(buf, "xml:lang", s.Lang)
writeField(buf, "version", s.Version)
buf.WriteString(">")
- // We never write </stream:stream>
- return buf.Bytes(), nil
-}
-
-func (s *stream) String() string {
- result, _ := s.MarshalXML()
- return string(result)
+ return buf.String()
}
func parseStream(se xml.StartElement) (*stream, error) {
@@ -246,28 +235,6 @@
return s, nil
}
-func (s *streamError) MarshalXML() ([]byte, error) {
- buf := bytes.NewBuffer(nil)
- buf.WriteString("<stream:error>")
- xml.Marshal(buf, s.Any)
- if s.Text != nil {
- xml.Marshal(buf, s.Text)
- }
- buf.WriteString("</stream:error>")
- return buf.Bytes(), nil
-}
-
-func (e *errText) MarshalXML() ([]byte, error) {
- buf := bytes.NewBuffer(nil)
- buf.WriteString("<text")
- writeField(buf, "xmlns", NsStreams)
- writeField(buf, "xml:lang", e.Lang)
- buf.WriteString(">")
- xml.Escape(buf, []byte(e.Text))
- buf.WriteString("</text>")
- return buf.Bytes(), nil
-}
-
func writeField(w io.Writer, field, value string) {
if value != "" {
io.WriteString(w, " ")
@@ -291,72 +258,9 @@
u.XMLName.Local)
}
-func marshalXML(st Stanza) ([]byte, error) {
- buf := bytes.NewBuffer(nil)
- buf.WriteString("<")
- buf.WriteString(st.GetName())
- if st.GetTo() != "" {
- writeField(buf, "to", st.GetTo())
- }
- if st.GetFrom() != "" {
- writeField(buf, "from", st.GetFrom())
- }
- if st.GetId() != "" {
- writeField(buf, "id", st.GetId())
- }
- if st.GetType() != "" {
- writeField(buf, "type", st.GetType())
- }
- if st.GetLang() != "" {
- writeField(buf, "xml:lang", st.GetLang())
- }
- buf.WriteString(">")
-
- if m, ok := st.(*Message); ok {
- err := xml.Marshal(buf, m.Subject)
- if err != nil {
- return nil, err
- }
- err = xml.Marshal(buf, m.Body)
- if err != nil {
- return nil, err
- }
- err = xml.Marshal(buf, m.Thread)
- if err != nil {
- return nil, err
- }
- }
- if p, ok := st.(*Presence); ok {
- err := xml.Marshal(buf, p.Show)
- if err != nil {
- return nil, err
- }
- err = xml.Marshal(buf, p.Status)
- if err != nil {
- return nil, err
- }
- err = xml.Marshal(buf, p.Priority)
- if err != nil {
- return nil, err
- }
- }
- if nested := st.GetNested(); nested != nil {
- for _, n := range nested {
- xml.Marshal(buf, n)
- }
- } else if st.innerxml() != "" {
- buf.WriteString(st.innerxml())
- }
-
- buf.WriteString("</")
- buf.WriteString(st.GetName())
- buf.WriteString(">")
- return buf.Bytes(), nil
-}
-
func (er *Error) Error() string {
buf := bytes.NewBuffer(nil)
- xml.Marshal(buf, er)
+ xml.NewEncoder(buf).Encode(er)
return buf.String()
}
@@ -400,10 +304,6 @@
return m.Innerxml
}
-func (m *Message) MarshalXML() ([]byte, error) {
- return marshalXML(m)
-}
-
func (p *Presence) GetName() string {
return "presence"
}
@@ -444,10 +344,6 @@
return p.Innerxml
}
-func (p *Presence) MarshalXML() ([]byte, error) {
- return marshalXML(p)
-}
-
func (iq *Iq) GetName() string {
return "iq"
}
@@ -488,15 +384,11 @@
return iq.Innerxml
}
-func (iq *Iq) MarshalXML() ([]byte, error) {
- return marshalXML(iq)
-}
-
// Parse a string into a struct implementing Stanza -- this will be
// either an Iq, a Message, or a Presence.
func ParseStanza(str string) (Stanza, error) {
r := strings.NewReader(str)
- p := xml.NewParser(r)
+ p := xml.NewDecoder(r)
tok, err := p.Token()
if err != nil {
return nil, err
@@ -516,7 +408,7 @@
default:
return nil, errors.New("Not iq, message, or presence")
}
- err = p.Unmarshal(stan, &se)
+ err = p.DecodeElement(stan, &se)
if err != nil {
return nil, err
}