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)) |