package main import ( "crypto/tls" "crypto/x509" "encoding/xml" "log" "strings" ) const ( StreamCloser = `` ) type XmppEvent uint8 const ( XmppDisconnect XmppEvent = iota XmppConnect ) func (l *Limox) xmpp(jid string, pwd string) { log.Printf("JID: '%s' PWD: '%s'\n", jid, pwd) domain := domainpart(jid) log.Printf("Domain: '%s'\n", domain) roots, err := x509.SystemCertPool() if err != nil { l.XmppEvents <- err return } conn, err := tls.Dial("tcp", domain+":"+"5223", &tls.Config{RootCAs: roots}) if err != nil { l.XmppEvents <- err return } l.XmppEvents <- XmppConnect sendStreamStart(conn, jid) var closing bool = false for { ev := <-l.GuiEvents switch ev { case Disconnect: closing = true default: log.Fatalf("Unknown GuiEvent '%d'!\n", ev) } if closing { break } } log.Print("C: " + StreamCloser) conn.Write([]byte(StreamCloser)) conn.Close() l.XmppEvents <- XmppDisconnect } type StreamInit struct { XMLName xml.Name `xml:"stream:stream"` From string `xml:"from,attr"` To string `xml:"to,attr"` Version string `xml:"version,attr"` XmlLang string `xml:"xml:lang,attr"` Xmlns string `xml:"xmlns,attr"` XmlnsStream string `xml:"xmlns:stream,attr"` } func sendStreamStart(t *tls.Conn, jid string) { data := StreamInit{ From: jid, To: domainpart(jid), Version: "1.0", XmlLang: "en", Xmlns: "jabber:client", XmlnsStream: "http://etherx.jabber.org/streams", } serialized, err := xml.Marshal(data) if err != nil { log.Fatal(err) } str := strings.TrimSuffix(string(serialized), StreamCloser) log.Print("C: " + str) t.Write([]byte(serialized)) } // domainpart extracts the domain name from a JID / XMPP address. See // https://datatracker.ietf.org/doc/html/rfc7622#section-3.2 for details. func domainpart(jid string) string { list := []rune(jid) for i, v := range list { if v == '/' { list = list[:i] break } } for i, v := range list { if v == '@' { list = list[i+1:] break } } return string(list) }