@@ 4,5 4,6 @@ source "https://rubygems.org"
gem "blather", git: "https://github.com/adhearsion/blather", branch: "develop"
gem "glimmer-dsl-libui", "~> 0.5.24"
+gem "hsluv"
gem "sqlite3"
gem "xdg"
@@ 1,7 1,9 @@
# frozen_string_literal: true
+require "base64"
require "glimmer-dsl-libui"
require "blather/client"
+require "hsluv"
require "securerandom"
require "sqlite3"
require "xdg"
@@ 27,6 29,13 @@ end
BLATHER = self
include Glimmer
+set_caps(
+ "https://git.singpolyma.net/jabber-client-demo",
+ [],
+ ["urn:xmpp:avatar:metadata+notify"]
+)
+
+$avatars = {}
$conversations = {}
$roster = [["", ""]]
@@ 47,7 56,7 @@ class Conversation
def initialize(jid)
@jid = jid
- @messages = [["", ""]]
+ @messages = [[default_avatar(""), "", ""]]
EM.defer do
mam_messages = []
DB.execute(<<~SQL, [@jid]) do |row|
@@ 87,6 96,7 @@ class Conversation
vertical_box {
table {
+ image_column("Avatar")
text_column("Sender")
text_column("Message")
editable false
@@ 136,9 146,18 @@ class Conversation
BLATHER.my_roster[jid]&.name || jid
end
+ def default_avatar(string)
+ hue = (Digest::SHA1.digest(string).unpack1("v").to_f / 65536) * 360
+ rgb = Hsluv.rgb_prepare(Hsluv.hsluv_to_rgb(hue, 100, 50))
+ rgba = rgb.pack("CCC") + "\xff".b
+ image { image_part(rgba * 32 * 32, 32, 32, 4) }
+ end
+
def message_row(m)
+ from = m.from&.stripped || BLATHER.jid.stripped
[
- format_sender(m.from&.stripped || BLATHER.jid.stripped),
+ $avatars[from.to_s] || default_avatar(from.to_s),
+ format_sender(from),
m.body
]
end
@@ 286,6 305,8 @@ when_ready do
xml_child(iq, :enable, "urn:xmpp:carbons:2")
}
+ send_caps
+
last_mam_id = DB.execute(<<~SQL)[0]&.first
SELECT value FROM data WHERE key='last_mam_id' LIMIT 1
SQL
@@ 346,6 367,33 @@ message :body do |m|
handle_live_message(m)
end
+pubsub_event(
+ "//ns:items[@node='urn:xmpp:avatar:metadata']",
+ ns: "http://jabber.org/protocol/pubsub#event"
+) do |m|
+ id = m.items.first&.payload_node&.children&.first&.[]("id")
+ next $avatars.delete(m.from.stripped.to_s) unless id
+
+ path = DATA_DIR + id.to_s
+ key = m.from.stripped.to_s
+ if path.exist?
+ LibUI.queue_main { $avatars[key] = image(path.to_s, 32, 32) rescue nil }
+ else
+ write_with_handler(
+ Blather::Stanza::PubSub::Items.new(:get).tap { |iq|
+ iq.node = "urn:xmpp:avatar:data"
+ iq.to = m.from
+ }
+ ) do |reply|
+ next if reply.error?
+
+ data = Base64.decode64(reply.items.first&.payload_node&.text.to_s)
+ path.write(data)
+ LibUI.queue_main { $avatars[key] = image(path.to_s, 32, 32) rescue nil }
+ end
+ end
+end
+
after(:roster) do
LibUI.queue_main do
$roster.clear