Package: dino-im
Version: 0.3.0-2~bpo11+1
Severity: wishlist
Tags: patch

I authored a patch that resolves XMPP links (ie, xmpp:f...@bar.com) in messages, if the body of the XMPP link match a user in the roster. The upstream pull request is here - https://github.com/dino/dino/pull/1212 Upstream hasn't commented on the patch yet, and I'm trying to get it upstream, but in the meantime I'd love to see it included in Debian.

I've been personally using this patch for 5 months now, and have had no stability problems. If an XMPP link matches a user in the roster, a roster contact display name is shown. If it doesn't match a roster user, nothing is changed. It's not entirely complete (xmpp links in notifications aren't resolved to roster names, for example), but it makes using Dino with 3rd party services that use XMPP links a whole lot nicer.

Please consider including it. I've attached the patch that I included in my own builds at https://people.debian.org/~dilinger/dino-im/ , if that's helpful.

>From ec2e6192d6cf01ab57326ac4cc9ffc99eae89f95 Mon Sep 17 00:00:00 2001
From: Andres Salomon <dilin...@queued.net>
Date: Sat, 12 Mar 2022 17:23:14 -0500
Subject: [PATCH] Display friendlier xmpp: links when a jid is in the roster

In jabber chats, there may be cases where an xmpp link is a valid
jid that's in an account's roster. For example, Cheogram's jmp.chat
service uses xmpp: links to support SMS group chat over jabber. In
jmp.chat's case, that ends up looking like a message coming from a
jid that has combined multiple phone numbers with the format
"+11231231234,+13213214...@cheogram.com", and message body beginning
with "<xmpp:+111231231...@cheogram.com> " or
"<xmpp:+13213214...@cheogram.com> " (depending on which phone number
the message is coming from).

Those jids aren't particularly user-friendly, so we'd instead like to
display the roster name while still keeping the underlying link
clickable. In order to do that, we modify Util.parse_add_markup_theme()
(since that's where the <a> html tag markup is created) to add a
callback function that takes a uri and returns what the <a> tag
should display. If the callback returns null, we just stick with the
default behavior of just displaying the link. However, if the uri
includes a jid that's in the user's roster, we return the name that's
in the roster. Util.parse_add_markup_theme() then uses that returned
name in the <a> tag.

A callback is used in order to keep the lookup generic, for future
uses. While the call to Util.parse_add_markup_theme() inside of
MessageItemWidget::generate_markup_text()'s non-muc code has a
callback that specifically only checks for xmpp: links, there's no
reason that it needs to be limited to that. It could handle any link;
for example, translating an http:// link to that same link but with
" (insecure)" appended to the end.
---
 .../message_widget.vala                       | 12 ++++++-
 main/src/ui/util/helper.vala                  | 31 ++++++++++++-------
 2 files changed, 31 insertions(+), 12 deletions(-)

--- a/main/src/ui/conversation_content_view/message_widget.vala
+++ b/main/src/ui/conversation_content_view/message_widget.vala
@@ -200,7 +200,17 @@ public class MessageItemWidget : SizeReq
         if (conversation.type_ == Conversation.Type.GROUPCHAT) {
             markup_text = Util.parse_add_markup_theme(markup_text, conversation.nickname, true, true, true, Util.is_dark_theme(this), ref theme_dependent);
         } else {
-            markup_text = Util.parse_add_markup_theme(markup_text, null, true, true, true, Util.is_dark_theme(this), ref theme_dependent);
+            Util.LinkDisplay roster_lookup = (uri) => {
+                string? s = null;
+                if (GLib.Uri.parse_scheme(uri) == "xmpp") {
+                    try {
+                        Jid? j = new Jid(uri["xmpp:".length:uri.length]);
+                        s = Dino.get_real_display_name(stream_interactor, conversation.account, j);
+                    } catch (InvalidJidError e) { /* it's fine */ }
+                }
+                return s;
+            };
+            markup_text = Util.parse_add_markup_theme(markup_text, null, true, true, true, Util.is_dark_theme(this), ref theme_dependent, false, roster_lookup);
         }
 
         if (message.body.has_prefix("/me ")) {
--- a/main/src/ui/util/helper.vala
+++ b/main/src/ui/util/helper.vala
@@ -242,7 +242,9 @@ public static string parse_add_markup(st
     return parse_add_markup_theme(s_, highlight_word, parse_links, parse_text_markup, parse_text_markup, false, ref ignore_out_var);
 }
 
-public static string parse_add_markup_theme(string s_, string? highlight_word, bool parse_links, bool parse_text_markup, bool parse_quotes, bool dark_theme, ref bool theme_dependent, bool already_escaped_ = false) {
+public delegate string? LinkDisplay(string uri);
+
+public static string parse_add_markup_theme(string s_, string? highlight_word, bool parse_links, bool parse_text_markup, bool parse_quotes, bool dark_theme, ref bool theme_dependent, bool already_escaped_ = false, LinkDisplay? lookup = null) {
     string s = s_;
     bool already_escaped = already_escaped_;
 
@@ -258,9 +260,9 @@ public static string parse_add_markup_th
 
             theme_dependent = true;
             quote_match_info.fetch_pos(0, out start, out end);
-            return parse_add_markup_theme(s[0:start], highlight_word, parse_links, parse_text_markup, parse_quotes, dark_theme, ref theme_dependent, already_escaped) +
-                    @"<span color='$dim_color'>$gt " + parse_add_markup_theme(s[start + gt.length + 1:end], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped) + "</span>" +
-                    parse_add_markup_theme(s[end:s.length], highlight_word, parse_links, parse_text_markup, parse_quotes, dark_theme, ref theme_dependent, already_escaped);
+            return parse_add_markup_theme(s[0:start], highlight_word, parse_links, parse_text_markup, parse_quotes, dark_theme, ref theme_dependent, already_escaped, lookup) +
+                    @"<span color='$dim_color'>$gt " + parse_add_markup_theme(s[start + gt.length + 1:end], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup) + "</span>" +
+                    parse_add_markup_theme(s[end:s.length], highlight_word, parse_links, parse_text_markup, parse_quotes, dark_theme, ref theme_dependent, already_escaped, lookup);
         }
     }
 
@@ -304,11 +306,18 @@ public static string parse_add_markup_th
                     }
                 }
 
-                return parse_add_markup_theme(s[0:start], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped) +
+                // Change how links are displayed?
+                string? disp_name = lookup != null ? lookup(link) : null;
+                if (disp_name == null) {
+                    // Default to the link name
+                    disp_name = link;
+                }
+
+                return parse_add_markup_theme(s[0:start], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup) +
                         "<a href=\"" + Markup.escape_text(link) + "\">" +
-                        parse_add_markup_theme(link, highlight_word, false, false, false, dark_theme, ref theme_dependent, already_escaped) +
+                        parse_add_markup_theme(disp_name, highlight_word, false, false, false, dark_theme, ref theme_dependent, already_escaped, lookup) +
                         "</a>" +
-                        parse_add_markup_theme(s[end:s.length], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped);
+                        parse_add_markup_theme(s[end:s.length], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup);
             }
             match_info.next();
         }
@@ -327,9 +336,9 @@ public static string parse_add_markup_th
             if (match_info.matches()) {
                 int start, end;
                 match_info.fetch_pos(0, out start, out end);
-                return parse_add_markup_theme(s[0:start], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped) +
+                return parse_add_markup_theme(s[0:start], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup) +
                     "<b>" + s[start:end] + "</b>" +
-                    parse_add_markup_theme(s[end:s.length], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped);
+                    parse_add_markup_theme(s[end:s.length], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup);
             }
         } catch (RegexError e) {
             assert_not_reached();
@@ -349,11 +358,11 @@ public static string parse_add_markup_th
                 if (match_info.matches()) {
                     int start, end;
                     match_info.fetch_pos(2, out start, out end);
-                    return parse_add_markup_theme(s[0:start-1], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped) +
+                    return parse_add_markup_theme(s[0:start-1], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup) +
                         "<span color='#9E9E9E'>" +  s[start-1:start] + "</span>" +
                         @"<$(convenience_tag[i])>" + s[start:end] + @"</$(convenience_tag[i])>" +
                         "<span color='#9E9E9E'>" + s[end:end+1] + "</span>" +
-                        parse_add_markup_theme(s[end+1:s.length], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped);
+                        parse_add_markup_theme(s[end+1:s.length], highlight_word, parse_links, parse_text_markup, false, dark_theme, ref theme_dependent, already_escaped, lookup);
                 }
             } catch (RegexError e) {
                 assert_not_reached();

Reply via email to