From fc0ed5ac2cccc64f10f6941d7660acf3ed3d3d08 Mon Sep 17 00:00:00 2001 From: sunglocto Date: Sun, 26 Apr 2026 10:40:13 +0100 Subject: [PATCH] somehow sunglocto returned --- assets.go | 131 +++++++++++++++++++++ assets/car_down.png | Bin 0 -> 656 bytes assets/car_high.png | Bin 0 -> 456 bytes assets/car_up.png | Bin 0 -> 641 bytes assets/chart_bar_laggy.png | Bin 0 -> 434 bytes gtk-helpers.go | 25 +++- gtk-message.go | 24 ++++ main.go | 231 ++++++++++++++++++++++++++++--------- style.css | 7 ++ types.go | 2 + version.go | 2 +- xmpp-helpers.go | 33 ++++-- xmpp-link-previews.go | 20 ++++ 13 files changed, 407 insertions(+), 68 deletions(-) create mode 100644 assets/car_down.png create mode 100644 assets/car_high.png create mode 100644 assets/car_up.png create mode 100644 assets/chart_bar_laggy.png create mode 100644 xmpp-link-previews.go diff --git a/assets.go b/assets.go index a3f23ce..dca5958 100644 --- a/assets.go +++ b/assets.go @@ -72,6 +72,9 @@ var disconnectBytes []byte //go:embed assets/chart_bar.png var barBytes []byte +//go:embed assets/chart_bar_laggy.png +var barLaggyBytes []byte + //go:embed assets/ok.png var okBytes []byte @@ -90,6 +93,47 @@ var informationBytes []byte //go:embed assets/car.png var carBytes []byte +//go:embed assets/car_high.png +var carHighBytes []byte + +// muc icons + +//go:embed assets/muc_open.png +var mucOpenBytes []byte + +//go:embed assets/muc_membersonly.png +var mucMembersOnlyBytes []byte + +//go:embed assets/muc_passwordprotected.png +var mucPasswordProtectedBytes []byte + +//go:embed assets/muc_unsecured.png +var mucUnsecuredBytes []byte + +//go:embed assets/muc_hidden.png +var mucHiddenBytes []byte + +//go:embed assets/muc_public.png +var mucPublicBytes []byte + +//go:embed assets/muc_unmoderated.png +var mucUnmoderatedBytes []byte + +//go:embed assets/muc_moderated.png +var mucModeratedBytes []byte + +//go:embed assets/muc_nonanonymous.png +var mucNonAnonymousBytes []byte + +//go:embed assets/muc_semianonymous.png +var mucSemiAnonymousBytes []byte + +//go:embed assets/muc_persistent.png +var mucPersistentBytes []byte + +//go:embed assets/muc_temporary.png +var mucTemporaryBytes []byte + func init() { loader := gdkpixbuf.NewPixbufLoader() @@ -212,6 +256,13 @@ func init() { loader = gdkpixbuf.NewPixbufLoader() + loader.Write(barLaggyBytes) + loader.Close() + + clientAssets["chart_bar_laggy"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(okBytes) loader.Close() @@ -286,4 +337,84 @@ func init() { loader.Close() clientAssets["car"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + + loader.Write(carHighBytes) + loader.Close() + + clientAssets["car_high"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + + loader.Write(mucOpenBytes) + loader.Close() + + clientAssets["muc_open"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucMembersOnlyBytes) + loader.Close() + + clientAssets["muc_membersonly"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucPasswordProtectedBytes) + loader.Close() + + clientAssets["muc_passwordprotected"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucUnsecuredBytes) + loader.Close() + + clientAssets["muc_unsecured"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucHiddenBytes) + loader.Close() + + clientAssets["muc_hidden"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucPublicBytes) + loader.Close() + + clientAssets["muc_public"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucUnmoderatedBytes) + loader.Close() + + clientAssets["muc_unmoderated"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucModeratedBytes) + loader.Close() + + clientAssets["muc_moderated"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucNonAnonymousBytes) + loader.Close() + + clientAssets["muc_nonanonymous"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucSemiAnonymousBytes) + loader.Close() + + clientAssets["muc_semianonymous"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucPersistentBytes) + loader.Close() + + clientAssets["muc_persistent"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) + + loader = gdkpixbuf.NewPixbufLoader() + loader.Write(mucTemporaryBytes) + loader.Close() + + clientAssets["muc_temporary"] = gdk.NewTextureForPixbuf(loader.Pixbuf()) } diff --git a/assets/car_down.png b/assets/car_down.png new file mode 100644 index 0000000000000000000000000000000000000000..24ceb57ac16be06e67d5c91731261236c00b46fc GIT binary patch literal 656 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU5V0SwEl z8uu_TFmM)lL>4nJ@ErnSMo|r~1_lNO$r9IylHmNblJdl&REB`W%)AmkKi3ciQ$0gH zLnC2E_YwvMh8?L9o@t(*S_~Wv3=FIcQjDw&j0_A6UJMKj(oi-i_%s-q!QxB|3=D>h zObmhy3=B~W3=Em=EMV~*1_=06#>nu3nSlXDqua{Bz|6offt`Vcfq}um$k>2!0mNL8 zovaHWW=(?_#lXbC$iM_v8Dwd}z{CL6WoTdkQqWwlFH>~k@_hydh8|BB#}JKR-~QV| zO$Gwa!5cLMy;n!*haNcn@4tT5?TMTCttT6Mrill!b!0D`dPvA&?J6!-hqaHFL|lt{ z9d*65Fky49lnT3NSHksezppqZ_bgnn`C8fozH@;EZ+_b~PyTL~7R1I6r6WjRuxqi=o8^8W@`pysL_^taTy_n|g-v)A{r>mdKI;Vst E0K{79m;e9( literal 0 HcmV?d00001 diff --git a/assets/car_high.png b/assets/car_high.png new file mode 100644 index 0000000000000000000000000000000000000000..132a097d7e1b730f8b4ae648cdff5701ccc5fa84 GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU-L15RjOeSEA?V8lqsTXQ*drB+Teu!oa|= zBQ?S^&C^qhfrEj8ft5juk(Ggwfq}t`fq_99$_6=GgOM35&cwjLV93bCAjrVL5XHd2 zklD@x7S91Wj)8&UQyC+}3uXk3ZYu)=GXui}b_Ny(1_lEoV*|zo5OYCxvMzv_H4SPO z69Xdy6If-Cr3C{M15}rxfdNQCbG^Py(S^(R85kIRJY5_^G=f|Ey@ePQIGkGF)jvPR z|3pt*GoNjX#d@Vrky0JJOdd%AQX01}J(apNjc?sIBa_<3Iex1%HZA==@$uDvEawbn f#J@bSFKE&phOdmbb_sdz1KHu}>gTe~DWM4f=8|ae literal 0 HcmV?d00001 diff --git a/assets/car_up.png b/assets/car_up.png new file mode 100644 index 0000000000000000000000000000000000000000..28a85475232fc3e53fb0c0c7a2defec137a01074 GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QUpc>6XME{wE6%4|6A_=-*WH&#Pk0ro&TSA;D7Fc|9SiWFT3&I zd*gqfjsF7z0#3j9ue0R8&f@>NOaA}-`SZxL|3WkW3(fd1Jmdexix&?(`Oh%n|FL7o zcJAD{W58Kf9l85kKD7`zx57^I^XbGK0mL7#J7~8JQRa85kI% zK!MZF0v698hC3=IrGvd#7SGDR0I-)CT8==5}P4ABVo?Y}L=q{!pk+`VSk z$0l(Wmy7@YyK5P2y4`;6iO-}=#m@|>x?6%Gm{wdhNMH+ydcAes#$~;RizUrBGvB^z zve3#Sh~@X;k0I6>YqyHb(Z3$ee9qGS;N9x`4jhV8d~_Qod=yO1%zRp+w{(iv3dV<@ sLzh{*%qTurAM5}8_vO;xOU?fs5Z7Uo2)UtUR|9gOr>mdKI;Vst087i~egFUf literal 0 HcmV?d00001 diff --git a/assets/chart_bar_laggy.png b/assets/chart_bar_laggy.png new file mode 100644 index 0000000000000000000000000000000000000000..51a9da10f5a51d169bc642954b5889156e7e562b GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4rT@h1`S>QU!K#4Mt|LI1>W{gCQdmgCGL~Llgr8 zLuNY*SUd;hI0goW1dxxAXmnc{7?>FtCa^QGFfcF}7#SNdE`XQ|vXgZI#H?vhvzQnd z8JNH-gDfo=m>8hC3=IrG3T`f+HTC3n?sx_U1~X3=#}JL+sf{dAj 100 { + sIcon.SetFromPaintable(clientAssets["car_high"]) + } else { + sIcon.SetFromPaintable(clientAssets["car"]) + } + sStatus.SetText(fmt.Sprintf("%.2fKB/s", diff)) oldsize = stat.Size() } }() + connectionStatus.SetText(fmt.Sprintf("Connected as %s", JidMustParse(clientroot.Session.BindJid).Bare())) connectionStatus.SetTooltipText(fmt.Sprintf("Binded JID: %s\nUsing TLS: %t", clientroot.Session.BindJid, clientroot.Session.TlsEnabled)) connectionIcon.SetFromPaintable(clientAssets["connect"]) @@ -514,15 +527,24 @@ func main() { jid := item.Id node := item.Any autojoin := false + name := "" for _, attr := range node.Attrs { if attr.Name.Local == "autojoin" { autojoin = attr.Value == "true" + break + } + } + + for _, attr := range node.Attrs { + if attr.Name.Local == "name" { + name = attr.Value + break } } _, ok := tabs.Load(jid) if !ok && autojoin { - createTab(jid, true) + createTab(jid, true, name) b := gtk.NewLabel(jid) gesture1 := gtk.NewGestureClick() gesture1.SetButton(1) @@ -544,17 +566,19 @@ func main() { for _, attr := range node.Attrs { if attr.Name.Local == "autojoin" { autojoin = attr.Value == "true" + break } } for _, node := range node.Nodes { if node.XMLName.Local == "nick" { nick = node.Content + break } } if autojoin { - err := joinMuc(client, clientroot.Session.BindJid, jid, nick) + err := joinMuc(client, clientroot.Session.BindJid, jid, nick, "") if err != nil { panic(err) } @@ -707,9 +731,11 @@ func activate(app *gtk.Application) { box := gtk.NewBox(gtk.OrientationVertical, 0) jid_box := gtk.NewBox(gtk.OrientationHorizontal, 0) nick_box := gtk.NewBox(gtk.OrientationHorizontal, 0) + disco_box := gtk.NewBox(gtk.OrientationHorizontal, 0) jid_entry := gtk.NewEntry() nick_entry := gtk.NewEntry() + disco_check := gtk.NewCheckButton() jid_entry.SetHAlign(gtk.AlignEnd) jid_entry.SetHExpand(true) @@ -725,8 +751,14 @@ func activate(app *gtk.Application) { nick_box.Append(gtk.NewLabel("Nick:")) nick_box.Append(nick_entry) + disco_check.SetActive(true) + disco_box.Append(gtk.NewLabel("Check MUC features before joining")) + disco_box.Append(disco_check) + disco_box.SetTooltipText("If you are creating a MUC through this window then turn this off") + box.Append(jid_box) box.Append(nick_box) + box.Append(disco_box) btn := gtk.NewButtonWithLabel("Submit") btn.SetVAlign(gtk.AlignBaseline) @@ -742,14 +774,14 @@ func activate(app *gtk.Application) { btn.ConnectClicked(func() { t := jid_entry.Text() _, ok := tabs.Load(t) - jm := func() { - - err := joinMuc(client, clientroot.Session.BindJid, t, nick_entry.Text()) + jm := func(n string, pw string) { + err := joinMuc(client, clientroot.Session.BindJid, t, nick_entry.Text(), pw) if err != nil { - panic(err) + showErrorDialog(err) + return } - createTab(t, true) + createTab(t, true, n) b := gtk.NewLabel(t) gesture1 := gtk.NewGestureClick() gesture1.SetButton(1) @@ -761,7 +793,14 @@ func activate(app *gtk.Application) { menu.Append(b) } if !ok { - // First check the MUC's disco and see if it's semianon + + if !disco_check.Active() { + jm(t, "") + win.SetVisible(false) + return + } + + var res *stanza.DiscoInfo allowed := true fmt.Println("Attempting to get Disco info") @@ -783,55 +822,137 @@ func activate(app *gtk.Application) { mychan, err := client.SendIQ(ctx, myIQ) if err == nil { result := <-mychan - res, ok := result.Payload.(*stanza.DiscoInfo) + res, ok = result.Payload.(*stanza.DiscoInfo) if ok { - semianon := false features := res.Features + allowed = false + password_protected := false + password := "" + warning_win := gtk.NewWindow() + warning_win.SetTitle(fmt.Sprintf("Joining %s", res.Identity[0].Name)) + warning_win.SetDefaultSize(400, 400) + warning_win.SetResizable(false) + + buttons := gtk.NewBox(gtk.OrientationHorizontal, 0) + join_button := gtk.NewButtonWithLabel("Join") + join_button.ConnectClicked(func() { + warning_win.SetVisible(false) + if password_protected { + allowed = false + + password_win := gtk.NewWindow() + password_win.SetTitle("Password required") + password_win.SetDefaultSize(400, 1) + password_win.SetResizable(false) + box := gtk.NewBox(gtk.OrientationVertical, 0) + en := gtk.NewEntry() + en.SetPlaceholderText("Password") + submit := gtk.NewButtonWithLabel("Submit") + submit.ConnectClicked(func() { + password = en.Text() + jm(res.Identity[0].Name, password) + password_win.SetVisible(false) + }) + box.Append(en) + box.Append(submit) + password_win.SetChild(box) + password_win.SetVisible(true) + } + + jm(res.Identity[0].Name, password) + }) + + cancel_button := gtk.NewButtonWithLabel("Cancel") + cancel_button.ConnectClicked(func() { + warning_win.SetVisible(false) + }) + + buttons.Append(join_button) + buttons.Append(cancel_button) + warning_box := gtk.NewBox(gtk.OrientationVertical, 0) + header := gtk.NewLabel(res.Identity[0].Name) + warning_box.Append(header) for _, feature := range features { - if feature.Var == "muc_nonanonymous" { - semianon = false - break - } else if feature.Var == "muc_semianonymous" { - semianon = true - break + switch feature.Var { + case "muc_passwordprotected": + password_protected = true + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_passwordprotected"])) + box.Append(gtk.NewLabel("This MUC is password-protected")) + warning_box.Append(box) + case "muc_unsecured": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_unsecured"])) + box.Append(gtk.NewLabel("This MUC does not require a password")) + warning_box.Append(box) + case "muc_membersonly": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_membersonly"])) + box.Append(gtk.NewLabel("Only members can join this MUC")) + warning_box.Append(box) + case "muc_open": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_open"])) + box.Append(gtk.NewLabel("Anyone can join this MUC")) + warning_box.Append(box) + case "muc_moderated": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_moderated"])) + box.Append(gtk.NewLabel("Only members can speak in this MUC")) + warning_box.Append(box) + case "muc_unmoderated": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_unmoderated"])) + box.Append(gtk.NewLabel("Anyone can speak in this MUC")) + warning_box.Append(box) + case "muc_nonanonymous": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_nonanonymous"])) + box.Append(gtk.NewLabel("This MUC is non-anonymous, your JID will be visible to other users")) + warning_box.Append(box) + case "muc_semianonymous": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_semianonymous"])) + box.Append(gtk.NewLabel("This MUC is semi-anonymous, only moderators will see your full JID")) + warning_box.Append(box) + case "muc_persistent": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_persistent"])) + box.Append(gtk.NewLabel("This MUC is persistent, it will not be deleted when the last user leaves")) + warning_box.Append(box) + case "muc_temporary": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_temporary"])) + box.Append(gtk.NewLabel("This MUC is temporary, it will be deleted when the last user leaves")) + warning_box.Append(box) + case "muc_public": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_public"])) + box.Append(gtk.NewLabel("This MUC can be found in directories and search engines")) + warning_box.Append(box) + case "muc_hidden": + box := gtk.NewBox(gtk.OrientationHorizontal, 0) + box.Append(gtk.NewImageFromPaintable(clientAssets["muc_hidden"])) + box.Append(gtk.NewLabel("This MUC is hidden and cannot be found in directories or search engines")) + warning_box.Append(box) } } - if !semianon { - allowed = false - warning_win := gtk.NewWindow() - warning_win.SetTitle("Warning") - warning_win.SetDefaultSize(400, 400) - warning_win.SetResizable(false) - - warning_box := gtk.NewBox(gtk.OrientationVertical, 0) - warning_label := gtk.NewLabel("This muc is not semi-anonymous. Your JID will be revealed to non-moderators if you join. Continue?") - - buttons := gtk.NewBox(gtk.OrientationHorizontal, 0) - join_button := gtk.NewButtonWithLabel("Join") - join_button.ConnectClicked(func() { - warning_win.SetVisible(false) - jm() - }) - - cancel_button := gtk.NewButtonWithLabel("Cancel") - cancel_button.ConnectClicked(func() { - warning_win.SetVisible(false) - }) - - buttons.Append(join_button) - buttons.Append(cancel_button) - - warning_box.Append(warning_label) - warning_box.Append(buttons) - warning_win.SetChild(warning_box) - warning_win.Present() + warning_box.Append(buttons) + warning_win.SetChild(warning_box) + warning_win.Present() + } else { + allowed = false + if result.Error != nil { + showErrorDialog(fmt.Errorf("Failed to get disco info: %s - %s", result.Error.Reason, result.Error.Text)) + } else { + showErrorDialog(fmt.Errorf("Failed to get disco info")) } } } if allowed { - jm() + jm(res.Identity[0].Name, "") } } win.SetVisible(false) diff --git a/style.css b/style.css index 5d59713..9e7dbe8 100644 --- a/style.css +++ b/style.css @@ -73,3 +73,10 @@ .None_CVD { } + +.link_preview { + color: white; + background-color: grey; + border-radius: 5px; + padding: 5px; +} diff --git a/types.go b/types.go index ad2bbcf..f38ba64 100644 --- a/types.go +++ b/types.go @@ -9,6 +9,7 @@ import ( type chatTab struct { isMuc bool msgs *gtk.ListBox + name string } type lambdaConfig struct { @@ -21,6 +22,7 @@ type lambdaConfig struct { JoinBookmarks bool CVD color.CVD Identicons bool + Debug bool } type mucUnit struct { diff --git a/version.go b/version.go index 29bd199..d1f4ba5 100644 --- a/version.go +++ b/version.go @@ -1,3 +1,3 @@ package main -var lambda_version string = "26w15a" +var lambda_version string = "26w17a" diff --git a/xmpp-helpers.go b/xmpp-helpers.go index 24b946d..211f58c 100644 --- a/xmpp-helpers.go +++ b/xmpp-helpers.go @@ -28,17 +28,32 @@ func sendMessage(c xmpp.Sender, sendTo string, msgType stanza.StanzaType, body s } // Joins a MUC -func joinMuc(c xmpp.Sender, jid string, muc string, nick string) error { +func joinMuc(c xmpp.Sender, jid string, muc string, nick string, password string) error { + var joinPresence stanza.Presence addr := muc + "/" + nick fmt.Println(addr) - joinPresence := stanza.Presence{ - Attrs: stanza.Attrs{ - From: jid, - To: addr, - }, - Extensions: []stanza.PresExtension{ - &stanza.MucPresence{}, - }, + if password == "" { + joinPresence = stanza.Presence{ + Attrs: stanza.Attrs{ + From: jid, + To: addr, + }, + Extensions: []stanza.PresExtension{ + &stanza.MucPresence{}, + }, + } + } else { + joinPresence = stanza.Presence{ + Attrs: stanza.Attrs{ + From: jid, + To: addr, + }, + Extensions: []stanza.PresExtension{ + &stanza.MucPresence{ + Password: password, + }, + }, + } } err := client.Send(joinPresence) diff --git a/xmpp-link-previews.go b/xmpp-link-previews.go new file mode 100644 index 0000000..8e50b7a --- /dev/null +++ b/xmpp-link-previews.go @@ -0,0 +1,20 @@ +package main + +import ( + "encoding/xml" + "gosrc.io/xmpp/stanza" +) + +type LinkPreview struct { + stanza.MsgExtension + XMLName xml.Name `xml:"http://www.w3.org/1999/02/22-rdf-syntax-ns# Description"` + About string `xml:"https://ogp.me/ns#,attr"` + Title string `xml:"https://ogp.me/ns# title"` + Description string `xml:"https://ogp.me/ns# description"` + Image string `xml:"https://ogp.me/ns# image"` + URL string `xml:"https://ogp.me/ns# url"` +} + +func init() { + stanza.TypeRegistry.MapExtension(stanza.PKTMessage, xml.Name{Space: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", Local: "Description"}, LinkPreview{}) +}