xmpp.go
changeset 74 e619e18dcec3
parent 72 53f15893a1a7
child 76 caa722ab8a0f
equal deleted inserted replaced
73:acca351fb8f0 74:e619e18dcec3
     6 // and 3921, plus the various XEPs at http://xmpp.org/protocols/.
     6 // and 3921, plus the various XEPs at http://xmpp.org/protocols/.
     7 package xmpp
     7 package xmpp
     8 
     8 
     9 import (
     9 import (
    10 	"bytes"
    10 	"bytes"
       
    11 	"encoding/xml"
       
    12 	"errors"
    11 	"fmt"
    13 	"fmt"
    12 	"io"
    14 	"io"
       
    15 	"log/syslog"
    13 	"net"
    16 	"net"
    14 	"os"
       
    15 	"sync"
    17 	"sync"
    16 	"syslog"
       
    17 	"xml"
       
    18 )
    18 )
    19 
    19 
    20 const (
    20 const (
    21 	// Version of RFC 3920 that we implement.
    21 	// Version of RFC 3920 that we implement.
    22 	Version = "1.0"
    22 	Version = "1.0"
   105 // connection has been established, but before XMPP stream negotiation
   105 // connection has been established, but before XMPP stream negotiation
   106 // has completed. The negotiation will occur asynchronously, and any
   106 // has completed. The negotiation will occur asynchronously, and any
   107 // send operation to Client.Out will block until negotiation (resource
   107 // send operation to Client.Out will block until negotiation (resource
   108 // binding) is complete.
   108 // binding) is complete.
   109 func NewClient(jid *JID, password string, exts []Extension) (*Client,
   109 func NewClient(jid *JID, password string, exts []Extension) (*Client,
   110 os.Error) {
   110 	error) {
   111 	// Include the mandatory extensions.
   111 	// Include the mandatory extensions.
   112 	exts = append(exts, rosterExt)
   112 	exts = append(exts, rosterExt)
   113 	exts = append(exts, bindExt)
   113 	exts = append(exts, bindExt)
   114 
   114 
   115 	// Resolve the domain in the JID.
   115 	// Resolve the domain in the JID.
   116 	_, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain)
   116 	_, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain)
   117 	if err != nil {
   117 	if err != nil {
   118 		return nil, os.NewError("LookupSrv " + jid.Domain +
   118 		return nil, errors.New("LookupSrv " + jid.Domain +
   119 			": " + err.String())
   119 			": " + err.Error())
   120 	}
   120 	}
   121 
   121 
   122 	var tcp *net.TCPConn
   122 	var tcp *net.TCPConn
   123 	for _, srv := range srvs {
   123 	for _, srv := range srvs {
   124 		addrStr := fmt.Sprintf("%s:%d", srv.Target, srv.Port)
   124 		addrStr := fmt.Sprintf("%s:%d", srv.Target, srv.Port)
   125 		addr, err := net.ResolveTCPAddr("tcp", addrStr)
   125 		addr, err := net.ResolveTCPAddr("tcp", addrStr)
   126 		if err != nil {
   126 		if err != nil {
   127 			err = os.NewError(fmt.Sprintf("ResolveTCPAddr(%s): %s",
   127 			err = errors.New(fmt.Sprintf("ResolveTCPAddr(%s): %s",
   128 				addrStr, err.String()))
   128 				addrStr, err.Error()))
   129 			continue
   129 			continue
   130 		}
   130 		}
   131 		tcp, err = net.DialTCP("tcp", nil, addr)
   131 		tcp, err = net.DialTCP("tcp", nil, addr)
   132 		if err != nil {
   132 		if err != nil {
   133 			err = os.NewError(fmt.Sprintf("DialTCP(%s): %s",
   133 			err = errors.New(fmt.Sprintf("DialTCP(%s): %s",
   134 				addr, err.String()))
   134 				addr, err.Error()))
   135 			continue
   135 			continue
   136 		}
   136 		}
   137 	}
   137 	}
   138 	if tcp == nil {
   138 	if tcp == nil {
   139 		return nil, err
   139 		return nil, err
   191 	go cl.writeTransport(outr)
   191 	go cl.writeTransport(outr)
   192 	return inr, outw
   192 	return inr, outw
   193 }
   193 }
   194 
   194 
   195 func startXmlReader(r io.Reader,
   195 func startXmlReader(r io.Reader,
   196 extStanza map[string]func(*xml.Name) interface{}) <-chan interface{} {
   196 	extStanza map[string]func(*xml.Name) interface{}) <-chan interface{} {
   197 	ch := make(chan interface{})
   197 	ch := make(chan interface{})
   198 	go readXml(r, ch, extStanza)
   198 	go readXml(r, ch, extStanza)
   199 	return ch
   199 	return ch
   200 }
   200 }
   201 
   201 
   269 // Start an XMPP session. A typical XMPP client should call this
   269 // Start an XMPP session. A typical XMPP client should call this
   270 // immediately after creating the Client in order to start the
   270 // immediately after creating the Client in order to start the
   271 // session, retrieve the roster, and broadcast an initial
   271 // session, retrieve the roster, and broadcast an initial
   272 // presence. The presence can be as simple as a newly-initialized
   272 // presence. The presence can be as simple as a newly-initialized
   273 // Presence struct.  See RFC 3921, Section 3.
   273 // Presence struct.  See RFC 3921, Section 3.
   274 func (cl *Client) StartSession(getRoster bool, pr *Presence) os.Error {
   274 func (cl *Client) StartSession(getRoster bool, pr *Presence) error {
   275 	id := <-Id
   275 	id := <-Id
   276 	iq := &Iq{To: cl.Jid.Domain, Id: id, Type: "set", Nested: []interface{}{Generic{XMLName: xml.Name{Space: NsSession, Local: "session"}}}}
   276 	iq := &Iq{To: cl.Jid.Domain, Id: id, Type: "set", Nested: []interface{}{Generic{XMLName: xml.Name{Space: NsSession, Local: "session"}}}}
   277 	ch := make(chan os.Error)
   277 	ch := make(chan error)
   278 	f := func(st Stanza) bool {
   278 	f := func(st Stanza) bool {
   279 		if st.GetType() == "error" {
   279 		if st.GetType() == "error" {
   280 			if Log != nil {
   280 			if Log != nil {
   281 				Log.Err(fmt.Sprintf("Can't start session: %v",
   281 				Log.Err(fmt.Sprintf("Can't start session: %v",
   282 					st))
   282 					st))