28 |
31 |
29 // DNS SRV names |
32 // DNS SRV names |
30 serverSrv = "xmpp-server" |
33 serverSrv = "xmpp-server" |
31 clientSrv = "xmpp-client" |
34 clientSrv = "xmpp-client" |
32 |
35 |
|
36 // TODO Make this a parameter to NewClient, not a |
|
37 // constant. We should have both a log level and a |
|
38 // syslog.Writer, so the app can control how much time we |
|
39 // spend generating log messages, as well as where they go. |
33 debug = true |
40 debug = true |
34 ) |
41 ) |
35 |
42 |
36 // The client in a client-server XMPP connection. |
43 // The client in a client-server XMPP connection. |
37 type Client struct { |
44 type Client struct { |
|
45 // This client's JID. This will be updated asynchronously when |
|
46 // resource binding completes; at that time an iq stanza will |
|
47 // be published on the In channel: |
|
48 // <iq><bind><jid>jid</jid></bind></iq> |
38 Jid JID |
49 Jid JID |
39 password string |
50 password string |
40 socket net.Conn |
51 socket net.Conn |
41 socketSync sync.WaitGroup |
52 socketSync sync.WaitGroup |
42 saslExpected string |
53 saslExpected string |
43 authDone bool |
54 authDone bool |
44 idMutex sync.Mutex |
55 idMutex sync.Mutex |
45 nextId int64 |
56 nextId int64 |
46 handlers chan *stanzaHandler |
57 handlers chan *stanzaHandler |
|
58 // Incoming XMPP stanzas from the server will be published on |
|
59 // this channel. Information which is only used by this |
|
60 // library to set up the XMPP stream will not appear here. |
|
61 // TODO Make these channels of type Stanza. |
47 In <-chan interface{} |
62 In <-chan interface{} |
|
63 // Outgoing XMPP stanzas to the server should be sent to this |
|
64 // channel. |
48 Out chan<- interface{} |
65 Out chan<- interface{} |
49 xmlOut chan<- interface{} |
66 xmlOut chan<- interface{} |
|
67 // TODO Remove this. Make a Stanza parser method available for |
|
68 // use by interact.go and similar applications. |
50 TextOut chan<- *string |
69 TextOut chan<- *string |
51 } |
70 } |
52 var _ io.Closer = &Client{} |
71 var _ io.Closer = &Client{} |
53 |
72 |
54 // Connect to the appropriate server and authenticate as the given JID |
73 // Connect to the appropriate server and authenticate as the given JID |
55 // with the given password. |
74 // with the given password. This function will return as soon as a TCP |
|
75 // connection has been established, but before XMPP stream negotiation |
|
76 // has completed. The negotiation will occur asynchronously, and sends |
|
77 // to Client.Out will block until negotiation is complete. |
56 func NewClient(jid *JID, password string) (*Client, os.Error) { |
78 func NewClient(jid *JID, password string) (*Client, os.Error) { |
57 // Resolve the domain in the JID. |
79 // Resolve the domain in the JID. |
58 _, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain) |
80 _, srvs, err := net.LookupSRV(clientSrv, "tcp", jid.Domain) |
59 if err != nil { |
81 if err != nil { |
60 return nil, os.NewError("LookupSrv " + jid.Domain + |
82 return nil, os.NewError("LookupSrv " + jid.Domain + |