third_party: add XMPP Go library

This library is needed for the GCM wakeup implementation.

Change-Id: Ia724c88ea9db0ce308f8a4e4446cb9c07db9705c
diff --git a/go/src/github.com/mattn/go-xmpp/LICENSE b/go/src/github.com/mattn/go-xmpp/LICENSE
new file mode 100644
index 0000000..6a66aea
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+   * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/go/src/github.com/mattn/go-xmpp/OWNERS b/go/src/github.com/mattn/go-xmpp/OWNERS
new file mode 100644
index 0000000..947f327
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/OWNERS
@@ -0,0 +1 @@
+spetrovic
diff --git a/go/src/github.com/mattn/go-xmpp/README.google b/go/src/github.com/mattn/go-xmpp/README.google
new file mode 100644
index 0000000..488586e
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/README.google
@@ -0,0 +1,10 @@
+URL: https://github.com/mattn/go-xmpp/archive/54cdc207271aaac6b929245612a2a05f5f7d38a3.zip
+Version: 54cdc207271aaac6b929245612a2a05f5f7d38a3
+License: MIT
+License File: LICENSE
+
+Description:
+Go XMPP library.
+
+Local Modifications:
+None.
diff --git a/go/src/github.com/mattn/go-xmpp/README.md b/go/src/github.com/mattn/go-xmpp/README.md
new file mode 100644
index 0000000..12e4a25
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/README.md
@@ -0,0 +1,4 @@
+go-xmpp
+=======
+
+go xmpp library (original was written by russ cox  )
diff --git a/go/src/github.com/mattn/go-xmpp/_example/example-gui.go b/go/src/github.com/mattn/go-xmpp/_example/example-gui.go
new file mode 100644
index 0000000..f8d3dbc
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/_example/example-gui.go
@@ -0,0 +1,112 @@
+package main
+
+import (
+	"crypto/tls"
+	"github.com/mattn/go-gtk/gtk"
+	"github.com/mattn/go-xmpp"
+	"log"
+	"os"
+	"strings"
+)
+
+func main() {
+	gtk.Init(&os.Args)
+
+	window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
+	window.SetTitle("GoTalk")
+	window.Connect("destroy", func() {
+		gtk.MainQuit()
+	})
+	vbox := gtk.NewVBox(false, 1)
+	scrolledwin := gtk.NewScrolledWindow(nil, nil)
+	textview := gtk.NewTextView()
+	textview.SetEditable(false)
+	textview.SetCursorVisible(false)
+	scrolledwin.Add(textview)
+	vbox.Add(scrolledwin)
+
+	buffer := textview.GetBuffer()
+
+	entry := gtk.NewEntry()
+	vbox.PackEnd(entry, false, false, 0)
+
+	window.Add(vbox)
+	window.SetSizeRequest(300, 400)
+	window.ShowAll()
+
+	dialog := gtk.NewDialog()
+	dialog.SetTitle(window.GetTitle())
+	sgroup := gtk.NewSizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
+
+	hbox := gtk.NewHBox(false, 1)
+	dialog.GetVBox().Add(hbox)
+	label := gtk.NewLabel("username:")
+	sgroup.AddWidget(label)
+	hbox.Add(label)
+	username := gtk.NewEntry()
+	hbox.Add(username)
+
+	hbox = gtk.NewHBox(false, 1)
+	dialog.GetVBox().Add(hbox)
+	label = gtk.NewLabel("password:")
+	sgroup.AddWidget(label)
+	hbox.Add(label)
+	password := gtk.NewEntry()
+	password.SetVisibility(false)
+	hbox.Add(password)
+
+	dialog.AddButton(gtk.STOCK_OK, gtk.RESPONSE_OK)
+	dialog.AddButton(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
+	dialog.SetDefaultResponse(gtk.RESPONSE_OK)
+	dialog.SetTransientFor(window)
+	dialog.ShowAll()
+	res := dialog.Run()
+	username_ := username.GetText()
+	password_ := password.GetText()
+	dialog.Destroy()
+	if res != gtk.RESPONSE_OK {
+		os.Exit(0)
+	}
+
+	xmpp.DefaultConfig = tls.Config{
+		ServerName:         "talk.google.com",
+		InsecureSkipVerify: false,
+	}
+
+	talk, err := xmpp.NewClient("talk.google.com:443", username_, password_, false)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	entry.Connect("activate", func() {
+		text := entry.GetText()
+		tokens := strings.SplitN(text, " ", 2)
+		if len(tokens) == 2 {
+			func() {
+				defer recover()
+				talk.Send(xmpp.Chat{Remote: tokens[0], Type: "chat", Text: tokens[1]})
+				entry.SetText("")
+			}()
+		}
+	})
+
+	go func() {
+		for {
+			func() {
+				defer recover()
+				chat, err := talk.Recv()
+				if err != nil {
+					log.Fatal(err)
+				}
+
+				var iter gtk.TextIter
+				buffer.GetStartIter(&iter)
+				if msg, ok := chat.(xmpp.Chat); ok {
+					buffer.Insert(&iter, msg.Remote+": "+msg.Text+"\n")
+				}
+			}()
+		}
+	}()
+
+	gtk.Main()
+}
diff --git a/go/src/github.com/mattn/go-xmpp/_example/example.go b/go/src/github.com/mattn/go-xmpp/_example/example.go
new file mode 100644
index 0000000..136af5a
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/_example/example.go
@@ -0,0 +1,94 @@
+package main
+
+import (
+	"bufio"
+	"crypto/tls"
+	"flag"
+	"fmt"
+	"github.com/mattn/go-xmpp"
+	"log"
+	"os"
+	"strings"
+)
+
+var server = flag.String("server", "talk.google.com:443", "server")
+var username = flag.String("username", "", "username")
+var password = flag.String("password", "", "password")
+var status = flag.String("status", "xa", "status")
+var statusMessage = flag.String("status-msg", "I for one welcome our new codebot overlords.", "status message")
+var notls = flag.Bool("notls", false, "No TLS")
+var debug = flag.Bool("debug", false, "debug output")
+var session = flag.Bool("session", false, "use server session")
+
+func serverName(host string) string {
+	return strings.Split(host, ":")[0]
+}
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintf(os.Stderr, "usage: example [options]\n")
+		flag.PrintDefaults()
+		os.Exit(2)
+	}
+	flag.Parse()
+	if *username == "" || *password == "" {
+		if *debug && *username == "" && *password == "" {
+			fmt.Fprintf(os.Stderr, "no username or password were given; attempting ANONYMOUS auth\n")
+		} else if *username != "" || *password != "" {
+			flag.Usage()
+		}
+	}
+
+	if !*notls {
+		xmpp.DefaultConfig = tls.Config{
+			ServerName:         serverName(*server),
+			InsecureSkipVerify: false,
+		}
+	}
+
+	var talk *xmpp.Client
+	var err error
+	options := xmpp.Options{Host: *server,
+		User:          *username,
+		Password:      *password,
+		NoTLS:         *notls,
+		Debug:         *debug,
+		Session:       *session,
+		Status:        *status,
+		StatusMessage: *statusMessage,
+	}
+
+	talk, err = options.NewClient()
+
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	go func() {
+		for {
+			chat, err := talk.Recv()
+			if err != nil {
+				log.Fatal(err)
+			}
+			switch v := chat.(type) {
+			case xmpp.Chat:
+				fmt.Println(v.Remote, v.Text)
+			case xmpp.Presence:
+				fmt.Println(v.From, v.Show)
+			}
+		}
+	}()
+	for {
+		in := bufio.NewReader(os.Stdin)
+		line, err := in.ReadString('\n')
+		if err != nil {
+			continue
+		}
+		line = strings.TrimRight(line, "\n")
+
+		tokens := strings.SplitN(line, " ", 2)
+		if len(tokens) == 2 {
+			talk.Send(xmpp.Chat{Remote: tokens[0], Type: "chat", Text: tokens[1]})
+		}
+	}
+}
diff --git a/go/src/github.com/mattn/go-xmpp/xmpp.go b/go/src/github.com/mattn/go-xmpp/xmpp.go
new file mode 100644
index 0000000..b0a7d2e
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/xmpp.go
@@ -0,0 +1,869 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(rsc):
+//	More precise error handling.
+//	Presence functionality.
+// TODO(mattn):
+//  Add proxy authentication.
+
+// Package xmpp implements a simple Google Talk client
+// using the XMPP protocol described in RFC 3920 and RFC 3921.
+package xmpp
+
+import (
+	"bufio"
+	"bytes"
+	"crypto/md5"
+	"crypto/rand"
+	"crypto/tls"
+	"encoding/base64"
+	"encoding/binary"
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"io"
+	"math/big"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"strings"
+	"time"
+)
+
+const (
+	nsStream  = "http://etherx.jabber.org/streams"
+	nsTLS     = "urn:ietf:params:xml:ns:xmpp-tls"
+	nsSASL    = "urn:ietf:params:xml:ns:xmpp-sasl"
+	nsBind    = "urn:ietf:params:xml:ns:xmpp-bind"
+	nsClient  = "jabber:client"
+	nsSession = "urn:ietf:params:xml:ns:xmpp-session"
+)
+
+// Default TLS configuration options
+var DefaultConfig tls.Config
+
+// Cookie is a unique XMPP session identifier
+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[:]))
+}
+
+// Client holds XMPP connection opitons
+type Client struct {
+	conn   net.Conn // connection to server
+	jid    string   // Jabber ID for our connection
+	domain string
+	p      *xml.Decoder
+}
+
+func connect(host, user, passwd string) (net.Conn, error) {
+	addr := host
+
+	if strings.TrimSpace(host) == "" {
+		a := strings.SplitN(user, "@", 2)
+		if len(a) == 2 {
+			addr = a[1]
+		}
+	}
+	a := strings.SplitN(host, ":", 2)
+	if len(a) == 1 {
+		addr += ":5222"
+	}
+	proxy := os.Getenv("HTTP_PROXY")
+	if proxy == "" {
+		proxy = os.Getenv("http_proxy")
+	}
+	if proxy != "" {
+		url, err := url.Parse(proxy)
+		if err == nil {
+			addr = url.Host
+		}
+	}
+	c, err := net.Dial("tcp", addr)
+	if err != nil {
+		return nil, err
+	}
+
+	if proxy != "" {
+		fmt.Fprintf(c, "CONNECT %s HTTP/1.1\r\n", host)
+		fmt.Fprintf(c, "Host: %s\r\n", host)
+		fmt.Fprintf(c, "\r\n")
+		br := bufio.NewReader(c)
+		req, _ := http.NewRequest("CONNECT", host, nil)
+		resp, err := http.ReadResponse(br, req)
+		if err != nil {
+			return nil, err
+		}
+		if resp.StatusCode != 200 {
+			f := strings.SplitN(resp.Status, " ", 2)
+			return nil, errors.New(f[1])
+		}
+	}
+	return c, nil
+}
+
+// Options are used to specify additional options for new clients, such as a Resource.
+type Options struct {
+	// Host specifies what host to connect to, as either "hostname" or "hostname:port"
+	// If host is not specified, the  DNS SRV should be used to find the host from the domainpart of the JID.
+	// Default the port to 5222.
+	Host string
+
+	// User specifies what user to authenticate to the remote server.
+	User string
+
+	// Password supplies the password to use for authentication with the remote server.
+	Password string
+
+	// Resource specifies an XMPP client resource, like "bot", instead of accepting one
+	// from the server.  Use "" to let the server generate one for your client.
+	Resource string
+
+	// OAuthScope provides go-xmpp the required scope for OAuth2 authentication.
+	OAuthScope string
+
+	// OAuthToken provides go-xmpp with the required OAuth2 token used to authenticate
+	OAuthToken string
+
+	// OAuthXmlNs provides go-xmpp with the required namespaced used for OAuth2 authentication.  This is
+	// provided to the server as the xmlns:auth attribute of the OAuth2 authentication request.
+	OAuthXmlNs string
+
+	// TLS Config
+	TLSConfig *tls.Config
+
+	// InsecureAllowUnencryptedAuth permits authentication over a TCP connection that has not been promoted to
+	// TLS by STARTTLS; this could leak authentication information over the network, or permit man in the middle
+	// attacks.
+	InsecureAllowUnencryptedAuth bool
+
+	// NoTLS directs go-xmpp to not use TLS initially to contact the server; instead, a plain old unencrypted
+	// TCP connection should be used. (Can be combined with StartTLS to support STARTTLS-based servers.)
+	NoTLS bool
+
+	// StartTLS directs go-xmpp to STARTTLS if the server supports it; go-xmpp will automatically STARTTLS
+	// if the server requires it regardless of this option.
+	StartTLS bool
+
+	// Debug output
+	Debug bool
+
+	// Use server sessions
+	Session bool
+
+	// Presence Status
+	Status string
+
+	// Status message
+	StatusMessage string
+}
+
+// NewClient establishes a new Client connection based on a set of Options.
+func (o Options) NewClient() (*Client, error) {
+	host := o.Host
+	c, err := connect(host, o.User, o.Password)
+	if err != nil {
+		return nil, err
+	}
+
+	if strings.LastIndex(o.Host, ":") > 0 {
+		host = host[:strings.LastIndex(o.Host, ":")]
+	}
+
+	client := new(Client)
+	if o.NoTLS {
+		client.conn = c
+	} else {
+		var tlsconn *tls.Conn
+		if o.TLSConfig != nil {
+			tlsconn = tls.Client(c, o.TLSConfig)
+		} else {
+			DefaultConfig.ServerName = host
+			tlsconn = tls.Client(c, &DefaultConfig)
+		}
+		if err = tlsconn.Handshake(); err != nil {
+			return nil, err
+		}
+		insecureSkipVerify := DefaultConfig.InsecureSkipVerify
+		if o.TLSConfig != nil {
+			insecureSkipVerify = o.TLSConfig.InsecureSkipVerify
+		}
+		if !insecureSkipVerify {
+			if err = tlsconn.VerifyHostname(host); err != nil {
+				return nil, err
+			}
+		}
+		client.conn = tlsconn
+	}
+
+	if err := client.init(&o); err != nil {
+		client.Close()
+		return nil, err
+	}
+
+	return client, nil
+}
+
+// NewClient creates a new connection to a host given as "hostname" or "hostname:port".
+// If host is not specified, the  DNS SRV should be used to find the host from the domainpart of the JID.
+// Default the port to 5222.
+func NewClient(host, user, passwd string, debug bool) (*Client, error) {
+	opts := Options{
+		Host:     host,
+		User:     user,
+		Password: passwd,
+		Debug:    debug,
+		Session:  false,
+	}
+	return opts.NewClient()
+}
+
+// NewClientNoTLS creates a new client without TLS
+func NewClientNoTLS(host, user, passwd string, debug bool) (*Client, error) {
+	opts := Options{
+		Host:     host,
+		User:     user,
+		Password: passwd,
+		NoTLS:    true,
+		Debug:    debug,
+		Session:  false,
+	}
+	return opts.NewClient()
+}
+
+// Close closes the XMPP connection
+func (c *Client) Close() error {
+	if c.conn != (*tls.Conn)(nil) {
+		return c.conn.Close()
+	}
+	return nil
+}
+
+func saslDigestResponse(username, realm, passwd, nonce, cnonceStr, authenticate, digestURI, nonceCountStr string) string {
+	h := func(text string) []byte {
+		h := md5.New()
+		h.Write([]byte(text))
+		return h.Sum(nil)
+	}
+	hex := func(bytes []byte) string {
+		return fmt.Sprintf("%x", bytes)
+	}
+	kd := func(secret, data string) []byte {
+		return h(secret + ":" + data)
+	}
+
+	a1 := string(h(username+":"+realm+":"+passwd)) + ":" + nonce + ":" + cnonceStr
+	a2 := authenticate + ":" + digestURI
+	response := hex(kd(hex(h(a1)), nonce+":"+nonceCountStr+":"+cnonceStr+":auth:"+hex(h(a2))))
+	return response
+}
+
+func cnonce() string {
+	randSize := big.NewInt(0)
+	randSize.Lsh(big.NewInt(1), 64)
+	cn, err := rand.Int(rand.Reader, randSize)
+	if err != nil {
+		return ""
+	}
+	return fmt.Sprintf("%016x", cn)
+}
+
+func (c *Client) init(o *Options) error {
+
+	var domain string
+	var user string
+	a := strings.SplitN(o.User, "@", 2)
+	if len(o.User) > 0 {
+		if len(a) != 2 {
+			return errors.New("xmpp: invalid username (want user@domain): " + o.User)
+		}
+		user = a[0]
+		domain = a[1]
+	} // Otherwise, we'll be attempting ANONYMOUS
+
+	// Declare intent to be a jabber client and gather stream features.
+	f, err := c.startStream(o, domain)
+	if err != nil {
+		return err
+	}
+
+	// If the server requires we STARTTLS, attempt to do so.
+	if f, err = c.startTLSIfRequired(f, o, domain); err != nil {
+		return err
+	}
+
+	if o.User == "" && o.Password == "" {
+		foundAnonymous := false
+		for _, m := range f.Mechanisms.Mechanism {
+			if m == "ANONYMOUS" {
+				fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='ANONYMOUS' />\n", nsSASL)
+				foundAnonymous = true
+				break
+			}
+		}
+		if !foundAnonymous {
+			return fmt.Errorf("ANONYMOUS authentication is not an option and username and password were not specified")
+		}
+	} else {
+		// Even digest forms of authentication are unsafe if we do not know that the host
+		// we are talking to is the actual server, and not a man in the middle playing
+		// proxy.
+		if !c.IsEncrypted() && !o.InsecureAllowUnencryptedAuth {
+			return errors.New("refusing to authenticate over unencrypted TCP connection")
+		}
+
+		mechanism := ""
+		for _, m := range f.Mechanisms.Mechanism {
+			if m == "X-OAUTH2" && o.OAuthToken != "" && o.OAuthScope != "" {
+				mechanism = m
+				// Oauth authentication: send base64-encoded \x00 user \x00 token.
+				raw := "\x00" + user + "\x00" + o.OAuthToken
+				enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
+				base64.StdEncoding.Encode(enc, []byte(raw))
+				fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='X-OAUTH2' auth:service='oauth2' "+
+					"xmlns:auth='%s'>%s</auth>\n", nsSASL, o.OAuthXmlNs, enc)
+				break
+			}
+			if m == "PLAIN" {
+				mechanism = m
+				// Plain authentication: send base64-encoded \x00 user \x00 password.
+				raw := "\x00" + user + "\x00" + o.Password
+				enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
+				base64.StdEncoding.Encode(enc, []byte(raw))
+				fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>\n", nsSASL, enc)
+				break
+			}
+			if m == "DIGEST-MD5" {
+				mechanism = m
+				// Digest-MD5 authentication
+				fmt.Fprintf(c.conn, "<auth xmlns='%s' mechanism='DIGEST-MD5'/>\n", nsSASL)
+				var ch saslChallenge
+				if err = c.p.DecodeElement(&ch, nil); err != nil {
+					return errors.New("unmarshal <challenge>: " + err.Error())
+				}
+				b, err := base64.StdEncoding.DecodeString(string(ch))
+				if err != nil {
+					return err
+				}
+				tokens := map[string]string{}
+				for _, token := range strings.Split(string(b), ",") {
+					kv := strings.SplitN(strings.TrimSpace(token), "=", 2)
+					if len(kv) == 2 {
+						if kv[1][0] == '"' && kv[1][len(kv[1])-1] == '"' {
+							kv[1] = kv[1][1 : len(kv[1])-1]
+						}
+						tokens[kv[0]] = kv[1]
+					}
+				}
+				realm, _ := tokens["realm"]
+				nonce, _ := tokens["nonce"]
+				qop, _ := tokens["qop"]
+				charset, _ := tokens["charset"]
+				cnonceStr := cnonce()
+				digestURI := "xmpp/" + domain
+				nonceCount := fmt.Sprintf("%08x", 1)
+				digest := saslDigestResponse(user, realm, o.Password, nonce, cnonceStr, "AUTHENTICATE", digestURI, nonceCount)
+				message := "username=\"" + user + "\", realm=\"" + realm + "\", nonce=\"" + nonce + "\", cnonce=\"" + cnonceStr +
+					"\", nc=" + nonceCount + ", qop=" + qop + ", digest-uri=\"" + digestURI + "\", response=" + digest + ", charset=" + charset
+
+				fmt.Fprintf(c.conn, "<response xmlns='%s'>%s</response>\n", nsSASL, base64.StdEncoding.EncodeToString([]byte(message)))
+
+				var rspauth saslRspAuth
+				if err = c.p.DecodeElement(&rspauth, nil); err != nil {
+					return errors.New("unmarshal <challenge>: " + err.Error())
+				}
+				b, err = base64.StdEncoding.DecodeString(string(rspauth))
+				if err != nil {
+					return err
+				}
+				fmt.Fprintf(c.conn, "<response xmlns='%s'/>\n", nsSASL)
+				break
+			}
+		}
+		if mechanism == "" {
+			return fmt.Errorf("PLAIN authentication is not an option: %v", f.Mechanisms.Mechanism)
+		}
+	}
+	// Next message should be either success or failure.
+	name, val, err := next(c.p)
+	if err != nil {
+		return err
+	}
+	switch v := val.(type) {
+	case *saslSuccess:
+	case *saslFailure:
+		// v.Any is type of sub-element in failure,
+		// which gives a description of what failed.
+		return errors.New("auth failure: " + v.Any.Local)
+	default:
+		return errors.New("expected <success> or <failure>, got <" + name.Local + "> in " + name.Space)
+	}
+
+	// Now that we're authenticated, we're supposed to start the stream over again.
+	// Declare intent to be a jabber client.
+	if f, err = c.startStream(o, domain); err != nil {
+		return err
+	}
+
+	// Generate a uniqe cookie
+	cookie := getCookie()
+
+	// Send IQ message asking to bind to the local user name.
+	if o.Resource == "" {
+		fmt.Fprintf(c.conn, "<iq type='set' id='%x'><bind xmlns='%s'></bind></iq>\n", cookie, nsBind)
+	} else {
+		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
+	if err = c.p.DecodeElement(&iq, nil); err != nil {
+		return errors.New("unmarshal <iq>: " + err.Error())
+	}
+	if &iq.Bind == nil {
+		return errors.New("<iq> result missing <bind>")
+	}
+	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.
+	fmt.Fprintf(c.conn, "<presence xml:lang='en'><show>%s</show><status>%s</status></presence>", o.Status, o.StatusMessage)
+
+	return nil
+}
+
+// startTlsIfRequired examines the server's stream features and, if STARTTLS is required or supported, performs the TLS handshake.
+// f will be updated if the handshake completes, as the new stream's features are typically different from the original.
+func (c *Client) startTLSIfRequired(f *streamFeatures, o *Options, domain string) (*streamFeatures, error) {
+	// whether we start tls is a matter of opinion: the server's and the user's.
+	switch {
+	case f.StartTLS == nil:
+		// the server does not support STARTTLS
+		return f, nil
+	case f.StartTLS.Required != nil:
+		// the server requires STARTTLS.
+	case !o.StartTLS:
+		// the user wants STARTTLS and the server supports it.
+	}
+	var err error
+
+	fmt.Fprintf(c.conn, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>\n")
+	var k tlsProceed
+	if err = c.p.DecodeElement(&k, nil); err != nil {
+		return f, errors.New("unmarshal <proceed>: " + err.Error())
+	}
+
+	tc := o.TLSConfig
+	if tc == nil {
+		tc = new(tls.Config)
+		*tc = DefaultConfig
+		//TODO(scott): we should consider using the server's address or reverse lookup
+		tc.ServerName = domain
+	}
+	t := tls.Client(c.conn, tc)
+
+	if err = t.Handshake(); err != nil {
+		return f, errors.New("starttls handshake: " + err.Error())
+	}
+	c.conn = t
+
+	// restart our declaration of XMPP stream intentions.
+	tf, err := c.startStream(o, domain)
+	if err != nil {
+		return f, err
+	}
+	return tf, nil
+}
+
+// startStream will start a new XML decoder for the connection, signal the start of a stream to the server and verify that the server has
+// also started the stream; if o.Debug is true, startStream will tee decoded XML data to stderr.  The features advertised by the server
+// will be returned.
+func (c *Client) startStream(o *Options, domain string) (*streamFeatures, error) {
+	if o.Debug {
+		c.p = xml.NewDecoder(tee{c.conn, os.Stderr})
+	} else {
+		c.p = xml.NewDecoder(c.conn)
+	}
+
+	_, err := fmt.Fprintf(c.conn, "<?xml version='1.0'?>\n"+
+		"<stream:stream to='%s' xmlns='%s'\n"+
+		" xmlns:stream='%s' version='1.0'>\n",
+		xmlEscape(domain), nsClient, nsStream)
+	if err != nil {
+		return nil, err
+	}
+
+	// We expect the server to start a <stream>.
+	se, err := nextStart(c.p)
+	if err != nil {
+		return nil, err
+	}
+	if se.Name.Space != nsStream || se.Name.Local != "stream" {
+		return nil, fmt.Errorf("expected <stream> but got <%v> in %v", se.Name.Local, se.Name.Space)
+	}
+
+	// Now we're in the stream and can use Unmarshal.
+	// Next message should be <features> to tell us authentication options.
+	// See section 4.6 in RFC 3920.
+	f := new(streamFeatures)
+	if err = c.p.DecodeElement(f, nil); err != nil {
+		return f, errors.New("unmarshal <features>: " + err.Error())
+	}
+	return f, nil
+}
+
+// IsEncrypted will return true if the client is connected using a TLS transport, either because it used.
+// TLS to connect from the outset, or because it successfully used STARTTLS to promote a TCP connection to TLS.
+func (c *Client) IsEncrypted() bool {
+	_, ok := c.conn.(*tls.Conn)
+	return ok
+}
+
+// Chat is an incoming or outgoing XMPP chat message.
+type Chat struct {
+	Remote string
+	Type   string
+	Text   string
+	Roster Roster
+	Other  []string
+	Stamp  time.Time
+}
+
+type Roster []Contact
+
+type Contact struct {
+	Remote string
+	Name   string
+	Group  []string
+}
+
+// Presence is an XMPP presence notification.
+type Presence struct {
+	From   string
+	To     string
+	Type   string
+	Show   string
+	Status string
+}
+
+type IQ struct {
+	ID   string
+	From string
+	To   string
+	Type string
+}
+
+// Recv waits to receive the next XMPP stanza.
+// Return type is either a presence notification or a chat message.
+func (c *Client) Recv() (stanza interface{}, err error) {
+	for {
+		_, val, err := next(c.p)
+		if err != nil {
+			return Chat{}, err
+		}
+		switch v := val.(type) {
+		case *clientMessage:
+			stamp, _ := time.Parse(
+				"2006-01-02T15:04:05Z",
+				v.Delay.Stamp,
+			)
+			chat := Chat{
+				Remote: v.From,
+				Type:   v.Type,
+				Text:   v.Body,
+				Other:  v.Other,
+				Stamp:  stamp,
+			}
+			return chat, nil
+		case *clientQuery:
+			var r Roster
+			for _, item := range v.Item {
+				r = append(r, Contact{item.Jid, item.Name, item.Group})
+			}
+			return Chat{Type: "roster", Roster: r}, nil
+		case *clientPresence:
+			return Presence{v.From, v.To, v.Type, v.Show, v.Status}, nil
+		case *clientIQ:
+			return IQ{v.ID, v.From, v.To, v.Type}, nil
+		}
+	}
+}
+
+// Send sends the message wrapped inside an XMPP message stanza body.
+func (c *Client) Send(chat Chat) (n int, err error) {
+	return fmt.Fprintf(c.conn, "<message to='%s' type='%s' xml:lang='en'>"+"<body>%s</body></message>",
+		xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text))
+}
+
+// SendOrg sends the original text without being wrapped in an XMPP message stanza.
+func (c *Client) SendOrg(org string) (n int, err error) {
+	return fmt.Fprint(c.conn, org)
+}
+
+// SendHtml sends the message as HTML as defined by XEP-0071
+func (c *Client) SendHtml(chat Chat) (n int, err error) {
+	return fmt.Fprintf(c.conn, "<message to='%s' type='%s' xml:lang='en'>"+
+		"<body>%s</body>"+
+		"<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html></message>",
+		xmlEscape(chat.Remote), xmlEscape(chat.Type), xmlEscape(chat.Text), chat.Text)
+}
+
+// Roster asks for the chat roster.
+func (c *Client) Roster() error {
+	fmt.Fprintf(c.conn, "<iq from='%s' type='get' id='roster1'><query xmlns='jabber:iq:roster'/></iq>\n", xmlEscape(c.jid))
+	return nil
+}
+
+// RFC 3920  C.1  Streams name space
+type streamFeatures struct {
+	XMLName    xml.Name `xml:"http://etherx.jabber.org/streams features"`
+	StartTLS   *tlsStartTLS
+	Mechanisms saslMechanisms
+	Bind       bindBind
+	Session    bool
+}
+
+type streamError struct {
+	XMLName xml.Name `xml:"http://etherx.jabber.org/streams error"`
+	Any     xml.Name
+	Text    string
+}
+
+// RFC 3920  C.3  TLS name space
+type tlsStartTLS struct {
+	XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls starttls"`
+	Required *string  `xml:"required"`
+}
+
+type tlsProceed struct {
+	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls proceed"`
+}
+
+type tlsFailure struct {
+	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls failure"`
+}
+
+// RFC 3920  C.4  SASL name space
+type saslMechanisms struct {
+	XMLName   xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
+	Mechanism []string `xml:"mechanism"`
+}
+
+type saslAuth struct {
+	XMLName   xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"`
+	Mechanism string   `xml:",attr"`
+}
+
+type saslChallenge string
+
+type saslRspAuth string
+
+type saslResponse string
+
+type saslAbort struct {
+	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl abort"`
+}
+
+type saslSuccess struct {
+	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"`
+}
+
+type saslFailure struct {
+	XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"`
+	Any     xml.Name `xml:",any"`
+}
+
+// RFC 3920  C.5  Resource binding name space
+type bindBind struct {
+	XMLName  xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
+	Resource string
+	Jid      string `xml:"jid"`
+}
+
+// RFC 3921  B.1  jabber:client
+type clientMessage struct {
+	XMLName xml.Name `xml:"jabber:client message"`
+	From    string   `xml:"from,attr"`
+	ID      string   `xml:"id,attr"`
+	To      string   `xml:"to,attr"`
+	Type    string   `xml:"type,attr"` // chat, error, groupchat, headline, or normal
+
+	// These should technically be []clientText, but string is much more convenient.
+	Subject string `xml:"subject"`
+	Body    string `xml:"body"`
+	Thread  string `xml:"thread"`
+
+	// Any hasn't matched element
+	Other []string `xml:",any"`
+
+	Delay Delay `xml:"delay"`
+}
+
+type Delay struct {
+	Stamp string `xml:"stamp,attr"`
+}
+
+type clientText struct {
+	Lang string `xml:",attr"`
+	Body string `xml:"chardata"`
+}
+
+type clientPresence struct {
+	XMLName xml.Name `xml:"jabber:client presence"`
+	From    string   `xml:"from,attr"`
+	ID      string   `xml:"id,attr"`
+	To      string   `xml:"to,attr"`
+	Type    string   `xml:"type,attr"` // error, probe, subscribe, subscribed, unavailable, unsubscribe, unsubscribed
+	Lang    string   `xml:"lang,attr"`
+
+	Show     string `xml:"show"`   // away, chat, dnd, xa
+	Status   string `xml:"status"` // sb []clientText
+	Priority string `xml:"priority,attr"`
+	Error    *clientError
+}
+
+type clientIQ struct { // info/query
+	XMLName xml.Name `xml:"jabber:client iq"`
+	From    string   `xml:"from,attr"`
+	ID      string   `xml:"id,attr"`
+	To      string   `xml:"to,attr"`
+	Type    string   `xml:"type,attr"` // error, get, result, set
+	Error   clientError
+	Bind    bindBind
+}
+
+type clientError struct {
+	XMLName xml.Name `xml:"jabber:client error"`
+	Code    string   `xml:",attr"`
+	Type    string   `xml:",attr"`
+	Any     xml.Name
+	Text    string
+}
+
+type clientQuery struct {
+	Item []rosterItem
+}
+
+type rosterItem struct {
+	XMLName      xml.Name `xml:"jabber:iq:roster item"`
+	Jid          string   `xml:",attr"`
+	Name         string   `xml:",attr"`
+	Subscription string   `xml:",attr"`
+	Group        []string
+}
+
+// Scan XML token stream to find next StartElement.
+func nextStart(p *xml.Decoder) (xml.StartElement, error) {
+	for {
+		t, err := p.Token()
+		if err != nil && err != io.EOF || t == nil {
+			return xml.StartElement{}, err
+		}
+		switch t := t.(type) {
+		case xml.StartElement:
+			return t, nil
+		}
+	}
+}
+
+// Scan XML token stream for next element and save into val.
+// If val == nil, allocate new element based on proto map.
+// Either way, return val.
+func next(p *xml.Decoder) (xml.Name, interface{}, error) {
+	// Read start element to find out what type we want.
+	se, err := nextStart(p)
+	if err != nil {
+		return xml.Name{}, nil, err
+	}
+
+	// Put it in an interface and allocate one.
+	var nv interface{}
+	switch se.Name.Space + " " + se.Name.Local {
+	case nsStream + " features":
+		nv = &streamFeatures{}
+	case nsStream + " error":
+		nv = &streamError{}
+	case nsTLS + " starttls":
+		nv = &tlsStartTLS{}
+	case nsTLS + " proceed":
+		nv = &tlsProceed{}
+	case nsTLS + " failure":
+		nv = &tlsFailure{}
+	case nsSASL + " mechanisms":
+		nv = &saslMechanisms{}
+	case nsSASL + " challenge":
+		nv = ""
+	case nsSASL + " response":
+		nv = ""
+	case nsSASL + " abort":
+		nv = &saslAbort{}
+	case nsSASL + " success":
+		nv = &saslSuccess{}
+	case nsSASL + " failure":
+		nv = &saslFailure{}
+	case nsBind + " bind":
+		nv = &bindBind{}
+	case nsClient + " message":
+		nv = &clientMessage{}
+	case nsClient + " presence":
+		nv = &clientPresence{}
+	case nsClient + " iq":
+		nv = &clientIQ{}
+	case nsClient + " error":
+		nv = &clientError{}
+	default:
+		return xml.Name{}, nil, errors.New("unexpected XMPP message " +
+			se.Name.Space + " <" + se.Name.Local + "/>")
+	}
+
+	// Unmarshal into that storage.
+	if err = p.DecodeElement(nv, &se); err != nil {
+		return xml.Name{}, nil, err
+	}
+	return se.Name, nv, err
+}
+
+var xmlSpecial = map[byte]string{
+	'<':  "&lt;",
+	'>':  "&gt;",
+	'"':  "&quot;",
+	'\'': "&apos;",
+	'&':  "&amp;",
+}
+
+func xmlEscape(s string) string {
+	var b bytes.Buffer
+	for i := 0; i < len(s); i++ {
+		c := s[i]
+		if s, ok := xmlSpecial[c]; ok {
+			b.WriteString(s)
+		} else {
+			b.WriteByte(c)
+		}
+	}
+	return b.String()
+}
+
+type tee struct {
+	r io.Reader
+	w io.Writer
+}
+
+func (t tee) Read(p []byte) (n int, err error) {
+	n, err = t.r.Read(p)
+	if n > 0 {
+		t.w.Write(p[0:n])
+		t.w.Write([]byte("\n"))
+	}
+	return
+}
diff --git a/go/src/github.com/mattn/go-xmpp/xmpp_muc.go b/go/src/github.com/mattn/go-xmpp/xmpp_muc.go
new file mode 100644
index 0000000..eeb1c89
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/xmpp_muc.go
@@ -0,0 +1,47 @@
+// Copyright 2013 Flo Lauber <dev@qatfy.at>.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(flo):
+//   - support password protected MUC rooms
+//   - cleanup signatures of join/leave functions
+package xmpp
+
+import (
+	"fmt"
+)
+
+const (
+	nsMUC     = "http://jabber.org/protocol/muc"
+	nsMUCUser = "http://jabber.org/protocol/muc#user"
+)
+
+// xep-0045 7.2
+func (c *Client) JoinMUC(jid, nick string) {
+	if nick == "" {
+		nick = c.jid
+	}
+	fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
+		"<x xmlns='%s' />\n"+
+		"</presence>",
+		xmlEscape(jid), xmlEscape(nick), nsMUC)
+}
+
+// xep-0045 7.2.6
+func (c *Client) JoinProtectedMUC(jid, nick string, password string) {
+	if nick == "" {
+		nick = c.jid
+	}
+	fmt.Fprintf(c.conn, "<presence to='%s/%s'>\n"+
+		"<x xmlns='%s'>\n"+
+		"<password>%s</password>\n"+
+		"</x>\n"+
+		"</presence>",
+		xmlEscape(jid), xmlEscape(nick), nsMUC, xmlEscape(password))
+}
+
+// xep-0045 7.14
+func (c *Client) LeaveMUC(jid string) {
+	fmt.Fprintf(c.conn, "<presence from='%s' to='%s' type='unavailable' />",
+		c.jid, xmlEscape(jid))
+}
diff --git a/go/src/github.com/mattn/go-xmpp/xmpp_ping.go b/go/src/github.com/mattn/go-xmpp/xmpp_ping.go
new file mode 100644
index 0000000..685985d
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/xmpp_ping.go
@@ -0,0 +1,21 @@
+package xmpp
+
+import (
+	"fmt"
+)
+
+func (c *Client) PingC2S(jid, server string) error {
+	_, err := fmt.Fprintf(c.conn, "<iq from='%s' to='%s' id='c2s1' type='get'>\n"+
+		"<ping xmlns='urn:xmpp:ping'/>\n"+
+		"</iq>",
+		xmlEscape(jid), xmlEscape(server))
+	return err
+}
+
+func (c *Client) PingS2S(fromServer, toServer string) error {
+	_, err := fmt.Fprintf(c.conn, "<iq from='%s' to='%s' id='s2s1' type='get'>\n"+
+		"<ping xmlns='urn:xmpp:ping'/>\n"+
+		"</iq>",
+		xmlEscape(fromServer), xmlEscape(toServer))
+	return err
+}
diff --git a/go/src/github.com/mattn/go-xmpp/xmpp_subscription.go b/go/src/github.com/mattn/go-xmpp/xmpp_subscription.go
new file mode 100644
index 0000000..eb29314
--- /dev/null
+++ b/go/src/github.com/mattn/go-xmpp/xmpp_subscription.go
@@ -0,0 +1,20 @@
+package xmpp
+
+import (
+	"fmt"
+)
+
+func (c *Client) ApproveSubscription(jid string) {
+	fmt.Fprintf(c.conn, "<presence to='%s' type='subscribed'/>",
+		xmlEscape(jid))
+}
+
+func (c *Client) RevokeSubscription(jid string) {
+	fmt.Fprintf(c.conn, "<presence to='%s' type='unsubscribed'/>",
+		xmlEscape(jid))
+}
+
+func (c *Client) RequestSubscription(jid string) {
+	fmt.Fprintf(c.conn, "<presence to='%s' type='subscribe'/>",
+		xmlEscape(jid))
+}