Repository: profanity-im/profanity (c)

Issue:
OMEMO QR code is not compatible with conversations 
Profanity creates a QR with content in the form `xmpp:user@example.org?omemo-sid-1032437584=67214ab8-a25fd7a9-44ed1ea6-4276f18d-ff92fae9-23f8ebab-5b218d0d-4ceedc4` which doesn't work with conversations. Removing the dashes makes it work: `xmpp:user@example.org?omemo-sid-1032437584=67214ab8a25fd7a944ed1ea64276f18dff92fae923f8ebab5b218d0d4ceedc4`

The XEP refers to [RFC7748](https://www.rfc-editor.org/rfc/rfc7748) which also doesn't show dashes in fingerprints.

<!--- More than 50 issues open? Please don't file any new feature requests -->
<!--- Help us reduce the work first :-) -->

## Expected Behavior
Fingerprint is verified in conversations after scanning QR code.

## Current Behavior
Fingerprint is not verified in conversations after scanning QR code.

## Possible Solution
Remove dashes from fingerprint.

## Environment
Debian bookworm

```
profanity -v              
Profanity, version 0.13.1
Copyright (C) 2012 - 2019 James Booth <boothj5web@gmail.com>.
Copyright (C) 2019 - 2022 Michael Vetter <jubalh@iodoru.org>.
License GPLv3+: GNU GPL version 3 or later <https://www.gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Build information:
XMPP library: libstrophe
Desktop notification support: Enabled
OTR support: Enabled (libotr 4.1.1)
PGP support: Enabled (libgpgme 1.18.0)
OMEMO support: Enabled
C plugins: Enabled
Python plugins: Enabled (3.11.2)
GTK icons/clipboard: Enabled
GDK Pixbuf: Enabled
```



Discussion:

Patch:
diff --git a/src/common.c b/src/common.c
--- a/src/common.c
+++ b/src/common.c
@@ -355,33 +355,32 @@ prof_occurrences(const char* const needle, const char* const haystack, int offse
         return *result;
     }
 
-    gchar* haystack_curr = g_utf8_offset_to_pointer(haystack, offset);
-    if (g_str_has_prefix(haystack_curr, needle)) {
-        if (whole_word) {
-            gunichar before = 0;
-            gchar* haystack_before_ch = g_utf8_find_prev_char(haystack, haystack_curr);
-            if (haystack_before_ch) {
-                before = g_utf8_get_char(haystack_before_ch);
-            }
-
-            gunichar after = 0;
-            gchar* haystack_after_ch = haystack_curr + strlen(needle);
-            if (haystack_after_ch[0] != '\0') {
-                after = g_utf8_get_char(haystack_after_ch);
-            }
-
-            if (!g_unichar_isalnum(before) && !g_unichar_isalnum(after)) {
+    do {
+        gchar* haystack_curr = g_utf8_offset_to_pointer(haystack, offset);
+        if (g_str_has_prefix(haystack_curr, needle)) {
+            if (whole_word) {
+                gunichar before = 0;
+                gchar* haystack_before_ch = g_utf8_find_prev_char(haystack, haystack_curr);
+                if (haystack_before_ch) {
+                    before = g_utf8_get_char(haystack_before_ch);
+                }
+
+                gunichar after = 0;
+                gchar* haystack_after_ch = haystack_curr + strlen(needle);
+                if (haystack_after_ch[0] != '\0') {
+                    after = g_utf8_get_char(haystack_after_ch);
+                }
+
+                if (!g_unichar_isalnum(before) && !g_unichar_isalnum(after)) {
+                    *result = g_slist_append(*result, GINT_TO_POINTER(offset));
+                }
+            } else {
                 *result = g_slist_append(*result, GINT_TO_POINTER(offset));
             }
-        } else {
-            *result = g_slist_append(*result, GINT_TO_POINTER(offset));
         }
-    }
 
-    offset++;
-    if (g_strcmp0(g_utf8_offset_to_pointer(haystack, offset), "\0") != 0) {
-        *result = prof_occurrences(needle, haystack, offset, whole_word, result);
-    }
+        offset++;
+    } while (g_strcmp0(g_utf8_offset_to_pointer(haystack, offset), "\0") != 0);
 
     return *result;
 }
diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c
--- a/src/omemo/omemo.c
+++ b/src/omemo/omemo.c
@@ -1920,7 +1920,7 @@ char*
 omemo_qrcode_str()
 {
     char* mybarejid = connection_get_barejid();
-    char* fingerprint = omemo_own_fingerprint(TRUE);
+    char* fingerprint = omemo_own_fingerprint(FALSE);
     uint32_t sid = omemo_device_id();
 
     char* qrstr = g_strdup_printf("xmpp:%s?omemo-sid-%d=%s", mybarejid, sid, fingerprint);
diff --git a/src/ui/console.c b/src/ui/console.c
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -915,10 +915,12 @@ cons_show_qrcode(const char* const text)
         strcat(pad, "\u2588\u2588");
     }
 
-    win_println(console, THEME_DEFAULT, "", pad);
+    win_println(console, THEME_DEFAULT, "", "");
+    win_println(console, THEME_DEFAULT, "", "");
+    win_println(console, THEME_DEFAULT, "", "%s", pad);
     for (size_t y = 0; y < width; y += ZOOM_SIZE) {
         for (size_t x = 0; x < width; x += ZOOM_SIZE) {
-            strcat(buf, !(*data & 1) ? "\u2588\u2588" : "\u2800\u2800");
+            strcat(buf, !(*data & 1) ? "\u2588\u2588" : "  ");
 
             data++;
         }
@@ -929,6 +931,8 @@ cons_show_qrcode(const char* const text)
         buf[0] = '\0';
     }
     win_println(console, THEME_DEFAULT, "", "%s", pad);
+    win_println(console, THEME_DEFAULT, "", "");
+    win_println(console, THEME_DEFAULT, "", "");
 
     free(pad);
     free(buf);
diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c
--- a/src/xmpp/connection.c
+++ b/src/xmpp/connection.c
@@ -847,8 +847,6 @@ connection_set_priority(const int priority)
     conn.priority = priority;
 }
 
-#if defined(LIBXMPP_VERSION_MAJOR) && defined(LIBXMPP_VERSION_MINOR) \
-    && ((LIBXMPP_VERSION_MAJOR > 0) || (LIBXMPP_VERSION_MINOR >= 12))
 static xmpp_stanza_t*
 _get_soh_error(xmpp_stanza_t* error_stanza)
 {
@@ -857,19 +855,6 @@ _get_soh_error(xmpp_stanza_t* error_stanza)
                                          XMPP_STANZA_NAME_IN_NS("see-other-host", STANZA_NS_XMPP_STREAMS),
                                          NULL);
 }
-#else
-static xmpp_stanza_t*
-_get_soh_error(xmpp_stanza_t* error_stanza)
-{
-    const char* name = xmpp_stanza_get_name(error_stanza);
-    const char* ns = xmpp_stanza_get_ns(error_stanza);
-    if (!name || !ns || strcmp(name, "error") || strcmp(ns, STANZA_NS_STREAMS)) {
-        log_debug("_get_soh_error: could not find error stanza");
-        return NULL;
-    }
-    return xmpp_stanza_get_child_by_name_and_ns(error_stanza, "see-other-host", STANZA_NS_XMPP_STREAMS);
-}
-#endif
 
 #if GLIB_CHECK_VERSION(2, 66, 0)
 static gboolean
@@ -878,12 +863,8 @@ _split_url(const char* alturi, gchar** host, gint* port)
     /* Construct a valid URI with `schema://` as `g_uri_split_network()`
      * requires this to be there.
      */
-    const char* xmpp = "xmpp://";
-    char* xmpp_uri = _xmalloc(strlen(xmpp) + strlen(alturi) + 1, NULL);
-    memcpy(xmpp_uri, xmpp, strlen(xmpp));
-    memcpy(xmpp_uri + strlen(xmpp), alturi, strlen(alturi) + 1);
+    auto_gchar gchar* xmpp_uri = g_strdup_printf("xmpp://%s", alturi);
     gboolean ret = g_uri_split_network(xmpp_uri, 0, NULL, host, port, NULL);
-    free(xmpp_uri);
     /* fix-up `port` as g_uri_split_network() sets port to `-1` if it's missing
      * in the passed-in URI, but libstrophe expects a "missing port"
      * to be passed as `0` (which then results in connecting to the standard port).


Test patch:
diff --git a/tests/unittests/test_common.c b/tests/unittests/test_common.c
--- a/tests/unittests/test_common.c
+++ b/tests/unittests/test_common.c
@@ -535,6 +535,28 @@ _lists_equal(GSList* a, GSList* b)
     return TRUE;
 }
 
+void
+prof_occurrences_of_large_message_tests(void** state)
+{
+    GSList* actual = NULL;
+    GSList* expected = NULL;
+    /* use this with the old implementation to create a segfault
+     *     const size_t haystack_sz = 1024 * 1024;
+     */
+    const size_t haystack_sz = 1024;
+    size_t haystack_cur = 0;
+    char* haystack = malloc(haystack_sz);
+    const char needle[] = "needle ";
+    while (haystack_sz - haystack_cur > sizeof(needle)) {
+        memcpy(&haystack[haystack_cur], needle, sizeof(needle) - 1);
+        expected = g_slist_append(expected, GINT_TO_POINTER(haystack_cur));
+        haystack_cur += sizeof(needle) - 1;
+    }
+    assert_true(_lists_equal(prof_occurrences("needle", haystack, 0, FALSE, &actual), expected));
+    g_slist_free(actual);
+    g_slist_free(expected);
+}
+
 void
 prof_partial_occurrences_tests(void** state)
 {
diff --git a/tests/unittests/test_common.h b/tests/unittests/test_common.h
--- a/tests/unittests/test_common.h
+++ b/tests/unittests/test_common.h
@@ -31,5 +31,6 @@ void strip_quotes_strips_last(void** state);
 void strip_quotes_strips_both(void** state);
 void prof_partial_occurrences_tests(void** state);
 void prof_whole_occurrences_tests(void** state);
+void prof_occurrences_of_large_message_tests(void** state);
 void unique_filename_from_url_td(void** state);
 void format_call_external_argv_td(void** state);
diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c
--- a/tests/unittests/unittests.c
+++ b/tests/unittests/unittests.c
@@ -620,6 +620,7 @@ main(int argc, char* argv[])
 
         unit_test(prof_partial_occurrences_tests),
         unit_test(prof_whole_occurrences_tests),
+        unit_test(prof_occurrences_of_large_message_tests),
 
         unit_test(returns_no_commands),
         unit_test(returns_commands),