2018-11-26 11:55:02 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
|
|
|
#include "core/local_url_handlers.h"
|
|
|
|
|
2019-09-16 11:14:06 +00:00
|
|
|
#include "api/api_text_entities.h"
|
2020-07-01 14:19:25 +00:00
|
|
|
#include "api/api_chat_invite.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
#include "base/qthelp_regex.h"
|
|
|
|
#include "base/qthelp_url.h"
|
|
|
|
#include "lang/lang_cloud_manager.h"
|
|
|
|
#include "lang/lang_keys.h"
|
|
|
|
#include "core/update_checker.h"
|
2019-04-04 09:33:41 +00:00
|
|
|
#include "core/application.h"
|
2020-11-10 16:38:21 +00:00
|
|
|
#include "core/click_handler_types.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
#include "boxes/confirm_phone_box.h"
|
2019-02-07 16:36:30 +00:00
|
|
|
#include "boxes/background_preview_box.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
#include "boxes/confirm_box.h"
|
|
|
|
#include "boxes/share_box.h"
|
|
|
|
#include "boxes/connection_box.h"
|
|
|
|
#include "boxes/sticker_set_box.h"
|
2020-03-27 13:14:27 +00:00
|
|
|
#include "boxes/sessions_box.h"
|
2020-05-08 09:00:12 +00:00
|
|
|
#include "boxes/language_box.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
#include "passport/passport_form_controller.h"
|
2019-06-06 10:21:40 +00:00
|
|
|
#include "window/window_session_controller.h"
|
2021-02-09 17:52:20 +00:00
|
|
|
#include "ui/toast/toast.h"
|
2019-01-18 12:27:37 +00:00
|
|
|
#include "data/data_session.h"
|
2019-12-25 15:20:02 +00:00
|
|
|
#include "data/data_document.h"
|
2019-09-06 14:24:22 +00:00
|
|
|
#include "data/data_cloud_themes.h"
|
2019-04-04 09:33:41 +00:00
|
|
|
#include "data/data_channel.h"
|
2019-12-26 14:14:35 +00:00
|
|
|
#include "media/player/media_player_instance.h"
|
2020-03-27 13:14:27 +00:00
|
|
|
#include "window/window_session_controller.h"
|
2020-06-24 07:56:16 +00:00
|
|
|
#include "window/window_controller.h"
|
2020-03-27 13:14:27 +00:00
|
|
|
#include "settings/settings_common.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
#include "mainwidget.h"
|
2019-07-24 11:45:24 +00:00
|
|
|
#include "main/main_session.h"
|
2020-06-18 12:47:09 +00:00
|
|
|
#include "main/main_session_settings.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
#include "apiwrap.h"
|
2019-09-13 06:06:02 +00:00
|
|
|
#include "app.h"
|
2018-11-26 11:55:02 +00:00
|
|
|
|
2021-02-09 17:52:20 +00:00
|
|
|
#include <QtGui/QGuiApplication>
|
|
|
|
|
2018-11-26 11:55:02 +00:00
|
|
|
namespace Core {
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
using Match = qthelp::RegularExpressionMatch;
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool JoinGroupByHash(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-07-01 14:19:25 +00:00
|
|
|
Api::CheckChatInvite(controller, match->captured(1));
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ShowStickerSet(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
2019-01-21 13:42:21 +00:00
|
|
|
Core::App().hideMediaView();
|
2018-11-26 11:55:02 +00:00
|
|
|
Ui::show(Box<StickerSetBox>(
|
2020-09-18 15:32:13 +00:00
|
|
|
controller,
|
2018-11-26 11:55:02 +00:00
|
|
|
MTP_inputStickerSetShortName(MTP_string(match->captured(1)))));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-05 18:49:02 +00:00
|
|
|
bool ShowTheme(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-09-05 18:49:02 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2019-09-05 18:49:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-10 16:38:21 +00:00
|
|
|
const auto fromMessageId = context.value<ClickHandlerContext>().itemId;
|
2019-09-05 18:49:02 +00:00
|
|
|
Core::App().hideMediaView();
|
2020-06-24 07:56:16 +00:00
|
|
|
controller->session().data().cloudThemes().resolve(
|
2019-09-06 14:24:22 +00:00
|
|
|
match->captured(1),
|
2020-11-10 16:38:21 +00:00
|
|
|
fromMessageId);
|
2019-09-05 18:49:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-08 09:00:12 +00:00
|
|
|
void ShowLanguagesBox() {
|
|
|
|
static auto Guard = base::binary_guard();
|
|
|
|
Guard = LanguageBox::Show();
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool SetLanguage(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-05-08 09:00:12 +00:00
|
|
|
if (match->capturedRef(1).isEmpty()) {
|
|
|
|
ShowLanguagesBox();
|
|
|
|
} else {
|
|
|
|
const auto languageId = match->captured(2);
|
|
|
|
Lang::CurrentCloudManager().switchWithWarning(languageId);
|
|
|
|
}
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ShareUrl(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
|
|
|
auto url = params.value(qsl("url"));
|
|
|
|
if (url.isEmpty()) {
|
|
|
|
return false;
|
2020-09-18 15:32:13 +00:00
|
|
|
} else {
|
2020-06-12 14:09:04 +00:00
|
|
|
controller->content()->shareUrlLayer(url, params.value("text"));
|
|
|
|
return true;
|
2018-11-26 11:55:02 +00:00
|
|
|
}
|
2020-06-12 14:09:04 +00:00
|
|
|
return false;
|
2018-11-26 11:55:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ConfirmPhone(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
|
|
|
auto phone = params.value(qsl("phone"));
|
|
|
|
auto hash = params.value(qsl("hash"));
|
|
|
|
if (phone.isEmpty() || hash.isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-06-24 07:56:16 +00:00
|
|
|
ConfirmPhoneBox::Start(&controller->session(), phone, hash);
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ShareGameScore(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
2020-06-24 07:56:16 +00:00
|
|
|
ShareGameScoreByHash(&controller->session(), params.value(qsl("hash")));
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ApplySocksProxy(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2018-11-26 11:55:02 +00:00
|
|
|
auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
2019-11-13 14:12:04 +00:00
|
|
|
ProxiesBoxController::ShowApplyConfirmation(
|
|
|
|
MTP::ProxyData::Type::Socks5,
|
|
|
|
params);
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ApplyMtprotoProxy(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2018-11-26 11:55:02 +00:00
|
|
|
auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
2019-11-13 14:12:04 +00:00
|
|
|
ProxiesBoxController::ShowApplyConfirmation(
|
|
|
|
MTP::ProxyData::Type::Mtproto,
|
|
|
|
params);
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-18 15:32:13 +00:00
|
|
|
bool ShowPassportForm(
|
|
|
|
Window::SessionController *controller,
|
|
|
|
const QMap<QString, QString> ¶ms) {
|
|
|
|
if (!controller) {
|
|
|
|
return false;
|
|
|
|
}
|
2021-04-01 21:04:10 +00:00
|
|
|
const auto botId = params.value("bot_id", QString()).toULongLong();
|
2018-11-26 11:55:02 +00:00
|
|
|
const auto scope = params.value("scope", QString());
|
|
|
|
const auto callback = params.value("callback_url", QString());
|
|
|
|
const auto publicKey = params.value("public_key", QString());
|
|
|
|
const auto nonce = params.value(
|
|
|
|
Passport::NonceNameByScope(scope),
|
|
|
|
QString());
|
|
|
|
const auto errors = params.value("errors", QString());
|
2020-09-18 15:32:13 +00:00
|
|
|
controller->showPassportForm(Passport::FormRequest(
|
|
|
|
botId,
|
|
|
|
scope,
|
|
|
|
callback,
|
|
|
|
publicKey,
|
|
|
|
nonce,
|
|
|
|
errors));
|
|
|
|
return true;
|
2018-11-26 11:55:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ShowPassport(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-09-18 15:32:13 +00:00
|
|
|
return ShowPassportForm(
|
|
|
|
controller,
|
|
|
|
url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower));
|
2018-11-26 11:55:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ShowWallPaper(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2019-01-17 08:18:23 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
|
|
|
return BackgroundPreviewBox::Start(
|
2020-09-18 15:32:13 +00:00
|
|
|
controller,
|
2019-01-17 08:18:23 +00:00
|
|
|
params.value(qsl("slug")),
|
2019-01-29 07:29:38 +00:00
|
|
|
params);
|
2019-01-17 08:18:23 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ResolveUsername(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
2019-01-17 08:18:23 +00:00
|
|
|
const auto params = url_parse_params(
|
2018-11-26 11:55:02 +00:00
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
|
|
|
const auto domain = params.value(qsl("domain"));
|
|
|
|
const auto valid = [](const QString &domain) {
|
|
|
|
return qthelp::regex_match(
|
2018-11-30 09:25:08 +00:00
|
|
|
qsl("^[a-zA-Z0-9\\.\\_]+$"),
|
2018-11-26 11:55:02 +00:00
|
|
|
domain,
|
|
|
|
{}
|
|
|
|
).valid();
|
|
|
|
};
|
|
|
|
if (domain == qsl("telegrampassport")) {
|
2020-09-18 15:32:13 +00:00
|
|
|
return ShowPassportForm(controller, params);
|
2018-11-26 11:55:02 +00:00
|
|
|
} else if (!valid(domain)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto start = qsl("start");
|
|
|
|
auto startToken = params.value(start);
|
|
|
|
if (startToken.isEmpty()) {
|
|
|
|
start = qsl("startgroup");
|
|
|
|
startToken = params.value(start);
|
|
|
|
if (startToken.isEmpty()) {
|
|
|
|
start = QString();
|
|
|
|
}
|
|
|
|
}
|
2019-04-04 09:33:41 +00:00
|
|
|
auto post = (start == qsl("startgroup"))
|
|
|
|
? ShowAtProfileMsgId
|
|
|
|
: ShowAtUnreadMsgId;
|
2020-09-17 17:57:06 +00:00
|
|
|
const auto postParam = params.value(qsl("post"));
|
|
|
|
if (const auto postId = postParam.toInt()) {
|
2018-11-26 11:55:02 +00:00
|
|
|
post = postId;
|
|
|
|
}
|
2020-09-17 17:57:06 +00:00
|
|
|
const auto commentParam = params.value(qsl("comment"));
|
|
|
|
const auto commentId = commentParam.toInt();
|
2020-09-22 15:05:07 +00:00
|
|
|
const auto threadParam = params.value(qsl("thread"));
|
|
|
|
const auto threadId = threadParam.toInt();
|
2019-04-04 09:33:41 +00:00
|
|
|
const auto gameParam = params.value(qsl("game"));
|
2018-11-26 11:55:02 +00:00
|
|
|
if (!gameParam.isEmpty() && valid(gameParam)) {
|
|
|
|
startToken = gameParam;
|
|
|
|
post = ShowAtGameShareMsgId;
|
|
|
|
}
|
2020-11-10 16:38:21 +00:00
|
|
|
const auto fromMessageId = context.value<ClickHandlerContext>().itemId;
|
2020-09-22 15:05:07 +00:00
|
|
|
using Navigation = Window::SessionNavigation;
|
|
|
|
controller->showPeerByLink(Navigation::PeerByLinkInfo{
|
|
|
|
.usernameOrId = domain,
|
|
|
|
.messageId = post,
|
|
|
|
.repliesInfo = commentId
|
|
|
|
? Navigation::RepliesByLinkInfo{
|
|
|
|
Navigation::CommentId{ commentId }
|
|
|
|
}
|
|
|
|
: threadId
|
|
|
|
? Navigation::RepliesByLinkInfo{
|
|
|
|
Navigation::ThreadId{ threadId }
|
|
|
|
}
|
|
|
|
: Navigation::RepliesByLinkInfo{ v::null },
|
|
|
|
.startToken = startToken,
|
2021-03-10 20:03:20 +00:00
|
|
|
.voicechatHash = (params.contains(u"voicechat"_q)
|
|
|
|
? std::make_optional(params.value(u"voicechat"_q))
|
|
|
|
: std::nullopt),
|
2020-11-10 16:38:21 +00:00
|
|
|
.clickFromMessageId = fromMessageId,
|
2020-09-22 15:05:07 +00:00
|
|
|
});
|
2020-06-30 13:23:21 +00:00
|
|
|
return true;
|
2018-11-26 11:55:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool ResolvePrivatePost(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2019-04-04 09:33:41 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto params = url_parse_params(
|
|
|
|
match->captured(1),
|
|
|
|
qthelp::UrlParamNameTransform::ToLower);
|
2021-04-01 21:04:10 +00:00
|
|
|
const auto channelId = ChannelId(
|
|
|
|
params.value(qsl("channel")).toULongLong());
|
2019-04-04 09:33:41 +00:00
|
|
|
const auto msgId = params.value(qsl("post")).toInt();
|
2020-09-22 15:05:07 +00:00
|
|
|
const auto commentParam = params.value(qsl("comment"));
|
|
|
|
const auto commentId = commentParam.toInt();
|
|
|
|
const auto threadParam = params.value(qsl("thread"));
|
|
|
|
const auto threadId = threadParam.toInt();
|
2019-04-04 09:33:41 +00:00
|
|
|
if (!channelId || !IsServerMsgId(msgId)) {
|
|
|
|
return false;
|
|
|
|
}
|
2020-11-10 16:38:21 +00:00
|
|
|
const auto fromMessageId = context.value<ClickHandlerContext>().itemId;
|
2020-09-22 15:05:07 +00:00
|
|
|
using Navigation = Window::SessionNavigation;
|
|
|
|
controller->showPeerByLink(Navigation::PeerByLinkInfo{
|
|
|
|
.usernameOrId = channelId,
|
|
|
|
.messageId = msgId,
|
|
|
|
.repliesInfo = commentId
|
|
|
|
? Navigation::RepliesByLinkInfo{
|
|
|
|
Navigation::CommentId{ commentId }
|
|
|
|
}
|
|
|
|
: threadId
|
|
|
|
? Navigation::RepliesByLinkInfo{
|
|
|
|
Navigation::ThreadId{ threadId }
|
2019-04-04 09:33:41 +00:00
|
|
|
}
|
2020-09-22 15:05:07 +00:00
|
|
|
: Navigation::RepliesByLinkInfo{ v::null },
|
2020-11-10 16:38:21 +00:00
|
|
|
.clickFromMessageId = fromMessageId,
|
2020-09-22 15:05:07 +00:00
|
|
|
});
|
2019-04-04 09:33:41 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-27 13:14:27 +00:00
|
|
|
bool ResolveSettings(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2020-03-27 13:14:27 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2020-03-27 13:14:27 +00:00
|
|
|
return false;
|
|
|
|
}
|
2021-02-03 01:58:27 +00:00
|
|
|
controller->window().activate();
|
2020-09-18 15:32:13 +00:00
|
|
|
const auto section = match->captured(1).mid(1).toLower();
|
|
|
|
if (section.isEmpty()) {
|
|
|
|
controller->window().showSettings();
|
|
|
|
return true;
|
|
|
|
}
|
2020-03-27 13:14:27 +00:00
|
|
|
if (section == qstr("devices")) {
|
2020-06-24 07:56:16 +00:00
|
|
|
Ui::show(Box<SessionsBox>(&controller->session()));
|
2020-03-27 13:14:27 +00:00
|
|
|
return true;
|
2020-05-08 09:00:12 +00:00
|
|
|
} else if (section == qstr("language")) {
|
|
|
|
ShowLanguagesBox();
|
|
|
|
return true;
|
2020-03-27 13:14:27 +00:00
|
|
|
}
|
|
|
|
const auto type = (section == qstr("folders"))
|
|
|
|
? ::Settings::Type::Folders
|
|
|
|
: ::Settings::Type::Main;
|
2020-09-18 15:32:13 +00:00
|
|
|
controller->showSettings(type);
|
2020-03-27 13:14:27 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:00:30 +00:00
|
|
|
bool HandleUnknown(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-07-24 14:00:30 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2018-11-26 11:55:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto request = match->captured(1);
|
2020-06-30 14:26:44 +00:00
|
|
|
const auto callback = crl::guard(controller, [=](const MTPDhelp_deepLinkInfo &result) {
|
2018-11-26 11:55:02 +00:00
|
|
|
const auto text = TextWithEntities{
|
2019-07-05 13:38:38 +00:00
|
|
|
qs(result.vmessage()),
|
2020-06-08 08:03:45 +00:00
|
|
|
Api::EntitiesFromMTP(
|
2020-06-24 07:56:16 +00:00
|
|
|
&controller->session(),
|
2020-06-08 08:03:45 +00:00
|
|
|
result.ventities().value_or_empty())
|
2018-11-26 11:55:02 +00:00
|
|
|
};
|
|
|
|
if (result.is_update_app()) {
|
2020-09-24 12:48:02 +00:00
|
|
|
const auto callback = [=](Fn<void()> &&close) {
|
2018-11-26 11:55:02 +00:00
|
|
|
Core::UpdateApplication();
|
2020-09-24 12:48:02 +00:00
|
|
|
close();
|
2018-11-26 11:55:02 +00:00
|
|
|
};
|
2020-09-24 12:48:02 +00:00
|
|
|
Ui::show(Box<ConfirmBox>(
|
2018-11-26 11:55:02 +00:00
|
|
|
text,
|
2019-06-19 15:09:03 +00:00
|
|
|
tr::lng_menu_update(tr::now),
|
2018-11-26 11:55:02 +00:00
|
|
|
callback));
|
|
|
|
} else {
|
|
|
|
Ui::show(Box<InformBox>(text));
|
|
|
|
}
|
2020-06-30 14:26:44 +00:00
|
|
|
});
|
2020-06-24 07:56:16 +00:00
|
|
|
controller->session().api().requestDeepLinkInfo(request, callback);
|
2018-11-26 11:55:02 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-12-25 15:20:02 +00:00
|
|
|
bool OpenMediaTimestamp(
|
2020-06-24 07:56:16 +00:00
|
|
|
Window::SessionController *controller,
|
2019-12-25 15:20:02 +00:00
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
2020-06-24 07:56:16 +00:00
|
|
|
if (!controller) {
|
2019-12-25 15:20:02 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto time = match->captured(2).toInt();
|
|
|
|
if (time < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto base = match->captured(1);
|
|
|
|
if (base.startsWith(qstr("doc"))) {
|
|
|
|
const auto parts = base.mid(3).split('_');
|
|
|
|
const auto documentId = parts.value(0).toULongLong();
|
|
|
|
const auto itemId = FullMsgId(
|
|
|
|
parts.value(1).toInt(),
|
|
|
|
parts.value(2).toInt());
|
2020-06-24 07:56:16 +00:00
|
|
|
const auto session = &controller->session();
|
2019-12-25 15:20:02 +00:00
|
|
|
const auto document = session->data().document(documentId);
|
|
|
|
session->settings().setMediaLastPlaybackPosition(
|
|
|
|
documentId,
|
|
|
|
time * crl::time(1000));
|
2019-12-26 14:14:35 +00:00
|
|
|
if (document->isVideoFile()) {
|
2019-12-25 15:20:02 +00:00
|
|
|
Core::App().showDocument(
|
|
|
|
document,
|
|
|
|
session->data().message(itemId));
|
2021-02-25 13:20:32 +00:00
|
|
|
} else if (document->isSong() || document->isVoiceMessage()) {
|
2019-12-26 14:14:35 +00:00
|
|
|
Media::Player::instance()->play({ document, itemId });
|
2019-12-25 15:20:02 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-09 17:52:20 +00:00
|
|
|
bool ShowInviteLink(
|
|
|
|
Window::SessionController *controller,
|
|
|
|
const Match &match,
|
|
|
|
const QVariant &context) {
|
|
|
|
if (!controller) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto base64link = match->captured(1).toLatin1();
|
|
|
|
const auto link = QString::fromUtf8(QByteArray::fromBase64(base64link));
|
|
|
|
if (link.isEmpty()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
QGuiApplication::clipboard()->setText(link);
|
|
|
|
Ui::Toast::Show(tr::lng_group_invite_copied(tr::now));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-11-26 11:55:02 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
const std::vector<LocalUrlHandler> &LocalUrlHandlers() {
|
|
|
|
static auto Result = std::vector<LocalUrlHandler>{
|
|
|
|
{
|
|
|
|
qsl("^join/?\\?invite=([a-zA-Z0-9\\.\\_\\-]+)(&|$)"),
|
|
|
|
JoinGroupByHash
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^addstickers/?\\?set=([a-zA-Z0-9\\.\\_]+)(&|$)"),
|
|
|
|
ShowStickerSet
|
|
|
|
},
|
2019-09-05 18:49:02 +00:00
|
|
|
{
|
|
|
|
qsl("^addtheme/?\\?slug=([a-zA-Z0-9\\.\\_]+)(&|$)"),
|
|
|
|
ShowTheme
|
|
|
|
},
|
2018-11-26 11:55:02 +00:00
|
|
|
{
|
2020-05-08 09:00:12 +00:00
|
|
|
qsl("^setlanguage/?(\\?lang=([a-zA-Z0-9\\.\\_\\-]+))?(&|$)"),
|
2018-11-26 11:55:02 +00:00
|
|
|
SetLanguage
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^msg_url/?\\?(.+)(#|$)"),
|
|
|
|
ShareUrl
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^confirmphone/?\\?(.+)(#|$)"),
|
|
|
|
ConfirmPhone
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^share_game_score/?\\?(.+)(#|$)"),
|
|
|
|
ShareGameScore
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^socks/?\\?(.+)(#|$)"),
|
|
|
|
ApplySocksProxy
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^proxy/?\\?(.+)(#|$)"),
|
|
|
|
ApplyMtprotoProxy
|
|
|
|
},
|
|
|
|
{
|
|
|
|
qsl("^passport/?\\?(.+)(#|$)"),
|
|
|
|
ShowPassport
|
|
|
|
},
|
2019-01-17 08:18:23 +00:00
|
|
|
{
|
|
|
|
qsl("^bg/?\\?(.+)(#|$)"),
|
|
|
|
ShowWallPaper
|
|
|
|
},
|
2018-11-26 11:55:02 +00:00
|
|
|
{
|
|
|
|
qsl("^resolve/?\\?(.+)(#|$)"),
|
|
|
|
ResolveUsername
|
|
|
|
},
|
2019-04-04 09:33:41 +00:00
|
|
|
{
|
|
|
|
qsl("^privatepost/?\\?(.+)(#|$)"),
|
|
|
|
ResolvePrivatePost
|
|
|
|
},
|
2020-03-27 13:14:27 +00:00
|
|
|
{
|
2020-05-08 09:00:12 +00:00
|
|
|
qsl("^settings(/folders|/devices|/language)?$"),
|
2020-03-27 13:14:27 +00:00
|
|
|
ResolveSettings
|
|
|
|
},
|
2018-11-26 11:55:02 +00:00
|
|
|
{
|
|
|
|
qsl("^([^\\?]+)(\\?|#|$)"),
|
|
|
|
HandleUnknown
|
2019-12-25 15:20:02 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::vector<LocalUrlHandler> &InternalUrlHandlers() {
|
|
|
|
static auto Result = std::vector<LocalUrlHandler>{
|
|
|
|
{
|
|
|
|
qsl("^media_timestamp/?\\?base=([a-zA-Z0-9\\.\\_\\-]+)&t=(\\d+)(&|$)"),
|
|
|
|
OpenMediaTimestamp
|
|
|
|
},
|
2021-02-09 17:52:20 +00:00
|
|
|
{
|
|
|
|
qsl("^show_invite_link/?\\?link=([a-zA-Z0-9_\\+\\/\\=\\-]+)(&|$)"),
|
|
|
|
ShowInviteLink
|
|
|
|
},
|
2018-11-26 11:55:02 +00:00
|
|
|
};
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2019-08-06 14:43:26 +00:00
|
|
|
QString TryConvertUrlToLocal(QString url) {
|
|
|
|
if (url.size() > 8192) {
|
|
|
|
url = url.mid(0, 8192);
|
|
|
|
}
|
|
|
|
|
|
|
|
using namespace qthelp;
|
|
|
|
auto matchOptions = RegExOption::CaseInsensitive;
|
2019-08-06 14:54:44 +00:00
|
|
|
auto telegramMeMatch = regex_match(qsl("^(https?://)?(www\\.)?(telegram\\.(me|dog)|t\\.me)/(.+)$"), url, matchOptions);
|
2019-08-06 14:43:26 +00:00
|
|
|
if (telegramMeMatch) {
|
2019-08-06 14:54:44 +00:00
|
|
|
auto query = telegramMeMatch->capturedRef(5);
|
2021-02-04 13:14:02 +00:00
|
|
|
if (auto joinChatMatch = regex_match(qsl("^(joinchat/|\\+|\\%20)([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), query, matchOptions)) {
|
|
|
|
return qsl("tg://join?invite=") + url_encode(joinChatMatch->captured(2));
|
2019-08-06 14:43:26 +00:00
|
|
|
} else if (auto stickerSetMatch = regex_match(qsl("^addstickers/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) {
|
|
|
|
return qsl("tg://addstickers?set=") + url_encode(stickerSetMatch->captured(1));
|
2019-09-05 18:49:02 +00:00
|
|
|
} else if (auto themeMatch = regex_match(qsl("^addtheme/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), query, matchOptions)) {
|
|
|
|
return qsl("tg://addtheme?slug=") + url_encode(themeMatch->captured(1));
|
2019-08-06 14:43:26 +00:00
|
|
|
} 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)) {
|
|
|
|
//
|
|
|
|
// 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)) {
|
|
|
|
// 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 bgMatch = regex_match(qsl("^bg/([a-zA-Z0-9\\.\\_\\-]+)(\\?(.+)?)?$"), query, matchOptions)) {
|
|
|
|
const auto params = bgMatch->captured(3);
|
|
|
|
return qsl("tg://bg?slug=") + bgMatch->captured(1) + (params.isEmpty() ? QString() : '&' + params);
|
2020-09-17 17:57:06 +00:00
|
|
|
} else if (auto postMatch = regex_match(qsl("^c/(\\-?\\d+)/(\\d+)(/?\\?|/?$)"), query, matchOptions)) {
|
|
|
|
auto params = query.mid(postMatch->captured(0).size()).toString();
|
2021-03-13 11:50:34 +00:00
|
|
|
return qsl("tg://privatepost?channel=%1&post=%2").arg(postMatch->captured(1), postMatch->captured(2)) + (params.isEmpty() ? QString() : '&' + params);
|
2019-08-06 14:43:26 +00:00
|
|
|
} 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 qsl("tg://resolve/?domain=") + url_encode(usernameMatch->captured(1)) + postParam + (params.isEmpty() ? QString() : '&' + params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
2019-01-21 13:42:21 +00:00
|
|
|
bool InternalPassportLink(const QString &url) {
|
|
|
|
const auto urlTrimmed = url.trimmed();
|
|
|
|
if (!urlTrimmed.startsWith(qstr("tg://"), Qt::CaseInsensitive)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const auto command = urlTrimmed.midRef(qstr("tg://").size());
|
|
|
|
|
|
|
|
using namespace qthelp;
|
|
|
|
const auto matchOptions = RegExOption::CaseInsensitive;
|
|
|
|
const auto authMatch = regex_match(
|
|
|
|
qsl("^passport/?\\?(.+)(#|$)"),
|
|
|
|
command,
|
|
|
|
matchOptions);
|
|
|
|
const auto usernameMatch = regex_match(
|
|
|
|
qsl("^resolve/?\\?(.+)(#|$)"),
|
|
|
|
command,
|
|
|
|
matchOptions);
|
|
|
|
const auto usernameValue = usernameMatch->hasMatch()
|
|
|
|
? url_parse_params(
|
|
|
|
usernameMatch->captured(1),
|
|
|
|
UrlParamNameTransform::ToLower).value(qsl("domain"))
|
|
|
|
: QString();
|
|
|
|
const auto authLegacy = (usernameValue == qstr("telegrampassport"));
|
|
|
|
return authMatch->hasMatch() || authLegacy;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool StartUrlRequiresActivate(const QString &url) {
|
2020-06-24 07:56:16 +00:00
|
|
|
return Core::App().passcodeLocked()
|
2019-01-21 13:42:21 +00:00
|
|
|
? true
|
|
|
|
: !InternalPassportLink(url);
|
|
|
|
}
|
|
|
|
|
2018-11-26 11:55:02 +00:00
|
|
|
} // namespace Core
|