| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /*
- 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 "api/api_single_message_search.h"
- #include "main/main_session.h"
- #include "data/data_session.h"
- #include "data/data_channel.h"
- #include "data/data_search_controller.h"
- #include "core/local_url_handlers.h"
- #include "history/history_item.h"
- #include "base/qthelp_url.h"
- #include "apiwrap.h"
- namespace Api {
- namespace {
- using Key = details::SingleMessageSearchKey;
- Key ExtractKey(const QString &query) {
- const auto trimmed = query.trimmed();
- const auto local = Core::TryConvertUrlToLocal(trimmed);
- const auto check = local.isEmpty() ? trimmed : local;
- const auto parse = [&] {
- const auto delimeter = check.indexOf('?');
- return (delimeter > 0)
- ? qthelp::url_parse_params(
- check.mid(delimeter + 1),
- qthelp::UrlParamNameTransform::ToLower)
- : QMap<QString, QString>();
- };
- if (check.startsWith(u"tg://privatepost"_q, Qt::CaseInsensitive)) {
- const auto params = parse();
- const auto channel = params.value("channel");
- const auto post = params.value("post").toInt();
- return (channel.toULongLong() && post) ? Key{ channel, post } : Key();
- } else if (check.startsWith(u"tg://resolve"_q, Qt::CaseInsensitive)) {
- const auto params = parse();
- const auto domain = params.value("domain");
- const auto post = params.value("post").toInt();
- return (!domain.isEmpty() && post) ? Key{ domain, post } : Key();
- }
- return Key();
- }
- } // namespace
- SingleMessageSearch::SingleMessageSearch(not_null<Main::Session*> session)
- : _session(session) {
- }
- SingleMessageSearch::~SingleMessageSearch() {
- clear();
- }
- void SingleMessageSearch::clear() {
- _cache.clear();
- _requestKey = Key();
- _session->api().request(base::take(_requestId)).cancel();
- }
- std::optional<HistoryItem*> SingleMessageSearch::lookup(
- const QString &query,
- Fn<void()> ready) {
- const auto key = ExtractKey(query);
- if (!key) {
- return nullptr;
- }
- const auto i = _cache.find(key);
- if (i != end(_cache)) {
- return _session->data().message(i->second);
- }
- if (!(_requestKey == key)) {
- _session->api().request(base::take(_requestId)).cancel();
- _requestKey = key;
- }
- return performLookup(ready);
- }
- std::optional<HistoryItem*> SingleMessageSearch::performLookupByChannel(
- not_null<ChannelData*> channel,
- Fn<void()> ready) {
- Expects(!_requestKey.empty());
- const auto postId = _requestKey.postId;
- if (const auto item = _session->data().message(channel->id, postId)) {
- _cache.emplace(_requestKey, item->fullId());
- return item;
- } else if (!ready) {
- return nullptr;
- }
- const auto fail = [=] {
- _cache.emplace(_requestKey, FullMsgId());
- ready();
- };
- _requestId = _session->api().request(MTPchannels_GetMessages(
- channel->inputChannel,
- MTP_vector<MTPInputMessage>(1, MTP_inputMessageID(MTP_int(postId)))
- )).done([=](const MTPmessages_Messages &result) {
- const auto received = Api::ParseSearchResult(
- channel,
- Storage::SharedMediaType::kCount,
- postId,
- Data::LoadDirection::Around,
- result);
- if (!received.messageIds.empty()
- && received.messageIds.front() == postId) {
- _cache.emplace(
- _requestKey,
- FullMsgId(channel->id, postId));
- ready();
- } else {
- fail();
- }
- }).fail([=] {
- fail();
- }).send();
- return std::nullopt;
- }
- std::optional<HistoryItem*> SingleMessageSearch::performLookupById(
- ChannelId channelId,
- Fn<void()> ready) {
- Expects(!_requestKey.empty());
- if (const auto channel = _session->data().channelLoaded(channelId)) {
- return performLookupByChannel(channel, ready);
- } else if (!ready) {
- return nullptr;
- }
- const auto fail = [=] {
- _cache.emplace(_requestKey, FullMsgId());
- ready();
- };
- _requestId = _session->api().request(MTPchannels_GetChannels(
- MTP_vector<MTPInputChannel>(
- 1,
- MTP_inputChannel(MTP_long(channelId.bare), MTP_long(0)))
- )).done([=](const MTPmessages_Chats &result) {
- result.match([&](const auto &data) {
- const auto peer = _session->data().processChats(data.vchats());
- if (peer && peer->id == peerFromChannel(channelId)) {
- if (performLookupByChannel(peer->asChannel(), ready)) {
- ready();
- }
- } else {
- fail();
- }
- });
- }).fail([=] {
- fail();
- }).send();
- return std::nullopt;
- }
- std::optional<HistoryItem*> SingleMessageSearch::performLookupByUsername(
- const QString &username,
- Fn<void()> ready) {
- Expects(!_requestKey.empty());
- if (const auto peer = _session->data().peerByUsername(username)) {
- if (const auto channel = peer->asChannel()) {
- return performLookupByChannel(channel, ready);
- }
- _cache.emplace(_requestKey, FullMsgId());
- return nullptr;
- } else if (!ready) {
- return nullptr;
- }
- const auto fail = [=] {
- _cache.emplace(_requestKey, FullMsgId());
- ready();
- };
- _requestId = _session->api().request(MTPcontacts_ResolveUsername(
- MTP_flags(0),
- MTP_string(username),
- MTP_string()
- )).done([=](const MTPcontacts_ResolvedPeer &result) {
- result.match([&](const MTPDcontacts_resolvedPeer &data) {
- _session->data().processUsers(data.vusers());
- _session->data().processChats(data.vchats());
- const auto peerId = peerFromMTP(data.vpeer());
- const auto peer = peerId
- ? _session->data().peerLoaded(peerId)
- : nullptr;
- if (const auto channel = peer ? peer->asChannel() : nullptr) {
- if (performLookupByChannel(channel, ready)) {
- ready();
- }
- } else {
- fail();
- }
- });
- }).fail([=] {
- fail();
- }).send();
- return std::nullopt;
- }
- std::optional<HistoryItem*> SingleMessageSearch::performLookup(
- Fn<void()> ready) {
- Expects(!_requestKey.empty());
- if (!_requestKey.domainOrId[0].isDigit()) {
- return performLookupByUsername(_requestKey.domainOrId, ready);
- }
- const auto channelId = ChannelId(_requestKey.domainOrId.toULongLong());
- return performLookupById(channelId, ready);
- }
- QString ConvertPeerSearchQuery(const QString &query) {
- const auto trimmed = query.trimmed();
- const auto local = Core::TryConvertUrlToLocal(trimmed);
- const auto check = local.isEmpty() ? trimmed : local;
- if (!check.startsWith(u"tg://resolve"_q, Qt::CaseInsensitive)) {
- return query;
- }
- const auto delimeter = check.indexOf('?');
- const auto params = (delimeter > 0)
- ? qthelp::url_parse_params(
- check.mid(delimeter + 1),
- qthelp::UrlParamNameTransform::ToLower)
- : QMap<QString, QString>();
- return params.value("domain", query);
- }
- } // namespace Api
|