diff options
author | xengineering <me@xengineering.eu> | 2023-05-15 21:09:26 +0200 |
---|---|---|
committer | xengineering <me@xengineering.eu> | 2023-05-15 21:09:26 +0200 |
commit | 8023777ac1b0171783e1c55f67a6179d63708272 (patch) | |
tree | 38b43dff5cb3e846f018f9b77c0c76734bb0f832 /xmpp.go | |
parent | 1769afe3009b5b3cfa3beb3dcf051e41487be113 (diff) | |
download | limox-8023777ac1b0171783e1c55f67a6179d63708272.tar limox-8023777ac1b0171783e1c55f67a6179d63708272.tar.zst limox-8023777ac1b0171783e1c55f67a6179d63708272.zip |
Introduce package xengineering.eu/limox/xmpp
The XMPP logic is now big enough to create a corresponding package for
it.
Diffstat (limited to 'xmpp.go')
-rw-r--r-- | xmpp.go | 187 |
1 files changed, 0 insertions, 187 deletions
diff --git a/xmpp.go b/xmpp.go deleted file mode 100644 index a0aaba7..0000000 --- a/xmpp.go +++ /dev/null @@ -1,187 +0,0 @@ -package main - -import ( - "crypto/tls" - "crypto/x509" - "encoding/xml" - "log" - "os" -) - -type XmppEvent uint8 - -const ( - XmppDisconnect XmppEvent = iota - XmppConnect -) - -func xmpp(rxChan chan GuiEvent, txChan chan any, jid string, pwd string) { - conn, err := setupConn(jid) - if err != nil { - log.Print(err) - return - } - defer conn.Close() - - receiver := newXmppReceiver(conn) - go receiver.run() - defer receiver.stop() - - enc := xml.NewEncoder(conn) - defer enc.Close() - dbg := xml.NewEncoder(os.Stdout) - defer dbg.Close() - - end := sendStreamStart(enc, dbg, jid) - defer sendStreamEnd(enc, dbg, end) - - txChan <- XmppConnect - defer func() { txChan <- XmppDisconnect }() - - for { - select { - case ev := <-rxChan: - switch ev { - case Disconnect: - return - default: - log.Printf("Unknown GuiEvent '%d'!\n", ev) - } - case rx := <-receiver.data: - dbg.Indent("S: ", " ") - dbg.EncodeToken(rx) - dbg.Flush() - } - } -} - -type xmppReceiver struct { - terminator chan bool - data chan xml.Token - decoder *xml.Decoder -} - -func newXmppReceiver(conn *tls.Conn) xmppReceiver { - return xmppReceiver{ - make(chan bool), - make(chan xml.Token), - xml.NewDecoder(conn), - } -} - -func (r *xmppReceiver) run() { - for { - select { - case <-r.terminator: - return - default: - t, err := r.decoder.Token() - if err != nil { - log.Print(err) - } - if t != nil { - c := xml.CopyToken(t) - r.data <- c - } - } - } -} - -func (r *xmppReceiver) stop() { - r.terminator <- true -} - -func setupConn(jid string) (*tls.Conn, error) { - domain := domainpart(jid) - - roots, err := x509.SystemCertPool() - if err != nil { - return nil, err - } - - return tls.Dial("tcp", domain+":"+"5223", &tls.Config{RootCAs: roots}) -} - -func sendStreamStart(enc *xml.Encoder, dbg *xml.Encoder, jid string) xml.EndElement { - start := xml.StartElement{ - xml.Name{"jabber:client", "stream:stream"}, - []xml.Attr{ - xml.Attr{xml.Name{"", "from"}, jid}, - xml.Attr{xml.Name{"", "to"}, domainpart(jid)}, - xml.Attr{xml.Name{"", "version"}, "1.0"}, - xml.Attr{xml.Name{"", "xml:lang"}, "en"}, - xml.Attr{xml.Name{"", "xmlns:stream"}, "http://etherx.jabber.org/streams"}, - }, - } - - err := enc.EncodeToken(start) - if err != nil { - log.Println("Could not encode stream start to TCP channel!") - } - - err = enc.Flush() - if err != nil { - log.Println("Could not flush TCP channel XML encoder!") - } - - dbg.Indent("C: ", " ") - - err = dbg.EncodeToken(start) - if err != nil { - log.Println("Could not encode stream start to debug output!") - } - - err = dbg.Flush() - if err != nil { - log.Println("Could not flush debug XML encoder!") - } - - return start.End() -} - -func sendStreamEnd(enc *xml.Encoder, dbg *xml.Encoder, end xml.EndElement) { - - err := enc.EncodeToken(end) - if err != nil { - log.Println("Could not encode stream end to TCP channel!") - } - - err = enc.Flush() - if err != nil { - log.Println("Could not flush TCP channel XML encoder!") - } - - dbg.Indent("C: ", " ") - - err = dbg.EncodeToken(end) - if err != nil { - log.Println("Could not encode stream end to debug output!") - } - - err = dbg.Flush() - if err != nil { - log.Println("Could not flush debug XML encoder!") - } -} - -// 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) -} |