# Ссылки в сообщениях Android и Qt распознают `http://`, `https://` и `utun://` в обычном тексте личных и групповых сообщений. HTTP/HTTPS нечувствительны к регистру схемы; `utun://` распознаётся только в нижнем регистре. Утилиты разбора не открывают ссылки. Ссылки выделяются цветом и подчёркиванием; длинные веб-адреса переносятся по ширине. Сокращённая строка структурированного PM-приглашения сохраняет полный `utun://` адрес. Пробелы, управляющие символы, кавычки и угловые скобки отделяют ссылку от текста. Конечные `. , ; : ! ?` и лишние закрывающие скобки удаляются из распознанного адреса. Сбалансированные скобки в адресе, параметры, fragment и Unicode сохраняются. Адреса без схемы не распознаются. Некорректные веб-адреса остаются обычным текстом. Исходное сообщение в БД и протоколе не меняется. У `utun://` распознаётся кандидат из обычного base64-алфавита с до двух конечных `=`. На этом этапе не проверяются версия, поля и содержимое приглашения: `utun://abc+/==` может получить подсветку, но быть отклонённым при открытии. Предпросмотр Qt и Android использует общий `src/chat/invite_link.c` через Qt-обёртку/JNI; принимается версия 0x03. Сам декодер не проверяет регистрацию/срок join_key и не даёт членства. Разборщики возвращают непересекающиеся диапазоны исходного текста в порядке появления и полные адреса в исходном написании: Qt — `start/length`, Android — `start/end`, где end исключён. Единицы обоих API — UTF-16: `tools/chatgui/src/message_links.cpp`, Android `data/MessageLinks.kt`. Удаление внешней пунктуации занимает линейное время: баланс трёх видов скобок считается один раз, хвост сокращается по индексу без повторного копирования адреса. Порт веб-адреса пустой либо десятичный от 0 до 65535; знак перед числом недопустим. Подсветка и нажатие используют эти диапазоны. Android подставляет emoji placeholders только в обычный текст между ссылками: emoji внутри адреса остаётся частью полного URL. Qt использует один QTextLayout для размеров, отрисовки, выделения и координат нажатия. Перетаскивание выделяет текст без открытия ссылки. HTTP/HTTPS открываются из GUI системным обработчиком: Android `ACTION_VIEW`, Qt `QDesktopServices::openUrl`. На нажатии веб-адрес снова проверяется. В Qt `utun://` сначала декодируется: уже существующая группа, где узел является участником, открывается без JOIN; иначе показывается JoinDialog с автоматической попыткой входа. На Android адрес передаётся в существующий invite/JOIN flow. Ошибки открытия показываются через перевод интерфейса и логируются. Диагностика открытия содержит схему и host, без полного пути/query. Общие случаи: `tools/chatgui/tests/message_links_cases.tsv`. Qt `test_invite_links` проверяет разбор, перенесённые веб-ссылки, смесь схем, нажатие, drag/copy и сокращённые приглашения; `test_emoji_playback` — жесты приглашений. Android `MessageLinksTest` проверяет тот же TSV через Gradle, некорректные authority и длинный хвост пунктуации. Аналогичный тест длинного хвоста есть в Qt. Оба разбора не открывают ссылки; некорректный пользовательский текст не создаёт логов. ```bash cd tools/chatgui-android ./gradlew :app:testDebugUnitTest --tests com.utun.chat.data.MessageLinksTest ``` `tests/test_message_links.kt` остаётся отдельным CLI-тестом того же TSV; ему передаётся путь к файлу, а в classpath нужны собранные классы `MessageLinks`.