forked from sunglocto/lambda
initial commit
This commit is contained in:
317
main.go
Normal file
317
main.go
Normal file
@@ -0,0 +1,317 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/diamondburned/gotk4/pkg/gdk/v4"
|
||||
"github.com/diamondburned/gotk4/pkg/gio/v2"
|
||||
"github.com/diamondburned/gotk4/pkg/glib/v2"
|
||||
"github.com/diamondburned/gotk4/pkg/gtk/v4"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"gosrc.io/xmpp"
|
||||
"gosrc.io/xmpp/stanza"
|
||||
"mellium.im/xmpp/jid"
|
||||
"time"
|
||||
|
||||
_ "embed"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var loadedConfig lambdaConfig
|
||||
|
||||
var empty_dialog *gtk.Label
|
||||
|
||||
// var msgs *gtk.ListBox
|
||||
var content *gtk.Widgetter
|
||||
|
||||
var tabs map[string]*chatTab = make(map[string]*chatTab)
|
||||
var current string
|
||||
|
||||
var scroller *gtk.ScrolledWindow
|
||||
|
||||
//go:embed style.css
|
||||
var styleCSS string
|
||||
var client xmpp.Sender
|
||||
var clientroot *xmpp.Client
|
||||
|
||||
var uiQueue = make(chan func(), 100)
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
for fn := range uiQueue {
|
||||
glib.IdleAdd(func() bool {
|
||||
fn()
|
||||
return false
|
||||
})
|
||||
time.Sleep(10 * time.Millisecond) // Small delay between updates
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
b, err := os.ReadFile("lambda.toml")
|
||||
if err != nil {
|
||||
showErrorDialog(err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = toml.Decode(string(b), &loadedConfig)
|
||||
|
||||
config := xmpp.Config{
|
||||
TransportConfiguration: xmpp.TransportConfiguration{
|
||||
Address: loadedConfig.Server,
|
||||
},
|
||||
Jid: loadedConfig.Username,
|
||||
Credential: xmpp.Password(loadedConfig.Password),
|
||||
Insecure: loadedConfig.Insecure,
|
||||
StreamLogger: os.Stdout,
|
||||
}
|
||||
router := xmpp.NewRouter()
|
||||
|
||||
router.NewRoute().IQNamespaces(stanza.NSDiscoInfo).HandlerFunc(func(s xmpp.Sender, p stanza.Packet) {
|
||||
iq, ok := p.(*stanza.IQ)
|
||||
if !ok || iq.Type != stanza.IQTypeGet {
|
||||
return
|
||||
}
|
||||
|
||||
iqResp, err := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
identity := stanza.Identity{
|
||||
Name: "Lambda",
|
||||
Category: "client", // TODO: Allow spoofing on user request
|
||||
Type: "pc",
|
||||
}
|
||||
payload := stanza.DiscoInfo{
|
||||
XMLName: xml.Name{
|
||||
Space: stanza.NSDiscoInfo,
|
||||
Local: "query",
|
||||
},
|
||||
Identity: []stanza.Identity{identity},
|
||||
Features: []stanza.Feature{
|
||||
{Var: stanza.NSDiscoInfo},
|
||||
{Var: stanza.NSDiscoItems},
|
||||
{Var: "jabber:iq:version"},
|
||||
{Var: "urn:xmpp:delegation:1"},
|
||||
{Var: "http://jabber.org/protocol/muc"},
|
||||
{Var: "urn:xmpp:reply:0"},
|
||||
},
|
||||
}
|
||||
iqResp.Payload = &payload
|
||||
s.Send(iqResp)
|
||||
})
|
||||
|
||||
router.NewRoute().IQNamespaces("jabber:iq:version").HandlerFunc(func(s xmpp.Sender, p stanza.Packet) {
|
||||
iq, ok := p.(*stanza.IQ)
|
||||
if !ok || iq.Type != stanza.IQTypeGet {
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
iqResp, err := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
v := &stanza.Version{}
|
||||
v = v.SetInfo("Lambda", "1.0", "Windows") // TODO: Allow spoofing and report correct information
|
||||
|
||||
iqResp.Payload = v
|
||||
s.Send(iqResp)
|
||||
})
|
||||
|
||||
router.HandleFunc("message", func(s xmpp.Sender, p stanza.Packet) {
|
||||
m, ok := p.(stanza.Message)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if m.Body == "" {
|
||||
return
|
||||
}
|
||||
|
||||
originator := jid.MustParse(m.From).Bare().String()
|
||||
|
||||
glib.IdleAdd(func() {
|
||||
uiQueue <- func() {
|
||||
b := gtk.NewBox(gtk.OrientationVertical, 0)
|
||||
ba, ok := generateMessageWidget(p).(*gtk.Box)
|
||||
if ok {
|
||||
b = ba
|
||||
}
|
||||
|
||||
_, ok = tabs[originator]
|
||||
|
||||
if ok {
|
||||
fmt.Println("valid")
|
||||
tabs[originator].msgs.Append(b)
|
||||
scrollToBottomAfterUpdate(scroller)
|
||||
} else {
|
||||
fmt.Println("Got message when the tab does not exist!")
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
c, err := xmpp.NewClient(&config, router, func(err error) {
|
||||
showErrorDialog(err)
|
||||
panic(err)
|
||||
})
|
||||
if err != nil {
|
||||
showErrorDialog(err)
|
||||
panic(err)
|
||||
}
|
||||
client = c
|
||||
clientroot = c
|
||||
|
||||
cm := xmpp.NewStreamManager(c, func(c xmpp.Sender) {
|
||||
fmt.Println("XMPP client connected")
|
||||
/*
|
||||
*/
|
||||
})
|
||||
|
||||
go func() {
|
||||
err = cm.Run()
|
||||
if err != nil {
|
||||
showErrorDialog(err)
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
app := gtk.NewApplication("net.sunglocto.lambda", gio.ApplicationFlagsNone)
|
||||
app.ConnectActivate(func() { activate(app) })
|
||||
|
||||
if code := app.Run(os.Args); code > 0 {
|
||||
os.Exit(code)
|
||||
}
|
||||
}
|
||||
|
||||
func activate(app *gtk.Application) {
|
||||
// Load the CSS and apply it globally.
|
||||
gtk.StyleContextAddProviderForDisplay(
|
||||
gdk.DisplayGetDefault(), loadCSS(styleCSS),
|
||||
gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
)
|
||||
|
||||
window := gtk.NewApplicationWindow(app)
|
||||
app.SetMenubar(gio.NewMenu())
|
||||
|
||||
window.SetTitle("Lambda")
|
||||
menu := gtk.NewBox(gtk.OrientationHorizontal, 0)
|
||||
/*
|
||||
f_menu := gtk.NewMenuButton()
|
||||
f_menu.SetLabel("File")
|
||||
f_menu.SetAlwaysShowArrow(false)
|
||||
|
||||
e_menu := gtk.NewMenuButton()
|
||||
e_menu.SetLabel("Edit")
|
||||
e_menu.SetAlwaysShowArrow(false)
|
||||
|
||||
v_menu := gtk.NewMenuButton()
|
||||
v_menu.SetLabel("View")
|
||||
v_menu.SetAlwaysShowArrow(false)
|
||||
|
||||
b_menu := gtk.NewMenuButton()
|
||||
b_menu.SetLabel("Bookmarks")
|
||||
b_menu.SetAlwaysShowArrow(false)
|
||||
|
||||
h_menu := gtk.NewMenuButton()
|
||||
h_menu.SetLabel("Help")
|
||||
h_menu.SetAlwaysShowArrow(false)
|
||||
|
||||
menu.Append(f_menu)
|
||||
menu.Append(e_menu)
|
||||
menu.Append(v_menu)
|
||||
menu.Append(b_menu)
|
||||
menu.Append(h_menu)
|
||||
*/
|
||||
|
||||
empty_dialog = gtk.NewLabel("You are not focused on any chats.")
|
||||
empty_dialog.SetVExpand(true)
|
||||
|
||||
scroller = gtk.NewScrolledWindow()
|
||||
|
||||
box := gtk.NewBox(gtk.OrientationVertical, 0)
|
||||
// scroller.SetChild(empty_dialog)
|
||||
scroller.SetChild(empty_dialog)
|
||||
menu_scroll := gtk.NewScrolledWindow()
|
||||
menu_scroll.SetChild(menu)
|
||||
box.Append(menu_scroll)
|
||||
box.Append(scroller)
|
||||
|
||||
entry_box := gtk.NewBox(gtk.OrientationHorizontal, 0)
|
||||
|
||||
en := gtk.NewEntry()
|
||||
en.SetPlaceholderText("Say something, what else are you gonna do here?")
|
||||
b := gtk.NewButtonWithLabel("Send")
|
||||
|
||||
sendtxt := func() {
|
||||
t := en.Text()
|
||||
if t == "" {
|
||||
dialog := >k.AlertDialog{}
|
||||
dialog.SetDetail("detail")
|
||||
dialog.SetMessage("message")
|
||||
dialog.SetButtons([]string{"yes, no"})
|
||||
dialog.Choose(context.TODO(), &window.Window, nil)
|
||||
}
|
||||
|
||||
err := sendMessage(client, current, stanza.MessageTypeGroupchat, t, "", "")
|
||||
if err != nil {
|
||||
panic(err) // TODO: Show error message via GTK
|
||||
}
|
||||
en.SetText("")
|
||||
scrollToBottomAfterUpdate(scroller)
|
||||
}
|
||||
|
||||
en.Connect("activate", sendtxt)
|
||||
|
||||
b.ConnectClicked(sendtxt)
|
||||
|
||||
en.SetHExpand(true)
|
||||
|
||||
entry_box.Append(en)
|
||||
entry_box.Append(b)
|
||||
|
||||
debug_btn := gtk.NewButtonWithLabel("Join muc")
|
||||
|
||||
debug_btn.ConnectClicked(func() {
|
||||
showErrorDialog(errors.New("test error"))
|
||||
t := en.Text()
|
||||
_, ok := tabs[t]
|
||||
if !ok {
|
||||
err := joinMuc(client, clientroot.Session.BindJid, t, loadedConfig.Nick)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
createTab(t, true)
|
||||
b := gtk.NewButtonWithLabel(t)
|
||||
b.ConnectClicked(func() {
|
||||
b.AddCSSClass("accent")
|
||||
switchToTab(t)
|
||||
})
|
||||
menu.Append(b)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
entry_box.Append(debug_btn)
|
||||
|
||||
box.Append(entry_box)
|
||||
|
||||
window.SetChild(box)
|
||||
|
||||
window.SetVisible(true)
|
||||
}
|
||||
|
||||
func loadCSS(content string) *gtk.CSSProvider {
|
||||
prov := gtk.NewCSSProvider()
|
||||
prov.LoadFromString(content)
|
||||
return prov
|
||||
}
|
||||
Reference in New Issue
Block a user