diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 73814a433..95e6ca3a1 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -696,15 +696,16 @@ QString ApiWrap::exportDirectMessageLink( const auto base = linkChannel->hasUsername() ? linkChannel->username() : "c/" + QString::number(peerToChannel(linkChannel->id).bare); + const auto post = QString::number(linkItemId.bare); const auto query = base + '/' - + QString::number(linkItemId.bare) + (linkCommentId - ? "?comment=" + QString::number(linkCommentId.bare) + ? (post + "?comment=" + QString::number(linkCommentId.bare)) + : (linkThreadId && !linkThreadIsTopic) + ? (post + "?thread=" + QString::number(linkThreadId.bare)) : linkThreadId - ? ((linkThreadIsTopic ? "?topic=" : "?thread=") - + QString::number(linkThreadId.bare)) - : ""); + ? (QString::number(linkThreadId.bare) + '/' + post) + : post); if (linkChannel->hasUsername() && !linkChannel->isMegagroup() && !linkCommentId diff --git a/Telegram/SourceFiles/core/local_url_handlers.cpp b/Telegram/SourceFiles/core/local_url_handlers.cpp index 1a2895bb7..5f3bc644b 100644 --- a/Telegram/SourceFiles/core/local_url_handlers.cpp +++ b/Telegram/SourceFiles/core/local_url_handlers.cpp @@ -139,7 +139,7 @@ bool ShareUrl( auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); - auto url = params.value(qsl("url")); + auto url = params.value(u"url"_q); if (url.isEmpty()) { return false; } else { @@ -160,8 +160,8 @@ bool ConfirmPhone( const auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); - const auto phone = params.value(qsl("phone")); - const auto hash = params.value(qsl("hash")); + const auto phone = params.value(u"phone"_q); + const auto hash = params.value(u"hash"_q); if (phone.isEmpty() || hash.isEmpty()) { return false; } @@ -183,7 +183,7 @@ bool ShareGameScore( const auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); - ShareGameScoreByHash(controller, params.value(qsl("hash"))); + ShareGameScoreByHash(controller, params.value(u"hash"_q)); controller->window().activate(); return true; } @@ -265,16 +265,16 @@ bool ShowWallPaper( const auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); - const auto bg = params.value("bg_color"); - const auto color = params.value("color"); - const auto gradient = params.value("gradient"); + const auto bg = params.value(u"bg_color"_q); + const auto color = params.value(u"color"_q); + const auto gradient = params.value(u"gradient"_q); const auto result = BackgroundPreviewBox::Start( controller, (!color.isEmpty() ? color : !gradient.isEmpty() ? gradient - : params.value(qsl("slug"))), + : params.value(u"slug"_q)), params); controller->window().activate(); return result; @@ -283,7 +283,7 @@ bool ShowWallPaper( [[nodiscard]] ChatAdminRights ParseRequestedAdminRights( const QString &value) { auto result = ChatAdminRights(); - for (const auto &element : value.split(QRegularExpression("[+ ]"))) { + for (const auto &element : value.split(QRegularExpression(u"[+ ]"_q))) { if (element == u"change_info"_q) { result |= ChatAdminRight::ChangeInfo; } else if (element == u"post_messages"_q) { @@ -325,19 +325,19 @@ bool ResolveUsernameOrPhone( const auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); - const auto domain = params.value(qsl("domain")); - const auto phone = params.value(qsl("phone")); + const auto domain = params.value(u"domain"_q); + const auto phone = params.value(u"phone"_q); const auto validDomain = [](const QString &domain) { return qthelp::regex_match( - qsl("^[a-zA-Z0-9\\.\\_]+$"), + u"^[a-zA-Z0-9\\.\\_]+$"_q, domain, {} ).valid(); }; const auto validPhone = [](const QString &phone) { - return qthelp::regex_match(qsl("^[0-9]+$"), phone, {}).valid(); + return qthelp::regex_match(u"^[0-9]+$"_q, phone, {}).valid(); }; - if (domain == qsl("telegrampassport")) { + if (domain == u"telegrampassport"_q) { return ShowPassportForm(controller, params); } else if (!validDomain(domain) && !validPhone(phone)) { return false; @@ -359,17 +359,17 @@ bool ResolveUsernameOrPhone( || resolveType == ResolveType::AddToChannel) { adminRights = ParseRequestedAdminRights(params.value(u"admin"_q)); } - const auto postParam = params.value(qsl("post")); + const auto postParam = params.value(u"post"_q); if (const auto postId = postParam.toInt()) { post = postId; } - const auto commentParam = params.value(qsl("comment")); + const auto commentParam = params.value(u"comment"_q); const auto commentId = commentParam.toInt(); - const auto topicParam = params.value(qsl("topic")); + const auto topicParam = params.value(u"topic"_q); const auto topicId = topicParam.toInt(); - const auto threadParam = params.value(qsl("thread")); + const auto threadParam = params.value(u"thread"_q); const auto threadId = topicId ? topicId : threadParam.toInt(); - const auto gameParam = params.value(qsl("game")); + const auto gameParam = params.value(u"game"_q); if (!gameParam.isEmpty() && validDomain(gameParam)) { startToken = gameParam; resolveType = ResolveType::ShareGame; @@ -423,13 +423,13 @@ bool ResolvePrivatePost( match->captured(1), qthelp::UrlParamNameTransform::ToLower); const auto channelId = ChannelId( - params.value(qsl("channel")).toULongLong()); - const auto msgId = params.value(qsl("post")).toInt(); - const auto commentParam = params.value(qsl("comment")); + params.value(u"channel"_q).toULongLong()); + const auto msgId = params.value(u"post"_q).toInt(); + const auto commentParam = params.value(u"comment"_q); const auto commentId = commentParam.toInt(); - const auto topicParam = params.value(qsl("topic")); + const auto topicParam = params.value(u"topic"_q); const auto topicId = topicParam.toInt(); - const auto threadParam = params.value(qsl("thread")); + const auto threadParam = params.value(u"thread"_q); const auto threadId = topicId ? topicId : threadParam.toInt(); if (!channelId || (msgId && !IsServerMsgId(msgId))) { return false; @@ -465,19 +465,19 @@ bool ResolveSettings( const auto section = match->captured(1).mid(1).toLower(); const auto type = [&]() -> std::optional<::Settings::Type> { - if (section == qstr("language")) { + if (section == u"language"_q) { ShowLanguagesBox(); return {}; - } else if (section == qstr("devices")) { + } else if (section == u"devices"_q) { controller->session().api().authorizations().reload(); return ::Settings::Sessions::Id(); - } else if (section == qstr("folders")) { + } else if (section == u"folders"_q) { return ::Settings::Folders::Id(); - } else if (section == qstr("privacy")) { + } else if (section == u"privacy"_q) { return ::Settings::PrivacySecurity::Id(); - } else if (section == qstr("themes")) { + } else if (section == u"themes"_q) { return ::Settings::Chat::Id(); - } else if (section == qstr("change_number")) { + } else if (section == u"change_number"_q) { return ::Settings::ChangePhone::Id(); } return ::Settings::Main::Id(); @@ -531,7 +531,7 @@ bool OpenMediaTimestamp( return false; } const auto base = match->captured(1); - if (base.startsWith(qstr("doc"))) { + if (base.startsWith(u"doc"_q)) { const auto parts = base.mid(3).split('_'); const auto documentId = parts.value(0).toULongLong(); const auto itemId = FullMsgId( @@ -750,7 +750,7 @@ bool ResolveInvoice( const auto params = url_parse_params( match->captured(1), qthelp::UrlParamNameTransform::ToLower); - const auto slug = params.value(qsl("slug")); + const auto slug = params.value(u"slug"_q); if (slug.isEmpty()) { return false; } @@ -772,7 +772,7 @@ bool ResolvePremiumOffer( const auto params = url_parse_params( match->captured(1).mid(1), qthelp::UrlParamNameTransform::ToLower); - const auto refAddition = params.value(qsl("ref")); + const auto refAddition = params.value(u"ref"_q); const auto ref = "deeplink" + (refAddition.isEmpty() ? QString() : '_' + refAddition); ::Settings::ShowPremium(controller, ref); @@ -785,75 +785,75 @@ bool ResolvePremiumOffer( const std::vector &LocalUrlHandlers() { static auto Result = std::vector{ { - qsl("^join/?\\?invite=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"), + u"^join/?\\?invite=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"_q, JoinGroupByHash }, { - qsl("^(addstickers|addemoji)/?\\?set=([a-zA-Z0-9\\.\\_]+)(&|$)"), + u"^(addstickers|addemoji)/?\\?set=([a-zA-Z0-9\\.\\_]+)(&|$)"_q, ShowStickerSet }, { - qsl("^addtheme/?\\?slug=([a-zA-Z0-9\\.\\_]+)(&|$)"), + u"^addtheme/?\\?slug=([a-zA-Z0-9\\.\\_]+)(&|$)"_q, ShowTheme }, { - qsl("^setlanguage/?(\\?lang=([a-zA-Z0-9\\.\\_\\-]+))?(&|$)"), + u"^setlanguage/?(\\?lang=([a-zA-Z0-9\\.\\_\\-]+))?(&|$)"_q, SetLanguage }, { - qsl("^msg_url/?\\?(.+)(#|$)"), + u"^msg_url/?\\?(.+)(#|$)"_q, ShareUrl }, { - qsl("^confirmphone/?\\?(.+)(#|$)"), + u"^confirmphone/?\\?(.+)(#|$)"_q, ConfirmPhone }, { - qsl("^share_game_score/?\\?(.+)(#|$)"), + u"^share_game_score/?\\?(.+)(#|$)"_q, ShareGameScore }, { - qsl("^socks/?\\?(.+)(#|$)"), + u"^socks/?\\?(.+)(#|$)"_q, ApplySocksProxy }, { - qsl("^proxy/?\\?(.+)(#|$)"), + u"^proxy/?\\?(.+)(#|$)"_q, ApplyMtprotoProxy }, { - qsl("^passport/?\\?(.+)(#|$)"), + u"^passport/?\\?(.+)(#|$)"_q, ShowPassport }, { - qsl("^bg/?\\?(.+)(#|$)"), + u"^bg/?\\?(.+)(#|$)"_q, ShowWallPaper }, { - qsl("^resolve/?\\?(.+)(#|$)"), + u"^resolve/?\\?(.+)(#|$)"_q, ResolveUsernameOrPhone }, { - qsl("^privatepost/?\\?(.+)(#|$)"), + u"^privatepost/?\\?(.+)(#|$)"_q, ResolvePrivatePost }, { - qsl("^settings(/language|/devices|/folders|/privacy|/themes|/change_number)?$"), + u"^settings(/language|/devices|/folders|/privacy|/themes|/change_number)?$"_q, ResolveSettings }, { - qsl("^test_chat_theme/?\\?(.+)(#|$)"), + u"^test_chat_theme/?\\?(.+)(#|$)"_q, ResolveTestChatTheme, }, { - qsl("invoice/?\\?(.+)(#|$)"), + u"invoice/?\\?(.+)(#|$)"_q, ResolveInvoice, }, { - qsl("premium_offer/?(\\?.+)?(#|$)"), + u"premium_offer/?(\\?.+)?(#|$)"_q, ResolvePremiumOffer, }, { - qsl("^([^\\?]+)(\\?|#|$)"), + u"^([^\\?]+)(\\?|#|$)"_q, HandleUnknown }, }; @@ -863,15 +863,15 @@ const std::vector &LocalUrlHandlers() { const std::vector &InternalUrlHandlers() { static auto Result = std::vector{ { - qsl("^media_timestamp/?\\?base=([a-zA-Z0-9\\.\\_\\-]+)&t=(\\d+)(&|$)"), + u"^media_timestamp/?\\?base=([a-zA-Z0-9\\.\\_\\-]+)&t=(\\d+)(&|$)"_q, OpenMediaTimestamp }, { - qsl("^show_invite_link/?\\?link=([a-zA-Z0-9_\\+\\/\\=\\-]+)(&|$)"), + u"^show_invite_link/?\\?link=([a-zA-Z0-9_\\+\\/\\=\\-]+)(&|$)"_q, ShowInviteLink }, { - qsl("^url:(.+)$"), + u"^url:(.+)$"_q, OpenExternalLink }, }; @@ -885,7 +885,7 @@ QString TryConvertUrlToLocal(QString url) { using namespace qthelp; auto matchOptions = RegExOption::CaseInsensitive; - auto subdomainMatch = regex_match(qsl("^(https?://)?([a-zA-Z0-9\\_]+)\\.t\\.me(/\\d+)?/?(\\?.+)?"), url, matchOptions); + auto subdomainMatch = regex_match(u"^(https?://)?([a-zA-Z0-9\\_]+)\\.t\\.me(/\\d+)?/?(\\?.+)?"_q, url, matchOptions); if (subdomainMatch) { const auto name = subdomainMatch->captured(2); if (name.size() > 1 && name != "www") { @@ -900,65 +900,85 @@ QString TryConvertUrlToLocal(QString url) { : url; } } - auto telegramMeMatch = regex_match(qsl("^(https?://)?(www\\.)?(telegram\\.(me|dog)|t\\.me)/(.+)$"), url, matchOptions); + auto telegramMeMatch = regex_match(u"^(https?://)?(www\\.)?(telegram\\.(me|dog)|t\\.me)/(.+)$"_q, url, matchOptions); if (telegramMeMatch) { - auto query = telegramMeMatch->capturedView(5); - if (auto phoneMatch = regex_match(qsl("^\\+([0-9]+)(\\?|$)"), query, matchOptions)) { - auto params = query.mid(phoneMatch->captured(0).size()).toString(); - return qsl("tg://resolve?phone=") + phoneMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params); - } else if (auto joinChatMatch = regex_match(qsl("^(joinchat/|\\+|\\%20)([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://join?invite=") + url_encode(joinChatMatch->captured(2)); - } else if (auto stickerSetMatch = regex_match(qsl("^(addstickers|addemoji)/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://") + stickerSetMatch->captured(1) + "?set=" + url_encode(stickerSetMatch->captured(2)); - } else if (auto themeMatch = regex_match(qsl("^addtheme/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://addtheme?slug=") + url_encode(themeMatch->captured(1)); - } else if (auto languageMatch = regex_match(qsl("^setlanguage/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) { - return qsl("tg://setlanguage?lang=") + url_encode(languageMatch->captured(1)); - } else if (auto shareUrlMatch = regex_match(qsl("^share/url/?\\?(.+)$"), query, matchOptions)) { - return qsl("tg://msg_url?") + shareUrlMatch->captured(1); - } else if (auto confirmPhoneMatch = regex_match(qsl("^confirmphone/?\\?(.+)"), query, matchOptions)) { - return qsl("tg://confirmphone?") + confirmPhoneMatch->captured(1); - } else if (auto ivMatch = regex_match(qsl("^iv/?\\?(.+)(#|$)"), query, matchOptions)) { + const auto query = telegramMeMatch->capturedView(5); + if (const auto phoneMatch = regex_match(u"^\\+([0-9]+)(\\?|$)"_q, query, matchOptions)) { + const auto params = query.mid(phoneMatch->captured(0).size()).toString(); + return u"tg://resolve?phone="_q + phoneMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params); + } else if (const auto joinChatMatch = regex_match(u"^(joinchat/|\\+|\\%20)([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"_q, query, matchOptions)) { + return u"tg://join?invite="_q + url_encode(joinChatMatch->captured(2)); + } else if (const auto stickerSetMatch = regex_match(u"^(addstickers|addemoji)/([a-zA-Z0-9\\.\\_]+)(\\?|$)"_q, query, matchOptions)) { + return u"tg://"_q + stickerSetMatch->captured(1) + "?set=" + url_encode(stickerSetMatch->captured(2)); + } else if (const auto themeMatch = regex_match(u"^addtheme/([a-zA-Z0-9\\.\\_]+)(\\?|$)"_q, query, matchOptions)) { + return u"tg://addtheme?slug="_q + url_encode(themeMatch->captured(1)); + } else if (const auto languageMatch = regex_match(u"^setlanguage/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"_q, query, matchOptions)) { + return u"tg://setlanguage?lang="_q + url_encode(languageMatch->captured(1)); + } else if (const auto shareUrlMatch = regex_match(u"^share/url/?\\?(.+)$"_q, query, matchOptions)) { + return u"tg://msg_url?"_q + shareUrlMatch->captured(1); + } else if (const auto confirmPhoneMatch = regex_match(u"^confirmphone/?\\?(.+)"_q, query, matchOptions)) { + return u"tg://confirmphone?"_q + confirmPhoneMatch->captured(1); + } else if (const auto ivMatch = regex_match(u"^iv/?\\?(.+)(#|$)"_q, query, matchOptions)) { // // We need to show our t.me page, not the url directly. // //auto params = url_parse_params(ivMatch->captured(1), UrlParamNameTransform::ToLower); - //auto previewedUrl = params.value(qsl("url")); - //if (previewedUrl.startsWith(qstr("http://"), Qt::CaseInsensitive) - // || previewedUrl.startsWith(qstr("https://"), Qt::CaseInsensitive)) { + //auto previewedUrl = params.value(u"url"_q); + //if (previewedUrl.startsWith(u"http://"_q, Qt::CaseInsensitive) + // || previewedUrl.startsWith(u"https://"_q, Qt::CaseInsensitive)) { // return previewedUrl; //} return url; - } else if (auto socksMatch = regex_match(qsl("^socks/?\\?(.+)(#|$)"), query, matchOptions)) { - return qsl("tg://socks?") + socksMatch->captured(1); - } else if (auto proxyMatch = regex_match(qsl("^proxy/?\\?(.+)(#|$)"), query, matchOptions)) { - return qsl("tg://proxy?") + proxyMatch->captured(1); - } else if (auto invoiceMatch = regex_match(qsl("^(invoice/|\\$)([a-zA-Z0-9_\\-]+)(\\?|#|$)"), query, matchOptions)) { - return qsl("tg://invoice?slug=") + invoiceMatch->captured(2); - } else if (auto bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-\\~]+)(\\?(.+)?)?$"), query, matchOptions)) { + } else if (const auto socksMatch = regex_match(u"^socks/?\\?(.+)(#|$)"_q, query, matchOptions)) { + return u"tg://socks?"_q + socksMatch->captured(1); + } else if (const auto proxyMatch = regex_match(u"^proxy/?\\?(.+)(#|$)"_q, query, matchOptions)) { + return u"tg://proxy?"_q + proxyMatch->captured(1); + } else if (const auto invoiceMatch = regex_match(u"^(invoice/|\\$)([a-zA-Z0-9_\\-]+)(\\?|#|$)"_q, query, matchOptions)) { + return u"tg://invoice?slug="_q + invoiceMatch->captured(2); + } else if (const auto bgMatch = regex_match(u"^bg/([a-zA-Z0-9\\.\\_\\-\\~]+)(\\?(.+)?)?$"_q, query, matchOptions)) { const auto params = bgMatch->captured(3); const auto bg = bgMatch->captured(1); - const auto type = regex_match(qsl("^[a-fA-F0-9]{6}^"), bg) + const auto type = regex_match(u"^[a-fA-F0-9]{6}^"_q, bg) ? "color" - : (regex_match(qsl("^[a-fA-F0-9]{6}\\-[a-fA-F0-9]{6}$"), bg) - || regex_match(qsl("^[a-fA-F0-9]{6}(\\~[a-fA-F0-9]{6}){1,3}$"), bg)) + : (regex_match(u"^[a-fA-F0-9]{6}\\-[a-fA-F0-9]{6}$"_q, bg) + || regex_match(u"^[a-fA-F0-9]{6}(\\~[a-fA-F0-9]{6}){1,3}$"_q, bg)) ? "gradient" : "slug"; - return qsl("tg://bg?") + type + '=' + bg + (params.isEmpty() ? QString() : '&' + params); - } else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)(/\\d+)?(/?\\?|/?$)"), query, matchOptions)) { - const auto params = query.mid(postMatch->captured(0).size()).toString(); - const auto base = u"tg://privatepost?channel="_q + postMatch->captured(1); - const auto post = postMatch->captured(2).mid(1); - return base - + (post.isEmpty() ? QString() : u"&post="_q + post) - + (params.isEmpty() ? QString() : '&' + params); - } else if (auto usernameMatch = regex_match(qsl("^([a-zA-Z0-9\\.\\_]+)(/?\\?|/?$|/(\\d+)/?(?:\\?|$))"), query, matchOptions)) { - auto params = query.mid(usernameMatch->captured(0).size()).toString(); - auto postParam = QString(); - if (auto postMatch = regex_match(qsl("^/\\d+/?(?:\\?|$)"), usernameMatch->captured(2))) { - postParam = qsl("&post=") + usernameMatch->captured(3); + return u"tg://bg?"_q + type + '=' + bg + (params.isEmpty() ? QString() : '&' + params); + } else if (const auto privateMatch = regex_match(u"^" + "c/(\\-?\\d+)" + "(" + "/?\\?|" + "/?$|" + "/\\d+/?(\\?|$)|" + "/\\d+/\\d+/?(\\?|$)" + ")"_q, query, matchOptions)) { + const auto params = query.mid(privateMatch->captured(0).size()).toString(); + const auto base = u"tg://privatepost?channel="_q + privateMatch->captured(1); + auto added = QString(); + if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, privateMatch->captured(2))) { + added = u"&topic=%1&post=%2"_q.arg(threadPostMatch->captured(1)).arg(threadPostMatch->captured(2)); + } else if (const auto postMatch = regex_match(u"^/(\\d+)(/?\\?|/?$)"_q, privateMatch->captured(2))) { + added = u"&post="_q + postMatch->captured(1); } - return qsl("tg://resolve?domain=") + url_encode(usernameMatch->captured(1)) + postParam + (params.isEmpty() ? QString() : '&' + params); + return base + added + (params.isEmpty() ? QString() : '&' + params); + } else if (const auto usernameMatch = regex_match(u"^" + "([a-zA-Z0-9\\.\\_]+)" + "(" + "/?\\?|" + "/?$|" + "/\\d+/?(\\?|$)|" + "/\\d+/\\d+/?(\\?|$)" + ")"_q, query, matchOptions)) { + const auto params = query.mid(usernameMatch->captured(0).size()).toString(); + const auto base = u"tg://resolve?domain="_q + url_encode(usernameMatch->captured(1)); + auto added = QString(); + if (const auto threadPostMatch = regex_match(u"^/(\\d+)/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) { + added = u"&topic=%1&post=%2"_q.arg(threadPostMatch->captured(1)).arg(threadPostMatch->captured(2)); + } else if (const auto postMatch = regex_match(u"^/(\\d+)(/?\\?|/?$)"_q, usernameMatch->captured(2))) { + added = u"&post="_q + postMatch->captured(1); + } + return base + added + (params.isEmpty() ? QString() : '&' + params); } } return url; @@ -966,27 +986,27 @@ QString TryConvertUrlToLocal(QString url) { bool InternalPassportLink(const QString &url) { const auto urlTrimmed = url.trimmed(); - if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) { + if (!urlTrimmed.startsWith(u"tg://"_q, Qt::CaseInsensitive)) { return false; } - const auto command = base::StringViewMid(urlTrimmed, qstr("tg://").size()); + const auto command = base::StringViewMid(urlTrimmed, u"tg://"_q.size()); using namespace qthelp; const auto matchOptions = RegExOption::CaseInsensitive; const auto authMatch = regex_match( - qsl("^passport/?\\?(.+)(#|$)"), + u"^passport/?\\?(.+)(#|$)"_q, command, matchOptions); const auto usernameMatch = regex_match( - qsl("^resolve/?\\?(.+)(#|$)"), + u"^resolve/?\\?(.+)(#|$)"_q, command, matchOptions); const auto usernameValue = usernameMatch->hasMatch() ? url_parse_params( usernameMatch->captured(1), - UrlParamNameTransform::ToLower).value(qsl("domain")) + UrlParamNameTransform::ToLower).value(u"domain"_q) : QString(); - const auto authLegacy = (usernameValue == qstr("telegrampassport")); + const auto authLegacy = (usernameValue == u"telegrampassport"_q); return authMatch->hasMatch() || authLegacy; } diff --git a/Telegram/SourceFiles/data/data_download_manager.cpp b/Telegram/SourceFiles/data/data_download_manager.cpp index b8bab1704..e5861c470 100644 --- a/Telegram/SourceFiles/data/data_download_manager.cpp +++ b/Telegram/SourceFiles/data/data_download_manager.cpp @@ -540,7 +540,7 @@ void DownloadManager::loadingStopWithConfirmation( if (const auto strong = weak.get()) { if (const auto item = strong->data().message(id)) { if (const auto window = strong->tryResolveWindow()) { - window->showPeerHistoryAtItem(item); + window->showMessage(item); } } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 485636464..5e57e7b60 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -542,7 +542,7 @@ void Widget::setupDownloadBar() { } } if (first) { - controller()->showPeerHistoryAtItem(first); + controller()->showMessage(first); } }, _downloadBar->lifetime()); diff --git a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp index bbc7c1438..78f1cd920 100644 --- a/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/admin_log/history_admin_log_item.cpp @@ -641,7 +641,7 @@ TextWithEntities GenerateDefaultBannedRightsChangeText( result.append(qs(data.vtitle())); return Ui::Text::Link( std::move(result), - u"internal:url:https://t.me/c/%1?topic=%2"_q.arg( + u"internal:url:https://t.me/c/%1/%2"_q.arg( peerToChannel(channel->id).bare).arg( data.vid().v)); }, [](const MTPDforumTopicDeleted &) { diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index d5ad83ad9..1bf68782f 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1436,9 +1436,8 @@ ClickHandlerPtr goToMessageClickHandler( params.origin = Window::SectionShow::OriginMessage{ returnToId }; - const auto item = peer->owner().message(peer, msgId); - if (const auto topic = item ? item->topic() : nullptr) { - controller->showTopic(topic, msgId, params); + if (const auto item = peer->owner().message(peer, msgId)) { + controller->showMessage(item); } else { controller->showPeerHistory(peer, params, msgId); } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 0fbef097f..d0c24a208 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -609,8 +609,8 @@ HistoryWidget::HistoryWidget( ) | rpl::start_with_next([=](const Data::EntryUpdate &update) { if (_pinnedTracker && (update.flags & EntryUpdateFlag::HasPinnedMessages) - && (_migrated && update.entry.get() == _migrated) - || (update.entry.get() == _history)) { + && ((update.entry.get() == _history) + || (update.entry.get() == _migrated))) { checkPinnedBarState(); } }, lifetime()); @@ -6022,7 +6022,7 @@ void HistoryWidget::handlePeerMigration() { } bool HistoryWidget::replyToPreviousMessage() { - if (!_history || _editMsgId) { + if (!_history || _editMsgId || _history->peer->isForum()) { return false; } const auto fullId = FullMsgId(_history->peer->id, _replyToId); @@ -6030,14 +6030,14 @@ bool HistoryWidget::replyToPreviousMessage() { if (const auto view = item->mainView()) { if (const auto previousView = view->previousDisplayedInBlocks()) { const auto previous = previousView->data(); - controller()->showPeerHistoryAtItem(previous); + controller()->showMessage(previous); replyToMessage(previous); return true; } } } else if (const auto previousView = _history->findLastDisplayed()) { const auto previous = previousView->data(); - controller()->showPeerHistoryAtItem(previous); + controller()->showMessage(previous); replyToMessage(previous); return true; } @@ -6045,7 +6045,7 @@ bool HistoryWidget::replyToPreviousMessage() { } bool HistoryWidget::replyToNextMessage() { - if (!_history || _editMsgId) { + if (!_history || _editMsgId || _history->peer->isForum()) { return false; } const auto fullId = FullMsgId(_history->peer->id, _replyToId); @@ -6053,7 +6053,7 @@ bool HistoryWidget::replyToNextMessage() { if (const auto view = item->mainView()) { if (const auto nextView = view->nextDisplayedInBlocks()) { const auto next = nextView->data(); - controller()->showPeerHistoryAtItem(next); + controller()->showMessage(next); replyToMessage(next); } else { _highlighter.clear(); diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp index cf8906ac9..75ac5d4c8 100644 --- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp +++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp @@ -720,9 +720,8 @@ bool AddGoToMessageAction( const auto itemId = view->data()->fullId(); const auto controller = list->controller(); menu->addAction(tr::lng_context_to_msg(tr::now), crl::guard(controller, [=] { - const auto item = controller->session().data().message(itemId); - if (item) { - goToMessageClickHandler(item)->onClick(ClickContext{}); + if (const auto item = controller->session().data().message(itemId)) { + controller->showMessage(item); } }), &st::menuIconShowInChat); return true; diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp index 73d6ec884..659b0ea3a 100644 --- a/Telegram/SourceFiles/history/view/history_view_element.cpp +++ b/Telegram/SourceFiles/history/view/history_view_element.cpp @@ -692,7 +692,7 @@ auto Element::contextDependentServiceText() -> TextWithLinks { }, }; }; - const auto topicUrl = u"internal:url:https://t.me/c/%1?topic=%2"_q + const auto topicUrl = u"internal:url:https://t.me/c/%1/%2"_q .arg(peerToChannel(peerId).bare) .arg(topicRootId.bare); const auto fromLink = [&](int index) { diff --git a/Telegram/SourceFiles/info/info_layer_widget.cpp b/Telegram/SourceFiles/info/info_layer_widget.cpp index 5b2fb6e5d..18a37fd4d 100644 --- a/Telegram/SourceFiles/info/info_layer_widget.cpp +++ b/Telegram/SourceFiles/info/info_layer_widget.cpp @@ -73,7 +73,7 @@ bool LayerWidget::floatPlayerIsVisible(not_null item) { void LayerWidget::floatPlayerDoubleClickEvent( not_null item) { - _controller->showPeerHistoryAtItem(item); + _controller->showMessage(item); } void LayerWidget::setupHeightConsumers() { diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 81605435b..dc60273da 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -412,7 +412,7 @@ object_ptr DetailsFiller::setupInfo() { } else { const auto topicRootId = _topic ? _topic->rootId() : 0; const auto addToLink = topicRootId - ? "?topic=" + QString::number(topicRootId.bare) + ? ('/' + QString::number(topicRootId.bare)) : QString(); auto linkText = LinkValue( _peer, diff --git a/Telegram/SourceFiles/intro/intro_widget.cpp b/Telegram/SourceFiles/intro/intro_widget.cpp index 24aab653e..59a620254 100644 --- a/Telegram/SourceFiles/intro/intro_widget.cpp +++ b/Telegram/SourceFiles/intro/intro_widget.cpp @@ -196,7 +196,7 @@ void Widget::floatPlayerDoubleClickEvent(not_null item) { &item->history()->peer->session().account(), item->history()->peer, [&](not_null controller) { - controller->showPeerHistoryAtItem(item); + controller->showMessage(item); }); } diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 438fa6009..f55b202c1 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -440,7 +440,7 @@ void Session::uploadsStopWithConfirmation(Fn done) { if (const auto item = data().message(id)) { if (const auto window = tryResolveWindow()) { - window->showPeerHistoryAtItem(item); + window->showMessage(item); } } }); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 2ba25fcb6..df063ebb1 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -512,7 +512,7 @@ void MainWidget::floatPlayerClosed(FullMsgId itemId) { void MainWidget::floatPlayerDoubleClickEvent( not_null item) { - _controller->showPeerHistoryAtItem(item); + _controller->showMessage(item); } bool MainWidget::setForwardDraft(PeerId peerId, Data::ForwardDraft &&draft) { @@ -874,7 +874,7 @@ void MainWidget::createPlayer() { _player->entity()->setCloseCallback([=] { closeBothPlayers(); }); _player->entity()->setShowItemCallback([=]( not_null item) { - _controller->showPeerHistoryAtItem(item); + _controller->showMessage(item); }); _player->entity()->togglePlaylistRequests( diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 5b75dec19..5d00623b6 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1585,7 +1585,7 @@ void OverlayWidget::toMessage() { if (const auto item = _message) { close(); if (const auto window = findWindow()) { - window->showPeerHistoryAtItem(item); + window->showMessage(item); } } } diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 395701485..fef6154c2 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -314,6 +314,25 @@ void SessionNavigation::resolveChannelById( }).fail(fail).send(); } +void SessionNavigation::showMessageByLinkResolved( + not_null item, + const PeerByLinkInfo &info) { + auto params = SectionShow{ + SectionShow::Way::Forward + }; + params.origin = SectionShow::OriginMessage{ + info.clickFromMessageId + }; + const auto peer = item->history()->peer; + const auto topicId = peer->isForum() ? item->topicRootId() : 0; + if (topicId) { + const auto messageId = (item->id == topicId) ? MsgId() : item->id; + showRepliesForMessage(item->history(), topicId, messageId, params); + } else { + showPeerHistory(peer, params, item->id); + } +} + void SessionNavigation::showPeerByLinkResolved( not_null peer, const PeerByLinkInfo &info) { @@ -326,7 +345,7 @@ void SessionNavigation::showPeerByLinkResolved( if (info.voicechatHash && peer->isChannel()) { // First show the channel itself. crl::on_main(this, [=] { - showPeerHistory(peer->id, params, ShowAtUnreadMsgId); + showPeerHistory(peer, params, ShowAtUnreadMsgId); }); // Then try to join the voice chat. @@ -350,7 +369,24 @@ void SessionNavigation::showPeerByLinkResolved( commentId->id, params); } else if (peer->isForum()) { - parentController()->openForum(peer->asChannel(), params); + const auto itemId = info.messageId; + if (!itemId) { + parentController()->openForum(peer->asChannel(), params); + } else if (const auto item = peer->owner().message(peer, itemId)) { + showMessageByLinkResolved(item, info); + } else { + const auto callback = crl::guard(this, [=] { + if (const auto item = peer->owner().message(peer, itemId)) { + showMessageByLinkResolved(item, info); + } else { + showPeerHistory(peer, params, itemId); + } + }); + peer->session().api().requestMessageData( + peer, + info.messageId, + callback); + } } else if (bot && (info.resolveType == ResolveType::AddToGroup || info.resolveType == ResolveType::AddToChannel @@ -373,7 +409,7 @@ void SessionNavigation::showPeerByLinkResolved( } else if (info.resolveType == ResolveType::Mention) { if (bot || peer->isChannel()) { crl::on_main(this, [=] { - showPeerHistory(peer->id, params); + showPeerHistory(peer, params); }); } else { showPeerInfo(peer, params); @@ -421,7 +457,7 @@ void SessionNavigation::showPeerByLinkResolved( info.attachBotChooseTypes); } else { crl::on_main(this, [=] { - showPeerHistory(peer->id, params, msgId); + showPeerHistory(peer, params, msgId); }); } } @@ -1619,7 +1655,7 @@ void SessionController::showPeerHistory( content()->ui_showPeerHistory(peerId, params, msgId); } -void SessionController::showPeerHistoryAtItem( +void SessionController::showMessage( not_null item) { _window->invokeForSessionController( &item->history()->peer->session().account(), @@ -1628,7 +1664,13 @@ void SessionController::showPeerHistoryAtItem( if (item->isScheduled()) { controller->showSection( std::make_shared( - item->history())); + item->history()), + SectionShow::Way::ClearStack); + } else if (const auto topic = item->topic()) { + controller->showTopic( + topic, + item->id, + SectionShow::Way::ClearStack); } else { controller->showPeerHistory( item->history()->peer, diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 18383dfe6..e70b5c37f 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -275,6 +275,9 @@ private: const MTPcontacts_ResolvedPeer &result, Fn)> done); + void showMessageByLinkResolved( + not_null item, + const PeerByLinkInfo &info); void showPeerByLinkResolved( not_null peer, const PeerByLinkInfo &info); @@ -424,7 +427,7 @@ public: const SectionShow ¶ms = SectionShow::Way::ClearStack, MsgId msgId = ShowAtUnreadMsgId) override; - void showPeerHistoryAtItem(not_null item); + void showMessage(not_null item); void cancelUploadLayer(not_null item); void showLayer(