Merge pull request #30 from ir4y/master

Ejabberd compatibility
This commit is contained in:
mattn 2014-04-23 02:27:39 +09:00
commit 9276abaad9
2 changed files with 43 additions and 13 deletions

View File

@ -15,6 +15,7 @@ var username = flag.String("username", "", "username")
var password = flag.String("password", "", "password") var password = flag.String("password", "", "password")
var notls = flag.Bool("notls", false, "No TLS") var notls = flag.Bool("notls", false, "No TLS")
var debug = flag.Bool("debug", false, "debug output") var debug = flag.Bool("debug", false, "debug output")
var session = flag.Bool("session", false, "use server session")
func main() { func main() {
flag.Usage = func() { flag.Usage = func() {
@ -29,11 +30,15 @@ func main() {
var talk *xmpp.Client var talk *xmpp.Client
var err error var err error
if *notls { options := xmpp.Options{Host: *server,
talk, err = xmpp.NewClientNoTLS(*server, *username, *password, *debug) User: *username,
} else { Password: *password,
talk, err = xmpp.NewClient(*server, *username, *password, *debug) NoTLS: *notls,
} Debug: *debug,
Session: *session}
talk, err = options.NewClient()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

41
xmpp.go
View File

@ -19,6 +19,7 @@ import (
"crypto/rand" "crypto/rand"
"crypto/tls" "crypto/tls"
"encoding/base64" "encoding/base64"
"encoding/binary"
"encoding/xml" "encoding/xml"
"errors" "errors"
"fmt" "fmt"
@ -32,15 +33,26 @@ 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"
nsClient = "jabber:client" nsClient = "jabber:client"
NsSession = "urn:ietf:params:xml:ns:xmpp-session"
) )
var DefaultConfig tls.Config var DefaultConfig tls.Config
type Cookie uint64
func getCookie() Cookie {
var buf [8]byte
if _, err := rand.Reader.Read(buf[:]); err != nil {
panic("Failed to read random bytes: " + err.Error())
}
return Cookie(binary.LittleEndian.Uint64(buf[:]))
}
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
@ -117,6 +129,9 @@ type Options struct {
// Debug output // Debug output
Debug bool Debug bool
//Use server sessions
Session bool
} }
// NewClient establishes a new Client connection based on a set of Options. // NewClient establishes a new Client connection based on a set of Options.
@ -161,6 +176,7 @@ func NewClient(host, user, passwd string, debug bool) (*Client, error) {
User: user, User: user,
Password: passwd, Password: passwd,
Debug: debug, Debug: debug,
Session: false,
} }
return opts.NewClient() return opts.NewClient()
} }
@ -172,6 +188,7 @@ func NewClientNoTLS(host, user, passwd string, debug bool) (*Client, error) {
Password: passwd, Password: passwd,
NoTLS: true, NoTLS: true,
Debug: debug, Debug: debug,
Session: false,
} }
return opts.NewClient() return opts.NewClient()
} }
@ -343,14 +360,17 @@ func (c *Client) init(o *Options) error {
} }
if err = c.p.DecodeElement(&f, nil); err != nil { if err = c.p.DecodeElement(&f, nil); err != nil {
// TODO: often stream stop. // TODO: often stream stop.
//return os.NewError("unmarshal <features>: " + err.String()) //return errors.New("unmarshal <features>: " + err.Error())
} }
//Generate uniq cookie
cookie := getCookie()
// Send IQ message asking to bind to the local user name. // Send IQ message asking to bind to the local user name.
if o.Resource == "" { if o.Resource == "" {
fmt.Fprintf(c.conn, "<iq type='set' id='x'><bind xmlns='%s'></bind></iq>\n", nsBind) fmt.Fprintf(c.conn, "<iq type='set' id='%x'><bind xmlns='%s'></bind></iq>\n", cookie, nsBind)
} else { } else {
fmt.Fprintf(c.conn, "<iq type='set' id='x'><bind xmlns='%s'><resource>%s</resource></bind></iq>\n", nsBind, o.Resource) fmt.Fprintf(c.conn, "<iq type='set' id='%x'><bind xmlns='%s'><resource>%s</resource></bind></iq>\n", cookie, nsBind, o.Resource)
} }
var iq clientIQ var iq clientIQ
if err = c.p.DecodeElement(&iq, nil); err != nil { if err = c.p.DecodeElement(&iq, nil); err != nil {
@ -361,6 +381,11 @@ func (c *Client) init(o *Options) error {
} }
c.jid = iq.Bind.Jid // our local id c.jid = iq.Bind.Jid // our local id
if o.Session {
//if server support session, open it
fmt.Fprintf(c.conn, "<iq to='%s' type='set' id='%x'><session xmlns='%s'/></iq>", xmlEscape(domain), cookie, NsSession)
}
// We're connected and can now receive and send messages. // We're connected and can now receive and send messages.
fmt.Fprintf(c.conn, "<presence xml:lang='en'><show>xa</show><status>I for one welcome our new codebot overlords.</status></presence>") fmt.Fprintf(c.conn, "<presence xml:lang='en'><show>xa</show><status>I for one welcome our new codebot overlords.</status></presence>")
return nil return nil