From 8023777ac1b0171783e1c55f67a6179d63708272 Mon Sep 17 00:00:00 2001
From: xengineering <me@xengineering.eu>
Date: Mon, 15 May 2023 21:09:26 +0200
Subject: Introduce package xengineering.eu/limox/xmpp

The XMPP logic is now big enough to create a corresponding package for
it.
---
 gui.go       |   6 --
 limox.go     |  18 +++---
 xmpp.go      | 187 ----------------------------------------------------------
 xmpp/xmpp.go | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 198 insertions(+), 201 deletions(-)
 delete mode 100644 xmpp.go
 create mode 100644 xmpp/xmpp.go

diff --git a/gui.go b/gui.go
index e6e4c31..55730df 100644
--- a/gui.go
+++ b/gui.go
@@ -10,12 +10,6 @@ import (
 	"gioui.org/widget/material"
 )
 
-type GuiEvent uint8
-
-const (
-	Disconnect GuiEvent = iota
-)
-
 func (l *Limox) draw(e system.FrameEvent) {
 	gtx := layout.NewContext(&l.Operations, e)
 
diff --git a/limox.go b/limox.go
index 89a5916..2dee767 100644
--- a/limox.go
+++ b/limox.go
@@ -11,6 +11,8 @@ import (
 	"gioui.org/unit"
 	"gioui.org/widget"
 	"gioui.org/widget/material"
+
+	"xengineering.eu/limox/xmpp"
 )
 
 type LimoxState uint8
@@ -26,7 +28,7 @@ type Limox struct {
 	PwdEditor  widget.Editor
 	MainButton widget.Clickable
 	XmppEvents chan any
-	GuiEvents  chan GuiEvent
+	GuiEvents  chan xmpp.Event
 	State      LimoxState
 	Window     *app.Window
 	Operations op.Ops
@@ -42,7 +44,7 @@ func NewLimox() Limox {
 		Operations: op.Ops{},
 		Theme:      material.NewTheme(gofont.Collection()),
 		XmppEvents: make(chan any),
-		GuiEvents:  make(chan GuiEvent),
+		GuiEvents:  make(chan xmpp.Event),
 		State:      Disconnected,
 	}
 }
@@ -65,14 +67,14 @@ func (l *Limox) run() error {
 			case error:
 				log.Print(ev)
 				l.State = Disconnected
-			case XmppEvent:
+			case xmpp.Event:
 				switch ev {
-				case XmppDisconnect:
+				case xmpp.DisconnectEvent:
 					l.State = Disconnected
-				case XmppConnect:
+				case xmpp.ConnectEvent:
 					l.State = Connected
 				default:
-					log.Printf("Unknown XmppEvent '%d'\n", ev)
+					log.Printf("Unknown xmpp.Event '%d'\n", ev)
 				}
 			default:
 				log.Printf("Unknown event type '%s'.\n", reflect.TypeOf(ev))
@@ -86,14 +88,14 @@ func (l *Limox) buttonCallback() {
 	switch l.State {
 	case Disconnected:
 		log.Println("Starting connection establishment ...")
-		go xmpp(l.GuiEvents, l.XmppEvents, l.JidEditor.Text(), l.PwdEditor.Text())
+		go xmpp.Run(l.GuiEvents, l.XmppEvents, l.JidEditor.Text(), l.PwdEditor.Text())
 		l.State = Connecting
 	case Connecting:
 		log.Println("Aborted connection establishment")
 		l.State = Disconnected
 	case Connected:
 		log.Println("Disconnecting ...")
-		l.GuiEvents <- Disconnect
+		l.GuiEvents <- xmpp.ShouldDisconnectEvent
 		l.State = Disconnected
 	}
 }
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)
-}
diff --git a/xmpp/xmpp.go b/xmpp/xmpp.go
new file mode 100644
index 0000000..64ca494
--- /dev/null
+++ b/xmpp/xmpp.go
@@ -0,0 +1,188 @@
+package xmpp
+
+import (
+	"crypto/tls"
+	"crypto/x509"
+	"encoding/xml"
+	"log"
+	"os"
+)
+
+type Event uint8
+
+const (
+	DisconnectEvent Event = iota
+	ConnectEvent
+	ShouldDisconnectEvent
+)
+
+func Run(rxChan chan Event, 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 <- ConnectEvent
+	defer func() { txChan <- DisconnectEvent }()
+
+	for {
+		select {
+		case ev := <-rxChan:
+			switch ev {
+			case ShouldDisconnectEvent:
+				return
+			default:
+				log.Printf("Unknown Event '%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)
+}
-- 
cgit v1.2.3-70-g09d2