Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ce3f9bb71 | ||
|
|
a5483a5113 | ||
|
|
7f5e646db5 | ||
|
|
666251f23e | ||
|
|
d89d8b09da | ||
|
|
0aa20b4479 | ||
|
|
8658dba97a | ||
|
|
20c911651f | ||
|
|
bef20ba4a2 | ||
|
|
ee325031a0 | ||
|
|
b57549546d | ||
|
|
1e4d278604 | ||
|
|
80aa596310 | ||
|
|
4913288061 | ||
|
|
1a43cd8a67 |
@@ -10,7 +10,7 @@
|
||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||
ProcessorArchitecture="ARCHITECTURE"
|
||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||
Version="3.5.1.0" />
|
||||
Version="3.5.2.0" />
|
||||
<Properties>
|
||||
<DisplayName>Telegram Desktop</DisplayName>
|
||||
<PublisherDisplayName>Telegram Messenger LLP</PublisherDisplayName>
|
||||
|
||||
@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,5,1,0
|
||||
PRODUCTVERSION 3,5,1,0
|
||||
FILEVERSION 3,5,2,0
|
||||
PRODUCTVERSION 3,5,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -62,10 +62,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop"
|
||||
VALUE "FileVersion", "3.5.1.0"
|
||||
VALUE "FileVersion", "3.5.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.5.1.0"
|
||||
VALUE "ProductVersion", "3.5.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 3,5,1,0
|
||||
PRODUCTVERSION 3,5,1,0
|
||||
FILEVERSION 3,5,2,0
|
||||
PRODUCTVERSION 3,5,2,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -53,10 +53,10 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Telegram FZ-LLC"
|
||||
VALUE "FileDescription", "Telegram Desktop Updater"
|
||||
VALUE "FileVersion", "3.5.1.0"
|
||||
VALUE "FileVersion", "3.5.2.0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2014-2022"
|
||||
VALUE "ProductName", "Telegram Desktop"
|
||||
VALUE "ProductVersion", "3.5.1.0"
|
||||
VALUE "ProductVersion", "3.5.2.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
||||
@@ -318,7 +318,7 @@ void ProxyRow::updateFields(View &&view) {
|
||||
TextWithEntities()
|
||||
.append(_view.type)
|
||||
.append(' ')
|
||||
.append(Ui::Text::Link(endpoint, {})),
|
||||
.append(Ui::Text::Link(endpoint, QString())),
|
||||
Ui::ItemTextDefaultOptions());
|
||||
|
||||
const auto state = _view.state;
|
||||
|
||||
@@ -22,7 +22,7 @@ constexpr auto AppId = "{53F49750-6209-4FBF-9CA8-7A333C87D1ED}"_cs;
|
||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||
constexpr auto AppName = "Telegram Desktop"_cs;
|
||||
constexpr auto AppFile = "Telegram"_cs;
|
||||
constexpr auto AppVersion = 3005001;
|
||||
constexpr auto AppVersionStr = "3.5.1";
|
||||
constexpr auto AppVersion = 3005002;
|
||||
constexpr auto AppVersionStr = "3.5.2";
|
||||
constexpr auto AppBetaVersion = false;
|
||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||
|
||||
@@ -3025,6 +3025,24 @@ void InnerWidget::updateRowCornerStatusShown(
|
||||
}
|
||||
}
|
||||
|
||||
RowDescriptor InnerWidget::resolveChatNext(RowDescriptor from) const {
|
||||
const auto row = from.key ? from : _controller->activeChatEntryCurrent();
|
||||
return row.key
|
||||
? computeJump(
|
||||
chatListEntryAfter(row),
|
||||
JumpSkip::NextOrEnd)
|
||||
: row;
|
||||
}
|
||||
|
||||
RowDescriptor InnerWidget::resolveChatPrevious(RowDescriptor from) const {
|
||||
const auto row = from.key ? from : _controller->activeChatEntryCurrent();
|
||||
return row.key
|
||||
? computeJump(
|
||||
chatListEntryBefore(row),
|
||||
JumpSkip::PreviousOrBegin)
|
||||
: row;
|
||||
}
|
||||
|
||||
void InnerWidget::setupShortcuts() {
|
||||
Shortcuts::Requests(
|
||||
) | rpl::filter([=] {
|
||||
@@ -3197,7 +3215,7 @@ void InnerWidget::setupShortcuts() {
|
||||
|
||||
RowDescriptor InnerWidget::computeJump(
|
||||
const RowDescriptor &to,
|
||||
JumpSkip skip) {
|
||||
JumpSkip skip) const {
|
||||
auto result = to;
|
||||
if (result.key) {
|
||||
const auto down = (skip == JumpSkip::NextOrEnd)
|
||||
|
||||
@@ -125,6 +125,9 @@ public:
|
||||
[[nodiscard]] rpl::producer<ChosenRow> chosenRow() const;
|
||||
[[nodiscard]] rpl::producer<> updated() const;
|
||||
|
||||
[[nodiscard]] RowDescriptor resolveChatNext(RowDescriptor from = {}) const;
|
||||
[[nodiscard]] RowDescriptor resolveChatPrevious(RowDescriptor from = {}) const;
|
||||
|
||||
~InnerWidget();
|
||||
|
||||
public Q_SLOTS:
|
||||
@@ -238,7 +241,7 @@ private:
|
||||
void setupShortcuts();
|
||||
RowDescriptor computeJump(
|
||||
const RowDescriptor &to,
|
||||
JumpSkip skip);
|
||||
JumpSkip skip) const;
|
||||
bool jumpToDialogRow(RowDescriptor to);
|
||||
|
||||
RowDescriptor chatListEntryBefore(const RowDescriptor &which) const;
|
||||
|
||||
@@ -1685,6 +1685,14 @@ void Widget::updateForwardBar() {
|
||||
update();
|
||||
}
|
||||
|
||||
RowDescriptor Widget::resolveChatNext(RowDescriptor from) const {
|
||||
return _inner->resolveChatNext(from);
|
||||
}
|
||||
|
||||
RowDescriptor Widget::resolveChatPrevious(RowDescriptor from) const {
|
||||
return _inner->resolveChatPrevious(from);
|
||||
}
|
||||
|
||||
void Widget::keyPressEvent(QKeyEvent *e) {
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
if (_openedFolder) {
|
||||
|
||||
@@ -91,6 +91,9 @@ public:
|
||||
|
||||
[[nodiscard]] rpl::producer<> closeForwardBarRequests() const;
|
||||
|
||||
[[nodiscard]] RowDescriptor resolveChatNext(RowDescriptor from = {}) const;
|
||||
[[nodiscard]] RowDescriptor resolveChatPrevious(RowDescriptor from = {}) const;
|
||||
|
||||
// Float player interface.
|
||||
bool floatPlayerHandleWheelEvent(QEvent *e) override;
|
||||
QRect floatPlayerAvailableRect() override;
|
||||
|
||||
@@ -675,7 +675,7 @@ void GenerateItems(
|
||||
|
||||
const auto fromName = from->name;
|
||||
const auto fromLink = from->createOpenLink();
|
||||
const auto fromLinkText = Ui::Text::Link(fromName, {});
|
||||
const auto fromLinkText = Ui::Text::Link(fromName, QString());
|
||||
|
||||
const auto addSimpleServiceMessage = [&](
|
||||
const TextWithEntities &text,
|
||||
@@ -987,7 +987,7 @@ void GenerateItems(
|
||||
lt_sticker_set,
|
||||
Ui::Text::Link(
|
||||
tr::lng_admin_log_changed_stickers_set(tr::now),
|
||||
{}),
|
||||
QString()),
|
||||
Ui::Text::WithEntities);
|
||||
const auto setLink = std::make_shared<LambdaClickHandler>([=](
|
||||
ClickContext context) {
|
||||
@@ -1072,7 +1072,7 @@ void GenerateItems(
|
||||
lt_from,
|
||||
fromLinkText,
|
||||
lt_chat,
|
||||
Ui::Text::Link(now->name, {}),
|
||||
Ui::Text::Link(now->name, QString()),
|
||||
Ui::Text::WithEntities);
|
||||
const auto chatLink = std::make_shared<LambdaClickHandler>([=] {
|
||||
Ui::showPeerHistory(now, ShowAtUnreadMsgId);
|
||||
@@ -1196,7 +1196,7 @@ void GenerateItems(
|
||||
const auto participantPeerLink = participantPeer->createOpenLink();
|
||||
const auto participantPeerLinkText = Ui::Text::Link(
|
||||
participantPeer->name,
|
||||
{});
|
||||
QString());
|
||||
const auto text = (broadcast
|
||||
? tr::lng_admin_log_muted_participant_channel
|
||||
: tr::lng_admin_log_muted_participant)(
|
||||
@@ -1215,7 +1215,7 @@ void GenerateItems(
|
||||
const auto participantPeerLink = participantPeer->createOpenLink();
|
||||
const auto participantPeerLinkText = Ui::Text::Link(
|
||||
participantPeer->name,
|
||||
{});
|
||||
QString());
|
||||
const auto text = (broadcast
|
||||
? tr::lng_admin_log_unmuted_participant_channel
|
||||
: tr::lng_admin_log_unmuted_participant)(
|
||||
@@ -1319,7 +1319,7 @@ void GenerateItems(
|
||||
const auto participantPeerLink = participantPeer->createOpenLink();
|
||||
const auto participantPeerLinkText = Ui::Text::Link(
|
||||
participantPeer->name,
|
||||
{});
|
||||
QString());
|
||||
const auto volume = data.vparticipant().match([&](
|
||||
const MTPDgroupCallParticipant &data) {
|
||||
return data.vvolume().value_or(10000);
|
||||
@@ -1395,7 +1395,7 @@ void GenerateItems(
|
||||
lt_link,
|
||||
linkText,
|
||||
lt_user,
|
||||
Ui::Text::Link(user->name, {}),
|
||||
Ui::Text::Link(user->name, QString()),
|
||||
Ui::Text::WithEntities),
|
||||
data.vinvite(),
|
||||
user->createOpenLink());
|
||||
|
||||
@@ -131,17 +131,17 @@ void HistoryMessageForwarded::create(const HistoryMessageVia *via) const {
|
||||
phrase = tr::lng_forwarded_channel_via(
|
||||
tr::now,
|
||||
lt_channel,
|
||||
Ui::Text::Link(phrase.text, QString()), // Link 1.
|
||||
Ui::Text::Link(phrase.text, 1), // Link 1.
|
||||
lt_inline_bot,
|
||||
Ui::Text::Link('@' + via->bot->username, {}), // Link 2.
|
||||
Ui::Text::Link('@' + via->bot->username, 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
phrase = tr::lng_forwarded_via(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Link(phrase.text, QString()), // Link 1.
|
||||
Ui::Text::Link(phrase.text, 1), // Link 1.
|
||||
lt_inline_bot,
|
||||
Ui::Text::Link('@' + via->bot->username, {}), // Link 2.
|
||||
Ui::Text::Link('@' + via->bot->username, 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -125,7 +125,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
lt_from,
|
||||
fromLinkText(), // Link 1.
|
||||
lt_user,
|
||||
Ui::Text::Link(u->name, {}), // Link 2.
|
||||
Ui::Text::Link(u->name, 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
} else if (users.isEmpty()) {
|
||||
@@ -143,7 +143,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
auto user = history()->owner().user(users[i].v);
|
||||
result.links.push_back(user->createOpenLink());
|
||||
|
||||
auto linkText = Ui::Text::Link(user->name, {});
|
||||
auto linkText = Ui::Text::Link(user->name, QString());
|
||||
if (i == 0) {
|
||||
result.text = linkText;
|
||||
} else if (i + 1 == l) {
|
||||
@@ -253,7 +253,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
lt_from,
|
||||
fromLinkText(), // Link 1.
|
||||
lt_user,
|
||||
Ui::Text::Link(user->name, {}), // Link 2.
|
||||
Ui::Text::Link(user->name, 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
return result;
|
||||
@@ -364,7 +364,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
result.text = tr::lng_action_secure_values_sent(
|
||||
tr::now,
|
||||
lt_user,
|
||||
Ui::Text::Link(history()->peer->name, {}), // Link 1.
|
||||
Ui::Text::Link(history()->peer->name, QString()), // Link 1.
|
||||
lt_documents,
|
||||
{ .text = documents.join(", ") },
|
||||
Ui::Text::WithEntities);
|
||||
@@ -412,14 +412,14 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
lt_distance,
|
||||
{ .text = distance },
|
||||
lt_user,
|
||||
Ui::Text::Link(toPeer->name, {}), // Link 1.
|
||||
Ui::Text::Link(toPeer->name, QString()), // Link 1.
|
||||
Ui::Text::WithEntities);
|
||||
} else if (toId == selfId) {
|
||||
result.links.push_back(fromPeer->createOpenLink());
|
||||
return tr::lng_action_proximity_reached_you(
|
||||
tr::now,
|
||||
lt_from,
|
||||
Ui::Text::Link(fromPeer->name, {}), // Link 1.
|
||||
Ui::Text::Link(fromPeer->name, QString()), // Link 1.
|
||||
lt_distance,
|
||||
{ .text = distance },
|
||||
Ui::Text::WithEntities);
|
||||
@@ -429,11 +429,11 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
||||
return tr::lng_action_proximity_reached(
|
||||
tr::now,
|
||||
lt_from,
|
||||
Ui::Text::Link(fromPeer->name, {}), // Link 1.
|
||||
Ui::Text::Link(fromPeer->name, 1), // Link 1.
|
||||
lt_distance,
|
||||
{ .text = distance },
|
||||
lt_user,
|
||||
Ui::Text::Link(toPeer->name, {}), // Link 2.
|
||||
Ui::Text::Link(toPeer->name, 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
}();
|
||||
@@ -796,10 +796,11 @@ HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
|
||||
Ui::Text::WithEntities);
|
||||
auto result = PreparedText{};
|
||||
result.links.push_back(fromLink());
|
||||
auto linkIndex = 1;
|
||||
if (linkCallId) {
|
||||
const auto peer = history()->peer;
|
||||
result.links.push_back(GroupCallClickHandler(peer, linkCallId));
|
||||
chatText = Ui::Text::Link(chatText.text, {});
|
||||
chatText = Ui::Text::Link(chatText.text, ++linkIndex);
|
||||
}
|
||||
if (users.size() == 1) {
|
||||
auto user = owner->user(users[0].v);
|
||||
@@ -809,7 +810,7 @@ HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
|
||||
lt_from,
|
||||
fromLinkText(), // Link 1.
|
||||
lt_user,
|
||||
Ui::Text::Link(user->name, {}), // Link N.
|
||||
Ui::Text::Link(user->name, ++linkIndex), // Link N.
|
||||
lt_chat,
|
||||
chatText,
|
||||
Ui::Text::WithEntities);
|
||||
@@ -828,7 +829,7 @@ HistoryService::PreparedText HistoryService::prepareInvitedToCallText(
|
||||
auto user = owner->user(users[i].v);
|
||||
result.links.push_back(user->createOpenLink());
|
||||
|
||||
auto linkText = Ui::Text::Link(user->name, {});
|
||||
auto linkText = Ui::Text::Link(user->name, ++linkIndex);
|
||||
if (i == 0) {
|
||||
result.text = linkText;
|
||||
} else if (i + 1 == l) {
|
||||
@@ -902,8 +903,11 @@ HistoryService::PreparedText HistoryService::preparePinnedText() {
|
||||
Ui::kQEllipsis);
|
||||
}
|
||||
original = Ui::Text::Wrapped(
|
||||
std::move(original),
|
||||
EntityType::CustomUrl);
|
||||
Ui::Text::Filtered(
|
||||
std::move(original),
|
||||
{ EntityType::Spoiler, EntityType::StrikeOut }),
|
||||
EntityType::CustomUrl,
|
||||
Ui::Text::Link({}, 2).entities.front().data());
|
||||
result.text = tr::lng_action_pinned_message(
|
||||
tr::now,
|
||||
lt_from,
|
||||
@@ -917,7 +921,7 @@ HistoryService::PreparedText HistoryService::preparePinnedText() {
|
||||
lt_from,
|
||||
fromLinkText(), // Link 1.
|
||||
lt_media,
|
||||
Ui::Text::Link(mediaText, {}), // Link 2.
|
||||
Ui::Text::Link(mediaText, 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
}
|
||||
} else if (pinned && pinned->msgId) {
|
||||
@@ -928,7 +932,7 @@ HistoryService::PreparedText HistoryService::preparePinnedText() {
|
||||
lt_from,
|
||||
fromLinkText(), // Link 1.
|
||||
lt_media,
|
||||
Ui::Text::Link(tr::lng_contacts_loading(tr::now), {}), // Link 2.
|
||||
Ui::Text::Link(tr::lng_contacts_loading(tr::now), 2), // Link 2.
|
||||
Ui::Text::WithEntities);
|
||||
} else {
|
||||
result.links.push_back(fromLink());
|
||||
@@ -960,7 +964,7 @@ HistoryService::PreparedText HistoryService::prepareGameScoreText() {
|
||||
column,
|
||||
gamescore->msg->fullId()));
|
||||
auto titleText = game->title;
|
||||
return Ui::Text::Link(titleText, {});
|
||||
return Ui::Text::Link(titleText, QString());
|
||||
}
|
||||
}
|
||||
return tr::lng_deleted_message(tr::now, Ui::Text::WithEntities);
|
||||
@@ -1023,7 +1027,7 @@ HistoryService::PreparedText HistoryService::preparePaymentSentText() {
|
||||
if (payment->msg) {
|
||||
if (const auto media = payment->msg->media()) {
|
||||
if (const auto invoice = media->invoice()) {
|
||||
return Ui::Text::Link(invoice->title, {});
|
||||
return Ui::Text::Link(invoice->title, QString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1207,7 +1211,7 @@ std::unique_ptr<HistoryView::Element> HistoryService::createView(
|
||||
}
|
||||
|
||||
TextWithEntities HistoryService::fromLinkText() const {
|
||||
return Ui::Text::Link(_from->name, {});
|
||||
return Ui::Text::Link(_from->name, 1);
|
||||
}
|
||||
|
||||
ClickHandlerPtr HistoryService::fromLink() const {
|
||||
@@ -1515,7 +1519,7 @@ HistoryService::PreparedText GenerateJoinedText(
|
||||
: tr::lng_action_add_you)(
|
||||
tr::now,
|
||||
lt_from,
|
||||
Ui::Text::Link(inviter->name, {}),
|
||||
Ui::Text::Link(inviter->name, QString()),
|
||||
Ui::Text::WithEntities);
|
||||
return result;
|
||||
} else if (history->peer->isMegagroup()) {
|
||||
@@ -1530,7 +1534,7 @@ HistoryService::PreparedText GenerateJoinedText(
|
||||
result.text = tr::lng_action_user_joined(
|
||||
tr::now,
|
||||
lt_from,
|
||||
Ui::Text::Link(self->name, {}),
|
||||
Ui::Text::Link(self->name, QString()),
|
||||
Ui::Text::WithEntities);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -818,6 +818,13 @@ HistoryWidget::HistoryWidget(
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
if (session().supportMode()) {
|
||||
session().data().chatListEntryRefreshes(
|
||||
) | rpl::start_with_next([=] {
|
||||
crl::on_main(this, [=] { checkSupportPreload(true); });
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
setupScheduledToggle();
|
||||
setupSendAsToggle();
|
||||
orderWidgets();
|
||||
@@ -2299,9 +2306,11 @@ void HistoryWidget::setHistory(History *history) {
|
||||
history->forceFullResize();
|
||||
}
|
||||
};
|
||||
|
||||
if (_history) {
|
||||
unregisterDraftSources();
|
||||
clearAllLoadRequests();
|
||||
clearSupportPreloadRequest();
|
||||
const auto wasHistory = base::take(_history);
|
||||
const auto wasMigrated = base::take(_migrated);
|
||||
unloadHeavyViewParts(wasHistory);
|
||||
@@ -2371,6 +2380,16 @@ void HistoryWidget::clearDelayedShowAtRequest() {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::clearSupportPreloadRequest() {
|
||||
Expects(_history != nullptr);
|
||||
|
||||
if (_supportPreloadRequest) {
|
||||
auto &histories = _history->owner().histories();
|
||||
histories.cancelRequest(_supportPreloadRequest);
|
||||
_supportPreloadRequest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::clearAllLoadRequests() {
|
||||
Expects(_history != nullptr);
|
||||
|
||||
@@ -2990,6 +3009,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
|
||||
setMsgId(_delayedShowAtMsgId);
|
||||
historyLoaded();
|
||||
}
|
||||
if (session().supportMode()) {
|
||||
crl::on_main(this, [=] { checkSupportPreload(); });
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::historyLoaded() {
|
||||
@@ -3337,6 +3359,88 @@ void HistoryWidget::preloadHistoryByScroll() {
|
||||
if (scrollTop <= kPreloadHeightsCount * scrollHeight) {
|
||||
loadMessages();
|
||||
}
|
||||
if (session().supportMode()) {
|
||||
crl::on_main(this, [=] { checkSupportPreload(); });
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::checkSupportPreload(bool force) {
|
||||
if (!_history
|
||||
|| _firstLoadRequest
|
||||
|| _preloadRequest
|
||||
|| _preloadDownRequest
|
||||
|| (_supportPreloadRequest && !force)
|
||||
|| controller()->activeChatEntryCurrent().key.history() != _history) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto setting = session().settings().supportSwitch();
|
||||
const auto command = Support::GetSwitchCommand(setting);
|
||||
const auto descriptor = !command
|
||||
? Dialogs::RowDescriptor()
|
||||
: (*command == Shortcuts::Command::ChatNext)
|
||||
? controller()->resolveChatNext()
|
||||
: controller()->resolveChatPrevious();
|
||||
auto history = descriptor.key.history();
|
||||
if (!history || _supportPreloadHistory == history) {
|
||||
return;
|
||||
}
|
||||
clearSupportPreloadRequest();
|
||||
_supportPreloadHistory = history;
|
||||
auto offsetId = MsgId();
|
||||
auto offset = 0;
|
||||
auto loadCount = kMessagesPerPage;
|
||||
if (const auto around = history->loadAroundId()) {
|
||||
history->getReadyFor(ShowAtUnreadMsgId);
|
||||
offset = -loadCount / 2;
|
||||
offsetId = around;
|
||||
}
|
||||
const auto offsetDate = 0;
|
||||
const auto maxId = 0;
|
||||
const auto minId = 0;
|
||||
const auto historyHash = uint64(0);
|
||||
const auto type = Data::Histories::RequestType::History;
|
||||
auto &histories = history->owner().histories();
|
||||
_supportPreloadRequest = histories.sendRequest(history, type, [=](Fn<void()> finish) {
|
||||
return history->session().api().request(MTPmessages_GetHistory(
|
||||
history->peer->input,
|
||||
MTP_int(offsetId),
|
||||
MTP_int(offsetDate),
|
||||
MTP_int(offset),
|
||||
MTP_int(loadCount),
|
||||
MTP_int(maxId),
|
||||
MTP_int(minId),
|
||||
MTP_long(historyHash)
|
||||
)).done([=](const MTPmessages_Messages &result) {
|
||||
if (const auto around = history->loadAroundId()) {
|
||||
if (around != offsetId) {
|
||||
_supportPreloadRequest = 0;
|
||||
_supportPreloadHistory = nullptr;
|
||||
crl::on_main(this, [=] { checkSupportPreload(); });
|
||||
return;
|
||||
}
|
||||
history->clear(History::ClearType::Unload);
|
||||
history->getReadyFor(ShowAtUnreadMsgId);
|
||||
} else if (offsetId) {
|
||||
_supportPreloadRequest = 0;
|
||||
_supportPreloadHistory = nullptr;
|
||||
crl::on_main(this, [=] { checkSupportPreload(); });
|
||||
return;
|
||||
} else {
|
||||
history->clear(History::ClearType::Unload);
|
||||
history->getReadyFor(ShowAtTheEndMsgId);
|
||||
}
|
||||
result.match([](const MTPDmessages_messagesNotModified&) {
|
||||
}, [&](const auto &data) {
|
||||
history->owner().processUsers(data.vusers());
|
||||
history->owner().processChats(data.vchats());
|
||||
history->addOlderSlice(data.vmessages().v);
|
||||
});
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
finish();
|
||||
}).send();
|
||||
});
|
||||
}
|
||||
|
||||
void HistoryWidget::checkReplyReturns() {
|
||||
@@ -7534,10 +7638,7 @@ HistoryWidget::~HistoryWidget() {
|
||||
// Saving a draft on account switching.
|
||||
saveFieldToHistoryLocalDraft();
|
||||
session().api().saveDraftToCloudDelayed(_history);
|
||||
|
||||
clearAllLoadRequests();
|
||||
setHistory(nullptr);
|
||||
unregisterDraftSources();
|
||||
}
|
||||
setTabbedPanel(nullptr);
|
||||
}
|
||||
|
||||
@@ -234,6 +234,7 @@ public:
|
||||
Ui::ReportReason reason,
|
||||
Fn<void(MessageIdsList)> callback);
|
||||
void clearAllLoadRequests();
|
||||
void clearSupportPreloadRequest();
|
||||
void clearDelayedShowAtRequest();
|
||||
void clearDelayedShowAt();
|
||||
void saveFieldToHistoryLocalDraft();
|
||||
@@ -598,6 +599,7 @@ private:
|
||||
bool readyToForward() const;
|
||||
bool hasSilentToggle() const;
|
||||
|
||||
void checkSupportPreload(bool force = false);
|
||||
void handleSupportSwitch(not_null<History*> updated);
|
||||
|
||||
void inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result);
|
||||
@@ -685,6 +687,9 @@ private:
|
||||
MsgId _delayedShowAtMsgId = -1;
|
||||
int _delayedShowAtRequest = 0; // Not real mtpRequestId.
|
||||
|
||||
History *_supportPreloadHistory = nullptr;
|
||||
int _supportPreloadRequest = 0; // Not real mtpRequestId.
|
||||
|
||||
object_ptr<HistoryView::TopBarWidget> _topBar;
|
||||
object_ptr<Ui::ContinuousScroll> _scroll;
|
||||
QPointer<HistoryInner> _list;
|
||||
|
||||
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "platform/platform_specific.h"
|
||||
#include "core/crash_reports.h"
|
||||
#include "core/launcher.h"
|
||||
#include "mtproto/facade.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -569,10 +570,43 @@ void writeTcp(const QString &v) {
|
||||
}
|
||||
|
||||
void writeMtp(int32 dc, const QString &v) {
|
||||
const auto msg = QString("%1 (dc:%2) %3\n").arg(
|
||||
_logsEntryStart(),
|
||||
QString::number(dc),
|
||||
v);
|
||||
const auto expanded = [&] {
|
||||
const auto bare = MTP::isTemporaryDcId(dc)
|
||||
? MTP::getRealIdFromTemporaryDcId(dc)
|
||||
: MTP::BareDcId(dc);
|
||||
const auto base = (MTP::isTemporaryDcId(dc) ? "temporary_" : "")
|
||||
+ QString::number(bare);
|
||||
const auto shift = MTP::GetDcIdShift(dc);
|
||||
if (shift == 0) {
|
||||
return base + "_main";
|
||||
} else if (shift == MTP::kExportDcShift) {
|
||||
return base + "_export";
|
||||
} else if (shift == MTP::kExportMediaDcShift) {
|
||||
return base + "_export_download";
|
||||
} else if (shift == MTP::kConfigDcShift) {
|
||||
return base + "_config_enumeration";
|
||||
} else if (shift == MTP::kLogoutDcShift) {
|
||||
return base + "_logout_guest";
|
||||
} else if (shift == MTP::kUpdaterDcShift) {
|
||||
return base + "_download_update";
|
||||
} else if (shift == MTP::kGroupCallStreamDcShift) {
|
||||
return base + "_stream";
|
||||
} else if (MTP::isDownloadDcId(dc)) {
|
||||
const auto index = shift - MTP::kBaseDownloadDcShift;
|
||||
return base + "_download" + QString::number(index);
|
||||
} else if (MTP::isUploadDcId(dc)) {
|
||||
const auto index = shift - MTP::kBaseUploadDcShift;
|
||||
return base + "_upload" + QString::number(index);
|
||||
} else if (shift >= MTP::kDestroyKeyStartDcShift) {
|
||||
const auto index = shift - MTP::kDestroyKeyStartDcShift;
|
||||
return base + "_key_destroyer" + QString::number(index);
|
||||
}
|
||||
return base + "_unknown" + QString::number(shift);
|
||||
}();
|
||||
const auto msg = _logsEntryStart()
|
||||
+ u" (dc:%1) "_q.arg(expanded)
|
||||
+ v
|
||||
+ '\n';
|
||||
_logsWrite(LogDataMtp, msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -1779,6 +1779,16 @@ bool MainWidget::isThirdSectionShown() const {
|
||||
return _thirdSection != nullptr;
|
||||
}
|
||||
|
||||
Dialogs::RowDescriptor MainWidget::resolveChatNext(
|
||||
Dialogs::RowDescriptor from) const {
|
||||
return _dialogs ? _dialogs->resolveChatNext(from) : Dialogs::RowDescriptor();
|
||||
}
|
||||
|
||||
Dialogs::RowDescriptor MainWidget::resolveChatPrevious(
|
||||
Dialogs::RowDescriptor from) const {
|
||||
return _dialogs ? _dialogs->resolveChatPrevious(from) : Dialogs::RowDescriptor();
|
||||
}
|
||||
|
||||
bool MainWidget::stackIsEmpty() const {
|
||||
return _stack.empty();
|
||||
}
|
||||
|
||||
@@ -128,6 +128,11 @@ public:
|
||||
[[nodiscard]] bool isMainSectionShown() const;
|
||||
[[nodiscard]] bool isThirdSectionShown() const;
|
||||
|
||||
[[nodiscard]] Dialogs::RowDescriptor resolveChatNext(
|
||||
Dialogs::RowDescriptor from) const;
|
||||
[[nodiscard]] Dialogs::RowDescriptor resolveChatPrevious(
|
||||
Dialogs::RowDescriptor from) const;
|
||||
|
||||
void returnTabbedSelector();
|
||||
|
||||
void showAnimated(const QPixmap &bgAnimCache, bool back = false);
|
||||
|
||||
@@ -16,6 +16,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
|
||||
namespace MTP {
|
||||
namespace details {
|
||||
namespace {
|
||||
|
||||
std::atomic<int> GlobalConnectionCounter/* = 0*/;
|
||||
|
||||
} // namespace
|
||||
|
||||
ConnectionPointer::ConnectionPointer() = default;
|
||||
|
||||
@@ -158,7 +163,8 @@ std::optional<MTPResPQ> AbstractConnection::readPQFakeReply(
|
||||
AbstractConnection::AbstractConnection(
|
||||
QThread *thread,
|
||||
const ProxyData &proxy)
|
||||
: _proxy(proxy) {
|
||||
: _proxy(proxy)
|
||||
, _debugId(QString::number(++GlobalConnectionCounter)) {
|
||||
moveToThread(thread);
|
||||
}
|
||||
|
||||
@@ -188,6 +194,24 @@ ConnectionPointer AbstractConnection::Create(
|
||||
return result;
|
||||
}
|
||||
|
||||
QString AbstractConnection::ProtocolDcDebugId(int16 protocolDcId) {
|
||||
const auto postfix = (protocolDcId < 0) ? "_media" : "";
|
||||
protocolDcId = (protocolDcId < 0) ? (-protocolDcId) : protocolDcId;
|
||||
const auto prefix = (protocolDcId > kTestModeDcIdShift) ? "test_" : "";
|
||||
protocolDcId = (protocolDcId > kTestModeDcIdShift)
|
||||
? (protocolDcId - kTestModeDcIdShift)
|
||||
: protocolDcId;
|
||||
return prefix + QString::number(protocolDcId) + postfix;
|
||||
}
|
||||
|
||||
void AbstractConnection::logInfo(const QString &message) {
|
||||
DEBUG_LOG(("Connection %1 Info: ").arg(_debugId) + message);
|
||||
}
|
||||
|
||||
void AbstractConnection::logError(const QString &message) {
|
||||
DEBUG_LOG(("Connection %1 Error: ").arg(_debugId) + message);
|
||||
}
|
||||
|
||||
uint32 AbstractConnection::extendedNotSecurePadding() const {
|
||||
return uint32(base::RandomValue<uchar>() & 0x3F);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ struct ConnectionOptions;
|
||||
|
||||
class AbstractConnection;
|
||||
|
||||
inline constexpr auto kTestModeDcIdShift = 10000;
|
||||
|
||||
class ConnectionPointer {
|
||||
public:
|
||||
ConnectionPointer();
|
||||
@@ -122,6 +124,13 @@ public:
|
||||
[[nodiscard]] gsl::span<const mtpPrime> parseNotSecureResponse(
|
||||
const mtpBuffer &buffer) const;
|
||||
|
||||
[[nodiscard]] static QString ProtocolDcDebugId(int16 protocolDcId);
|
||||
[[nodiscard]] QString debugId() const {
|
||||
return _debugId;
|
||||
}
|
||||
void logInfo(const QString &message);
|
||||
void logError(const QString &message);
|
||||
|
||||
// Used to emit error(...) with no real code from the server.
|
||||
static constexpr auto kErrorCodeOther = -499;
|
||||
|
||||
@@ -141,6 +150,8 @@ protected:
|
||||
int _pingTime = 0;
|
||||
ProxyData _proxy;
|
||||
|
||||
QString _debugId;
|
||||
|
||||
// first we always send fake MTPReq_pq to see if connection works at all
|
||||
// we send them simultaneously through TCP/HTTP/IPv4/IPv6 to choose the working one
|
||||
[[nodiscard]] mtpBuffer preparePQFake(const MTPint128 &nonce) const;
|
||||
@@ -193,5 +204,8 @@ mtpBuffer AbstractConnection::prepareNotSecurePacket(
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CONNECTION_LOG_INFO(x) if (Logs::DebugEnabled()) { logInfo(x); }
|
||||
#define CONNECTION_LOG_ERROR(x) if (Logs::DebugEnabled()) { logError(x); }
|
||||
|
||||
} // namespace details
|
||||
} // namespace MTP
|
||||
|
||||
@@ -43,7 +43,7 @@ void HttpConnection::sendData(mtpBuffer &&buffer) {
|
||||
request.setHeader(QNetworkRequest::ContentLengthHeader, QVariant(requestSize));
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(qsl("application/x-www-form-urlencoded")));
|
||||
|
||||
TCP_LOG(("HTTP Info: sending %1 len request").arg(requestSize));
|
||||
CONNECTION_LOG_INFO(u"Sending %1 len request."_q.arg(requestSize));
|
||||
_requests.insert(_manager.post(request, QByteArray((const char*)(&buffer[2]), requestSize)));
|
||||
}
|
||||
|
||||
@@ -78,10 +78,12 @@ void HttpConnection::connectToServer(
|
||||
|
||||
auto buffer = preparePQFake(_checkNonce);
|
||||
|
||||
DEBUG_LOG(("HTTP Info: "
|
||||
"dc:%1 - Sending fake req_pq to '%2'"
|
||||
).arg(protocolDcId
|
||||
).arg(url().toDisplayString()));
|
||||
if (Logs::DebugEnabled()) {
|
||||
_debugId = u"%1(dc:%2,%3)"_q
|
||||
.arg(_debugId.toInt())
|
||||
.arg(ProtocolDcDebugId(protocolDcId))
|
||||
.arg(url().toDisplayString());
|
||||
}
|
||||
|
||||
_pingTime = crl::now();
|
||||
sendData(std::move(buffer));
|
||||
@@ -89,12 +91,12 @@ void HttpConnection::connectToServer(
|
||||
|
||||
mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) {
|
||||
QByteArray response = reply->readAll();
|
||||
TCP_LOG(("HTTP Info: read %1 bytes").arg(response.size()));
|
||||
CONNECTION_LOG_INFO(u"Read %1 bytes."_q.arg(response.size()));
|
||||
|
||||
if (response.isEmpty()) return mtpBuffer();
|
||||
|
||||
if (response.size() & 0x03 || response.size() < 8) {
|
||||
LOG(("HTTP Error: bad response size %1").arg(response.size()));
|
||||
CONNECTION_LOG_ERROR(u"Bad response size %1."_q.arg(response.size()));
|
||||
return mtpBuffer(1, -500);
|
||||
}
|
||||
|
||||
@@ -104,31 +106,46 @@ mtpBuffer HttpConnection::handleResponse(QNetworkReply *reply) {
|
||||
return data;
|
||||
}
|
||||
|
||||
qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe bad key"
|
||||
// Returns "maybe bad key".
|
||||
qint32 HttpConnection::handleError(QNetworkReply *reply) {
|
||||
auto result = qint32(kErrorCodeOther);
|
||||
|
||||
QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
|
||||
QVariant statusCode = reply->attribute(
|
||||
QNetworkRequest::HttpStatusCodeAttribute);
|
||||
if (statusCode.isValid()) {
|
||||
int status = statusCode.toInt();
|
||||
result = -status;
|
||||
}
|
||||
|
||||
switch (reply->error()) {
|
||||
case QNetworkReply::ConnectionRefusedError: LOG(("HTTP Error: connection refused - %1").arg(reply->errorString())); break;
|
||||
case QNetworkReply::RemoteHostClosedError: LOG(("HTTP Error: remote host closed - %1").arg(reply->errorString())); break;
|
||||
case QNetworkReply::HostNotFoundError: LOG(("HTTP Error: host not found - %1").arg(reply->errorString())); break;
|
||||
case QNetworkReply::TimeoutError: LOG(("HTTP Error: timeout - %1").arg(reply->errorString())); break;
|
||||
case QNetworkReply::OperationCanceledError: LOG(("HTTP Error: cancelled - %1").arg(reply->errorString())); break;
|
||||
case QNetworkReply::ConnectionRefusedError:
|
||||
CONNECTION_LOG_ERROR(u"Connection refused - %1."_q
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
case QNetworkReply::RemoteHostClosedError:
|
||||
CONNECTION_LOG_ERROR(u"Remote host closed - %1."_q
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
case QNetworkReply::HostNotFoundError:
|
||||
CONNECTION_LOG_ERROR(u"Host not found - %1."_q
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
case QNetworkReply::TimeoutError:
|
||||
CONNECTION_LOG_ERROR(u"Timeout - %1."_q
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
case QNetworkReply::OperationCanceledError:
|
||||
CONNECTION_LOG_ERROR(u"Cancelled - %1."_q
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
case QNetworkReply::SslHandshakeFailedError:
|
||||
case QNetworkReply::TemporaryNetworkFailureError:
|
||||
case QNetworkReply::NetworkSessionFailedError:
|
||||
case QNetworkReply::BackgroundRequestNotAllowedError:
|
||||
case QNetworkReply::UnknownNetworkError:
|
||||
if (reply->error() == QNetworkReply::UnknownNetworkError) {
|
||||
DEBUG_LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString()));
|
||||
} else {
|
||||
LOG(("HTTP Error: network error %1 - %2").arg(reply->error()).arg(reply->errorString()));
|
||||
}
|
||||
CONNECTION_LOG_ERROR(u"Network error %1 - %2."_q
|
||||
.arg(reply->error())
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
|
||||
// proxy errors (101-199):
|
||||
@@ -137,7 +154,11 @@ qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe ba
|
||||
case QNetworkReply::ProxyNotFoundError:
|
||||
case QNetworkReply::ProxyTimeoutError:
|
||||
case QNetworkReply::ProxyAuthenticationRequiredError:
|
||||
case QNetworkReply::UnknownProxyError: LOG(("HTTP Error: proxy error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||
case QNetworkReply::UnknownProxyError:
|
||||
CONNECTION_LOG_ERROR(u"Proxy error %1 - %2."_q
|
||||
.arg(reply->error())
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
|
||||
// content errors (201-299):
|
||||
case QNetworkReply::ContentAccessDenied:
|
||||
@@ -145,14 +166,21 @@ qint32 HttpConnection::handleError(QNetworkReply *reply) { // returnes "maybe ba
|
||||
case QNetworkReply::ContentNotFoundError:
|
||||
case QNetworkReply::AuthenticationRequiredError:
|
||||
case QNetworkReply::ContentReSendError:
|
||||
case QNetworkReply::UnknownContentError: LOG(("HTTP Error: content error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||
case QNetworkReply::UnknownContentError:
|
||||
CONNECTION_LOG_ERROR(u"Content error %1 - %2."_q
|
||||
.arg(reply->error())
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
|
||||
// protocol errors
|
||||
case QNetworkReply::ProtocolUnknownError:
|
||||
case QNetworkReply::ProtocolInvalidOperationError:
|
||||
case QNetworkReply::ProtocolFailure: LOG(("HTTP Error: protocol error %1 - %2").arg(reply->error()).arg(reply->errorString())); break;
|
||||
case QNetworkReply::ProtocolFailure:
|
||||
CONNECTION_LOG_ERROR(u"Protocol error %1 - %2."_q
|
||||
.arg(reply->error())
|
||||
.arg(reply->errorString()));
|
||||
break;
|
||||
};
|
||||
TCP_LOG(("HTTP Error %1, restarting! - %2").arg(reply->error()).arg(reply->errorString()));
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -178,20 +206,19 @@ void HttpConnection::requestFinished(QNetworkReply *reply) {
|
||||
} else if (const auto res_pq = readPQFakeReply(data)) {
|
||||
const auto &data = res_pq->c_resPQ();
|
||||
if (data.vnonce() == _checkNonce) {
|
||||
DEBUG_LOG(("Connection Info: "
|
||||
"HTTP-transport to %1 connected by pq-response"
|
||||
).arg(_address));
|
||||
CONNECTION_LOG_INFO(
|
||||
"HTTP-transport connected by pq-response.");
|
||||
_status = Status::Ready;
|
||||
_pingTime = crl::now() - _pingTime;
|
||||
connected();
|
||||
} else {
|
||||
DEBUG_LOG(("Connection Error: "
|
||||
"Wrong nonce received in HTTP fake pq-responce"));
|
||||
CONNECTION_LOG_ERROR(
|
||||
"Wrong nonce in HTTP fake pq-response.");
|
||||
error(kErrorCodeOther);
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG(("Connection Error: "
|
||||
"Could not parse HTTP fake pq-responce"));
|
||||
CONNECTION_LOG_ERROR(
|
||||
"Could not parse HTTP fake pq-response.");
|
||||
error(kErrorCodeOther);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ public:
|
||||
QString transport() const override;
|
||||
QString tag() const override;
|
||||
|
||||
static mtpBuffer handleResponse(QNetworkReply *reply);
|
||||
static qint32 handleError(QNetworkReply *reply); // Returns error code.
|
||||
mtpBuffer handleResponse(QNetworkReply *reply);
|
||||
qint32 handleError(QNetworkReply *reply); // Returns error code.
|
||||
|
||||
private:
|
||||
QUrl url() const;
|
||||
|
||||
@@ -72,12 +72,6 @@ void ResolvingConnection::setChild(ConnectionPointer &&child) {
|
||||
&AbstractConnection::disconnected,
|
||||
this,
|
||||
&ResolvingConnection::handleDisconnected);
|
||||
DEBUG_LOG(("Resolving Info: dc:%1 proxy '%2' got new child '%3'").arg(
|
||||
QString::number(_protocolDcId),
|
||||
_proxy.host + ':' + QString::number(_proxy.port),
|
||||
(_ipIndex >= 0 && _ipIndex < _proxy.resolvedIPs.size())
|
||||
? _proxy.resolvedIPs[_ipIndex]
|
||||
: _proxy.host));
|
||||
if (_protocolDcId) {
|
||||
_child->connectToServer(
|
||||
_address,
|
||||
@@ -85,6 +79,8 @@ void ResolvingConnection::setChild(ConnectionPointer &&child) {
|
||||
_protocolSecret,
|
||||
_protocolDcId,
|
||||
_protocolForFiles);
|
||||
CONNECTION_LOG_INFO("Resolving connected a new child: "
|
||||
+ _child->debugId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,18 +220,13 @@ void ResolvingConnection::connectToServer(
|
||||
_protocolSecret = protocolSecret;
|
||||
_protocolDcId = protocolDcId;
|
||||
_protocolForFiles = protocolForFiles;
|
||||
DEBUG_LOG(("Resolving Info: dc:%1 proxy '%2' connects a child '%3'").arg(
|
||||
QString::number(_protocolDcId),
|
||||
_proxy.host +':' + QString::number(_proxy.port),
|
||||
(_ipIndex >= 0 && _ipIndex < _proxy.resolvedIPs.size())
|
||||
? _proxy.resolvedIPs[_ipIndex]
|
||||
: _proxy.host));
|
||||
return _child->connectToServer(
|
||||
_child->connectToServer(
|
||||
address,
|
||||
port,
|
||||
protocolSecret,
|
||||
protocolDcId,
|
||||
protocolForFiles);
|
||||
CONNECTION_LOG_INFO("Resolving connected a child: " + _child->debugId());
|
||||
}
|
||||
|
||||
bool ResolvingConnection::isConnected() const {
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
virtual int readPacketLength(bytes::const_span bytes) const = 0;
|
||||
virtual bytes::const_span readPacket(bytes::const_span bytes) const = 0;
|
||||
|
||||
virtual QString debugPostfix() const = 0;
|
||||
|
||||
virtual ~Protocol() = default;
|
||||
|
||||
private:
|
||||
@@ -60,6 +62,8 @@ public:
|
||||
int readPacketLength(bytes::const_span bytes) const override;
|
||||
bytes::const_span readPacket(bytes::const_span bytes) const override;
|
||||
|
||||
QString debugPostfix() const override;
|
||||
|
||||
};
|
||||
|
||||
uint32 TcpConnection::Protocol::Version0::id() const {
|
||||
@@ -129,12 +133,18 @@ bytes::const_span TcpConnection::Protocol::Version0::readPacket(
|
||||
return bytes.subspan(sizeLength, size - sizeLength);
|
||||
}
|
||||
|
||||
QString TcpConnection::Protocol::Version0::debugPostfix() const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
class TcpConnection::Protocol::Version1 : public Version0 {
|
||||
public:
|
||||
explicit Version1(bytes::vector &&secret);
|
||||
|
||||
void prepareKey(bytes::span key, bytes::const_span source) override;
|
||||
|
||||
QString debugPostfix() const override;
|
||||
|
||||
private:
|
||||
bytes::vector _secret;
|
||||
|
||||
@@ -151,6 +161,10 @@ void TcpConnection::Protocol::Version1::prepareKey(
|
||||
bytes::copy(key, openssl::Sha256(payload));
|
||||
}
|
||||
|
||||
QString TcpConnection::Protocol::Version1::debugPostfix() const {
|
||||
return u"_obf"_q;
|
||||
}
|
||||
|
||||
class TcpConnection::Protocol::VersionD : public Version1 {
|
||||
public:
|
||||
using Version1::Version1;
|
||||
@@ -163,6 +177,8 @@ public:
|
||||
int readPacketLength(bytes::const_span bytes) const override;
|
||||
bytes::const_span readPacket(bytes::const_span bytes) const override;
|
||||
|
||||
QString debugPostfix() const override;
|
||||
|
||||
};
|
||||
|
||||
uint32 TcpConnection::Protocol::VersionD::id() const {
|
||||
@@ -209,6 +225,10 @@ bytes::const_span TcpConnection::Protocol::VersionD::readPacket(
|
||||
return bytes.subspan(sizeLength, size - sizeLength);
|
||||
}
|
||||
|
||||
QString TcpConnection::Protocol::VersionD::debugPostfix() const {
|
||||
return u"_dd"_q;
|
||||
}
|
||||
|
||||
auto TcpConnection::Protocol::Create(bytes::const_span secret)
|
||||
-> std::unique_ptr<Protocol> {
|
||||
// See also DcOptions::ValidateSecret.
|
||||
@@ -269,7 +289,7 @@ void TcpConnection::socketRead() {
|
||||
Expects(_leftBytes > 0 || !_usingLargeBuffer);
|
||||
|
||||
if (!_socket || !_socket->isConnected()) {
|
||||
LOG(("MTP Error: Socket not connected in socketRead()"));
|
||||
CONNECTION_LOG_ERROR("Socket not connected in socketRead()");
|
||||
error(kErrorCodeOther);
|
||||
return;
|
||||
}
|
||||
@@ -290,7 +310,7 @@ void TcpConnection::socketRead() {
|
||||
if (readCount > 0) {
|
||||
const auto read = free.subspan(0, readCount);
|
||||
aesCtrEncrypt(read, _receiveKey, &_receiveState);
|
||||
TCP_LOG(("TCP Info: read %1 bytes").arg(readCount));
|
||||
CONNECTION_LOG_INFO(u"Read %1 bytes"_q.arg(readCount));
|
||||
|
||||
_readBytes += readCount;
|
||||
if (_leftBytes > 0) {
|
||||
@@ -306,9 +326,10 @@ void TcpConnection::socketRead() {
|
||||
_largeBuffer.clear();
|
||||
_offsetBytes = _readBytes = 0;
|
||||
} else {
|
||||
TCP_LOG(("TCP Info: not enough %1 for packet! read %2"
|
||||
).arg(_leftBytes
|
||||
).arg(_readBytes));
|
||||
CONNECTION_LOG_INFO(
|
||||
u"Not enough %1 for packet! read %2"_q
|
||||
.arg(_leftBytes)
|
||||
.arg(_readBytes));
|
||||
receivedSome();
|
||||
}
|
||||
} else {
|
||||
@@ -320,8 +341,9 @@ void TcpConnection::socketRead() {
|
||||
// Not enough bytes yet.
|
||||
break;
|
||||
} else if (packetSize <= 0) {
|
||||
LOG(("TCP Error: bad packet size in 4 bytes: %1"
|
||||
).arg(packetSize));
|
||||
CONNECTION_LOG_ERROR(
|
||||
u"Bad packet size in 4 bytes: %1"_q
|
||||
.arg(packetSize));
|
||||
error(kErrorCodeOther);
|
||||
return;
|
||||
} else if (available.size() >= packetSize) {
|
||||
@@ -342,22 +364,23 @@ void TcpConnection::socketRead() {
|
||||
// If the next packet won't fit in the buffer.
|
||||
ensureAvailableInBuffer(packetSize);
|
||||
|
||||
TCP_LOG(("TCP Info: not enough %1 for packet! "
|
||||
"full size %2 read %3"
|
||||
).arg(_leftBytes
|
||||
).arg(packetSize
|
||||
).arg(available.size()));
|
||||
CONNECTION_LOG_INFO(u"Not enough %1 for packet! "
|
||||
"full size %2 read %3"_q
|
||||
.arg(_leftBytes)
|
||||
.arg(packetSize)
|
||||
.arg(available.size()));
|
||||
receivedSome();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (readCount < 0) {
|
||||
LOG(("TCP Error: socket read return %1").arg(readCount));
|
||||
CONNECTION_LOG_ERROR(u"Socket read return %1."_q.arg(readCount));
|
||||
error(kErrorCodeOther);
|
||||
return;
|
||||
} else {
|
||||
TCP_LOG(("TCP Info: no bytes read, but bytes available was true..."));
|
||||
CONNECTION_LOG_INFO(
|
||||
"No bytes read, but bytes available was true...");
|
||||
break;
|
||||
}
|
||||
} while (_socket
|
||||
@@ -367,8 +390,7 @@ void TcpConnection::socketRead() {
|
||||
|
||||
mtpBuffer TcpConnection::parsePacket(bytes::const_span bytes) {
|
||||
const auto packet = _protocol->readPacket(bytes);
|
||||
TCP_LOG(("TCP Info: packet received, size = %1"
|
||||
).arg(packet.size()));
|
||||
CONNECTION_LOG_INFO(u"Packet received, size = %1."_q.arg(packet.size()));
|
||||
const auto ints = gsl::make_span(
|
||||
reinterpret_cast<const mtpPrime*>(packet.data()),
|
||||
packet.size() / sizeof(mtpPrime));
|
||||
@@ -376,13 +398,8 @@ mtpBuffer TcpConnection::parsePacket(bytes::const_span bytes) {
|
||||
if (ints.size() < 3) {
|
||||
// nop or error or new quickack, latter is not yet supported.
|
||||
if (ints[0] != 0) {
|
||||
LOG(("TCP Error: "
|
||||
"error packet received, endpoint: '%1:%2', "
|
||||
"protocolDcId: %3, code = %4"
|
||||
).arg(_address.isEmpty() ? ("prx_" + _proxy.host) : _address
|
||||
).arg(_address.isEmpty() ? _proxy.port : _port
|
||||
).arg(_protocolDcId
|
||||
).arg(ints[0]));
|
||||
CONNECTION_LOG_ERROR(u"Error packet received, code = %1"_q
|
||||
.arg(ints[0]));
|
||||
}
|
||||
return mtpBuffer(1, ints[0]);
|
||||
}
|
||||
@@ -396,10 +413,7 @@ void TcpConnection::socketConnected() {
|
||||
|
||||
auto buffer = preparePQFake(_checkNonce);
|
||||
|
||||
DEBUG_LOG(("TCP Info: "
|
||||
"dc:%1 - Sending fake req_pq to '%2'"
|
||||
).arg(_protocolDcId
|
||||
).arg(_address + ':' + QString::number(_port)));
|
||||
CONNECTION_LOG_INFO("Sending fake req_pq.");
|
||||
|
||||
_pingTime = crl::now();
|
||||
sendData(std::move(buffer));
|
||||
@@ -423,7 +437,8 @@ void TcpConnection::sendData(mtpBuffer &&buffer) {
|
||||
|
||||
// buffer: 2 available int-s + data + available int.
|
||||
const auto bytes = _protocol->finalizePacket(buffer);
|
||||
TCP_LOG(("TCP Info: write packet %1 bytes").arg(bytes.size()));
|
||||
CONNECTION_LOG_INFO(u"TCP Info: write packet %1 bytes."_q
|
||||
.arg(bytes.size()));
|
||||
aesCtrEncrypt(bytes, _sendKey, &_sendState);
|
||||
_socket->write(connectionStartPrefix, bytes);
|
||||
}
|
||||
@@ -506,20 +521,10 @@ void TcpConnection::connectToServer(
|
||||
_address = _proxy.host;
|
||||
_port = _proxy.port;
|
||||
_protocol = Protocol::Create(secret);
|
||||
|
||||
DEBUG_LOG(("TCP Info: "
|
||||
"dc:%1 - Connecting to proxy '%2'"
|
||||
).arg(protocolDcId
|
||||
).arg(_address + ':' + QString::number(_port)));
|
||||
} else {
|
||||
_address = address;
|
||||
_port = port;
|
||||
_protocol = Protocol::Create(secret);
|
||||
|
||||
DEBUG_LOG(("TCP Info: "
|
||||
"dc:%1 - Connecting to '%2'"
|
||||
).arg(protocolDcId
|
||||
).arg(_address + ':' + QString::number(_port)));
|
||||
}
|
||||
_socket = AbstractSocket::Create(
|
||||
thread(),
|
||||
@@ -528,6 +533,18 @@ void TcpConnection::connectToServer(
|
||||
protocolForFiles);
|
||||
_protocolDcId = protocolDcId;
|
||||
|
||||
const auto postfix = _socket->debugPostfix();
|
||||
_debugId = u"%1(dc:%2,%3%4:%5%6)"_q
|
||||
.arg(_debugId.toInt())
|
||||
.arg(ProtocolDcDebugId(_protocolDcId))
|
||||
.arg((_proxy.type == ProxyData::Type::Mtproto) ? "mtproxy " : "")
|
||||
.arg(_address)
|
||||
.arg(_port)
|
||||
.arg(postfix.isEmpty() ? _protocol->debugPostfix() : postfix);
|
||||
_socket->setDebugId(_debugId);
|
||||
|
||||
CONNECTION_LOG_INFO("Connecting...");
|
||||
|
||||
_socket->connected(
|
||||
) | rpl::start_with_next([=] {
|
||||
socketConnected();
|
||||
@@ -584,19 +601,18 @@ void TcpConnection::socketPacket(bytes::const_span bytes) {
|
||||
if (const auto res_pq = readPQFakeReply(data)) {
|
||||
const auto &data = res_pq->c_resPQ();
|
||||
if (data.vnonce() == _checkNonce) {
|
||||
DEBUG_LOG(("Connection Info: Valid pq response by TCP."));
|
||||
CONNECTION_LOG_INFO("Valid pq response by TCP.");
|
||||
_status = Status::Ready;
|
||||
_connectedLifetime.destroy();
|
||||
_pingTime = (crl::now() - _pingTime);
|
||||
connected();
|
||||
} else {
|
||||
DEBUG_LOG(("Connection Error: "
|
||||
"Wrong nonce received in TCP fake pq-responce"));
|
||||
CONNECTION_LOG_ERROR(
|
||||
"Wrong nonce received in TCP fake pq-responce");
|
||||
error(kErrorCodeOther);
|
||||
}
|
||||
} else {
|
||||
DEBUG_LOG(("Connection Error: "
|
||||
"Could not parse TCP fake pq-responce"));
|
||||
CONNECTION_LOG_ERROR("Could not parse TCP fake pq-responce");
|
||||
error(kErrorCodeOther);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,4 +28,44 @@ std::unique_ptr<AbstractSocket> AbstractSocket::Create(
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractSocket::logError(int errorCode, const QString &errorText) {
|
||||
const auto log = [&](const QString &message) {
|
||||
DEBUG_LOG(("Socket %1 Error: ").arg(_debugId) + message);
|
||||
};
|
||||
switch (errorCode) {
|
||||
case QAbstractSocket::ConnectionRefusedError:
|
||||
log(u"Socket connection refused - %1."_q.arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::RemoteHostClosedError:
|
||||
log(u"Remote host closed socket connection - %1."_q.arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::HostNotFoundError:
|
||||
log(u"Host not found - %1."_q.arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::SocketTimeoutError:
|
||||
log(u"Socket timeout - %1."_q.arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::NetworkError: {
|
||||
log(u"Network - %1."_q.arg(errorText));
|
||||
} break;
|
||||
|
||||
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
||||
case QAbstractSocket::ProxyConnectionRefusedError:
|
||||
case QAbstractSocket::ProxyConnectionClosedError:
|
||||
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||
case QAbstractSocket::ProxyNotFoundError:
|
||||
case QAbstractSocket::ProxyProtocolError:
|
||||
log(u"Proxy (%1) - %2."_q.arg(errorCode).arg(errorText));
|
||||
break;
|
||||
|
||||
default:
|
||||
log(u"Other (%1) - %2."_q.arg(errorCode).arg(errorText));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace MTP::details
|
||||
|
||||
@@ -20,6 +20,10 @@ public:
|
||||
const QNetworkProxy &proxy,
|
||||
bool protocolForFiles);
|
||||
|
||||
void setDebugId(const QString &id) {
|
||||
_debugId = id;
|
||||
}
|
||||
|
||||
explicit AbstractSocket(not_null<QThread*> thread) {
|
||||
moveToThread(thread);
|
||||
}
|
||||
@@ -52,11 +56,15 @@ public:
|
||||
bytes::const_span buffer) = 0;
|
||||
|
||||
virtual int32 debugState() = 0;
|
||||
[[nodiscard]] virtual QString debugPostfix() const = 0;
|
||||
|
||||
protected:
|
||||
static const int kFilesSendBufferSize = 2 * 1024 * 1024;
|
||||
static const int kFilesReceiveBufferSize = 2 * 1024 * 1024;
|
||||
|
||||
void logError(int errorCode, const QString &errorText);
|
||||
|
||||
QString _debugId;
|
||||
rpl::event_stream<> _connected;
|
||||
rpl::event_stream<> _disconnected;
|
||||
rpl::event_stream<> _readyRead;
|
||||
|
||||
@@ -114,50 +114,12 @@ int32 TcpSocket::debugState() {
|
||||
return _socket.state();
|
||||
}
|
||||
|
||||
void TcpSocket::LogError(int errorCode, const QString &errorText) {
|
||||
switch (errorCode) {
|
||||
case QAbstractSocket::ConnectionRefusedError:
|
||||
LOG(("TCP Error: socket connection refused - %1").arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::RemoteHostClosedError:
|
||||
TCP_LOG(("TCP Info: remote host closed socket connection - %1"
|
||||
).arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::HostNotFoundError:
|
||||
LOG(("TCP Error: host not found - %1").arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::SocketTimeoutError:
|
||||
LOG(("TCP Error: socket timeout - %1").arg(errorText));
|
||||
break;
|
||||
|
||||
case QAbstractSocket::NetworkError: {
|
||||
DEBUG_LOG(("TCP Error: network - %1").arg(errorText));
|
||||
} break;
|
||||
|
||||
case QAbstractSocket::ProxyAuthenticationRequiredError:
|
||||
case QAbstractSocket::ProxyConnectionRefusedError:
|
||||
case QAbstractSocket::ProxyConnectionClosedError:
|
||||
case QAbstractSocket::ProxyConnectionTimeoutError:
|
||||
case QAbstractSocket::ProxyNotFoundError:
|
||||
case QAbstractSocket::ProxyProtocolError:
|
||||
LOG(("TCP Error: proxy (%1) - %2").arg(errorCode).arg(errorText));
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(("TCP Error: other (%1) - %2").arg(errorCode).arg(errorText));
|
||||
break;
|
||||
}
|
||||
|
||||
TCP_LOG(("TCP Error %1, restarting! - %2"
|
||||
).arg(errorCode
|
||||
).arg(errorText));
|
||||
QString TcpSocket::debugPostfix() const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
void TcpSocket::handleError(int errorCode) {
|
||||
LogError(errorCode, _socket.errorString());
|
||||
logError(errorCode, _socket.errorString());
|
||||
_error.fire({});
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,7 @@ public:
|
||||
void write(bytes::const_span prefix, bytes::const_span buffer) override;
|
||||
|
||||
int32 debugState() override;
|
||||
|
||||
static void LogError(int errorCode, const QString &errorText);
|
||||
QString debugPostfix() const override;
|
||||
|
||||
private:
|
||||
void handleError(int errorCode);
|
||||
|
||||
@@ -505,7 +505,7 @@ void TlsSocket::plainConnected() {
|
||||
domainFromSecret(),
|
||||
keyFromSecret());
|
||||
if (hello.data.isEmpty()) {
|
||||
LOG(("TLS Error: Could not generate Client Hello!"));
|
||||
logError(888, "Could not generate Client Hello.");
|
||||
_state = State::Error;
|
||||
_error.fire({});
|
||||
} else {
|
||||
@@ -563,7 +563,7 @@ void TlsSocket::checkHelloParts12(int parts1Size) {
|
||||
- kLengthSize
|
||||
- kServerHelloPart1.size();
|
||||
if (!CheckPart(data.subspan(part1Offset), kServerHelloPart1)) {
|
||||
LOG(("TLS Error: Bad Server Hello part1."));
|
||||
logError(888, "Bad Server Hello part1.");
|
||||
handleError();
|
||||
return;
|
||||
}
|
||||
@@ -587,7 +587,7 @@ void TlsSocket::checkHelloParts34(int parts123Size) {
|
||||
- kLengthSize
|
||||
- kServerHelloPart3.size();
|
||||
if (!CheckPart(data.subspan(part3Offset), kServerHelloPart3)) {
|
||||
LOG(("TLS Error: Bad Server Hello part."));
|
||||
logError(888, "Bad Server Hello part.");
|
||||
handleError();
|
||||
return;
|
||||
}
|
||||
@@ -611,7 +611,7 @@ void TlsSocket::checkHelloDigest() {
|
||||
bytes::set_with_const(digest, bytes::type(0));
|
||||
const auto check = openssl::HmacSha256(keyFromSecret(), fulldata);
|
||||
if (bytes::compare(digestCopy, check) != 0) {
|
||||
LOG(("TLS Error: Bad Server Hello digest."));
|
||||
logError(888, "Bad Server Hello digest.");
|
||||
handleError();
|
||||
return;
|
||||
}
|
||||
@@ -649,7 +649,7 @@ bool TlsSocket::checkNextPacket() {
|
||||
return true;
|
||||
}
|
||||
if (!CheckPart(incoming.subspan(offset), kServerHeader)) {
|
||||
LOG(("TLS Error: Bad packet header."));
|
||||
logError(888, "Bad packet header.");
|
||||
return false;
|
||||
}
|
||||
const auto length = ReadPartLength(
|
||||
@@ -773,12 +773,16 @@ int32 TlsSocket::debugState() {
|
||||
return _socket.state();
|
||||
}
|
||||
|
||||
QString TlsSocket::debugPostfix() const {
|
||||
return u"_ee"_q;
|
||||
}
|
||||
|
||||
void TlsSocket::handleError(int errorCode) {
|
||||
if (_state != State::Connected) {
|
||||
_syncTimeRequests.fire({});
|
||||
}
|
||||
if (errorCode) {
|
||||
TcpSocket::LogError(errorCode, _socket.errorString());
|
||||
logError(errorCode, _socket.errorString());
|
||||
}
|
||||
_state = State::Error;
|
||||
_error.fire({});
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
void write(bytes::const_span prefix, bytes::const_span buffer) override;
|
||||
|
||||
int32 debugState() override;
|
||||
QString debugPostfix() const override;
|
||||
|
||||
private:
|
||||
enum class State {
|
||||
|
||||
@@ -39,7 +39,6 @@ constexpr auto kPingSendAfter = 30 * crl::time(1000);
|
||||
constexpr auto kPingSendAfterForce = 45 * crl::time(1000);
|
||||
constexpr auto kTemporaryExpiresIn = TimeId(86400);
|
||||
constexpr auto kBindKeyAdditionalExpiresTimeout = TimeId(30);
|
||||
constexpr auto kTestModeDcIdShift = 10000;
|
||||
constexpr auto kKeyOldEnoughForDestroy = 60 * crl::time(1000);
|
||||
constexpr auto kSentContainerLives = 600 * crl::time(1000);
|
||||
constexpr auto kFastRequestDuration = crl::time(500);
|
||||
@@ -1252,14 +1251,10 @@ void SessionPrivate::handleReceived() {
|
||||
auto ints = intsBuffer.constData();
|
||||
if ((intsCount < kMinimalIntsCount) || (intsCount > kMaxMessageLength / kIntSize)) {
|
||||
LOG(("TCP Error: bad message received, len %1").arg(intsCount * kIntSize));
|
||||
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(ints, intsCount * kIntSize).str()));
|
||||
|
||||
return restart();
|
||||
}
|
||||
if (_keyId != *(uint64*)ints) {
|
||||
LOG(("TCP Error: bad auth_key_id %1 instead of %2 received").arg(_keyId).arg(*(uint64*)ints));
|
||||
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(ints, intsCount * kIntSize).str()));
|
||||
|
||||
return restart();
|
||||
}
|
||||
|
||||
@@ -1297,8 +1292,6 @@ void SessionPrivate::handleReceived() {
|
||||
constexpr auto kMsgKeyShift = 8U;
|
||||
if (ConstTimeIsDifferent(&msgKey, sha256Buffer.data() + kMsgKeyShift, sizeof(msgKey))) {
|
||||
LOG(("TCP Error: bad SHA256 hash after aesDecrypt in message"));
|
||||
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(encryptedInts, encryptedBytesCount).str()));
|
||||
|
||||
return restart();
|
||||
}
|
||||
|
||||
@@ -1307,17 +1300,19 @@ void SessionPrivate::handleReceived() {
|
||||
|| (paddingSize < kMinPaddingSize)
|
||||
|| (paddingSize > kMaxPaddingSize)) {
|
||||
LOG(("TCP Error: bad msg_len received %1, data size: %2").arg(messageLength).arg(encryptedBytesCount));
|
||||
TCP_LOG(("TCP Error: bad message %1").arg(Logs::mb(encryptedInts, encryptedBytesCount).str()));
|
||||
|
||||
return restart();
|
||||
}
|
||||
|
||||
TCP_LOG(("TCP Info: decrypted message %1,%2,%3 is %4 len").arg(msgId).arg(seqNo).arg(Logs::b(needAck)).arg(fullDataLength));
|
||||
if (Logs::DebugEnabled()) {
|
||||
_connection->logInfo(u"Decrypted message %1,%2,%3 is %4 len"_q
|
||||
.arg(msgId)
|
||||
.arg(seqNo)
|
||||
.arg(Logs::b(needAck))
|
||||
.arg(fullDataLength));
|
||||
}
|
||||
|
||||
if (session != _sessionId) {
|
||||
LOG(("MTP Error: bad server session received"));
|
||||
TCP_LOG(("MTP Error: bad server session %1 instead of %2 in message received").arg(session).arg(_sessionId));
|
||||
|
||||
return restart();
|
||||
}
|
||||
|
||||
@@ -1360,8 +1355,8 @@ void SessionPrivate::handleReceived() {
|
||||
auto sfrom = decryptedInts + 4U; // msg_id + seq_no + length + message
|
||||
MTP_LOG(_shiftedDcId, ("Recv: ")
|
||||
+ DumpToText(sfrom, end)
|
||||
+ QString(" (protocolDcId:%1,key:%2)"
|
||||
).arg(getProtocolDcId()
|
||||
+ QString(" (dc:%1,key:%2)"
|
||||
).arg(AbstractConnection::ProtocolDcDebugId(getProtocolDcId())
|
||||
).arg(_encryptionKey->keyId()));
|
||||
|
||||
const auto registered = _receivedMessageIds.registerMsgId(
|
||||
@@ -2619,8 +2614,8 @@ bool SessionPrivate::sendSecureRequest(
|
||||
auto from = request->constData() + 4;
|
||||
MTP_LOG(_shiftedDcId, ("Send: ")
|
||||
+ DumpToText(from, from + messageSize)
|
||||
+ QString(" (protocolDcId:%1,key:%2)"
|
||||
).arg(getProtocolDcId()
|
||||
+ QString(" (dc:%1,key:%2)"
|
||||
).arg(AbstractConnection::ProtocolDcDebugId(getProtocolDcId())
|
||||
).arg(_encryptionKey->keyId()));
|
||||
|
||||
uchar encryptedSHA256[32];
|
||||
|
||||
@@ -31,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "settings/settings_common.h"
|
||||
#include "api/api_updates.h"
|
||||
#include "base/qt/qt_common_adapters.h"
|
||||
#include "base/custom_app_icon.h"
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
@@ -283,6 +284,29 @@ auto GenerateCodes() {
|
||||
Ui::Toast::Show(now ? "Testing chat theme colors!" : "Not testing..");
|
||||
});
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
codes.emplace(qsl("customicon"), [](SessionController *window) {
|
||||
const auto iconFilters = qsl("Icon files (*.icns *.png);;") + FileDialog::AllFilesFilter();
|
||||
const auto change = [](const QString &path) {
|
||||
const auto success = path.isEmpty()
|
||||
? base::ClearCustomAppIcon()
|
||||
: base::SetCustomAppIcon(path);
|
||||
Ui::Toast::Show(success
|
||||
? (path.isEmpty()
|
||||
? "Icon cleared. Restarting the Dock."
|
||||
: "Icon updated. Restarting the Dock.")
|
||||
: (path.isEmpty()
|
||||
? "Icon clear failed. See log.txt for details."
|
||||
: "Icon update failed. See log.txt for details."));
|
||||
};
|
||||
FileDialog::GetOpenPath(Core::App().getFileDialogParent(), "Choose custom icon", iconFilters, [=](const FileDialog::OpenResult &result) {
|
||||
change(result.paths.isEmpty() ? QString() : result.paths.front());
|
||||
}, [=] {
|
||||
change(QString());
|
||||
});
|
||||
});
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,14 +21,19 @@ Qt::KeyboardModifiers SkipSwitchModifiers() {
|
||||
return Qt::ControlModifier | Qt::ShiftModifier;
|
||||
}
|
||||
|
||||
FnMut<bool()> GetSwitchMethod(SwitchSettings value) {
|
||||
std::optional<Shortcuts::Command> GetSwitchCommand(SwitchSettings value) {
|
||||
switch (value) {
|
||||
case SwitchSettings::Next:
|
||||
return Shortcuts::RequestHandler(Shortcuts::Command::ChatNext);
|
||||
return Shortcuts::Command::ChatNext;
|
||||
case SwitchSettings::Previous:
|
||||
return Shortcuts::RequestHandler(Shortcuts::Command::ChatPrevious);
|
||||
return Shortcuts::Command::ChatPrevious;
|
||||
}
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
FnMut<bool()> GetSwitchMethod(SwitchSettings value) {
|
||||
const auto command = GetSwitchCommand(value);
|
||||
return command ? Shortcuts::RequestHandler(*command) : nullptr;
|
||||
}
|
||||
|
||||
} // namespace Support
|
||||
|
||||
@@ -7,6 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Shortcuts {
|
||||
enum class Command;
|
||||
} // namespace Shortcuts
|
||||
|
||||
namespace Support {
|
||||
|
||||
enum class SwitchSettings {
|
||||
@@ -15,8 +19,10 @@ enum class SwitchSettings {
|
||||
Previous,
|
||||
};
|
||||
|
||||
Qt::KeyboardModifiers SkipSwitchModifiers();
|
||||
bool HandleSwitch(Qt::KeyboardModifiers modifiers);
|
||||
FnMut<bool()> GetSwitchMethod(SwitchSettings value);
|
||||
[[nodiscard]] Qt::KeyboardModifiers SkipSwitchModifiers();
|
||||
[[nodiscard]] bool HandleSwitch(Qt::KeyboardModifiers modifiers);
|
||||
[[nodiscard]] std::optional<Shortcuts::Command> GetSwitchCommand(
|
||||
SwitchSettings value);
|
||||
[[nodiscard]] FnMut<bool()> GetSwitchMethod(SwitchSettings value);
|
||||
|
||||
} // namespace Support
|
||||
|
||||
@@ -652,11 +652,11 @@ MainMenu::MainMenu(
|
||||
tr::now,
|
||||
lt_version,
|
||||
currentVersionText()),
|
||||
{}) // Link 1.
|
||||
1) // Link 1.
|
||||
.append(QChar(' '))
|
||||
.append(QChar(8211))
|
||||
.append(QChar(' '))
|
||||
.append(Ui::Text::Link(tr::lng_menu_about(tr::now), {}))); // Link 2.
|
||||
.append(Ui::Text::Link(tr::lng_menu_about(tr::now), 2))); // Link 2.
|
||||
_version->setLink(
|
||||
1,
|
||||
std::make_shared<UrlClickHandler>(Core::App().changelogLink()));
|
||||
@@ -1005,12 +1005,20 @@ void MainMenu::refreshMenu() {
|
||||
}, &st::mainMenuContacts, &st::mainMenuContactsOver);
|
||||
|
||||
const auto fix = std::make_shared<QPointer<QAction>>();
|
||||
*fix = _menu->addAction(qsl("Fix chats order"), [=] {
|
||||
auto fixCallback = [=] {
|
||||
(*fix)->setChecked(!(*fix)->isChecked());
|
||||
_controller->session().settings().setSupportFixChatsOrder(
|
||||
(*fix)->isChecked());
|
||||
_controller->session().saveSettings();
|
||||
}, &st::mainMenuFixOrder, &st::mainMenuFixOrderOver);
|
||||
};
|
||||
auto item = base::make_unique_q<Ui::Menu::Toggle>(
|
||||
_menu,
|
||||
st::mainMenu,
|
||||
u"Fix chats order"_q,
|
||||
std::move(fixCallback),
|
||||
&st::mainMenuFixOrder,
|
||||
&st::mainMenuFixOrderOver);
|
||||
*fix = _menu->addAction(std::move(item));
|
||||
(*fix)->setCheckable(true);
|
||||
(*fix)->setChecked(
|
||||
_controller->session().settings().supportFixChatsOrder());
|
||||
|
||||
@@ -795,6 +795,16 @@ bool SessionController::jumpToChatListEntry(Dialogs::RowDescriptor row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Dialogs::RowDescriptor SessionController::resolveChatNext(
|
||||
Dialogs::RowDescriptor from) const {
|
||||
return content()->resolveChatNext(from);
|
||||
}
|
||||
|
||||
Dialogs::RowDescriptor SessionController::resolveChatPrevious(
|
||||
Dialogs::RowDescriptor from) const {
|
||||
return content()->resolveChatPrevious(from);
|
||||
}
|
||||
|
||||
void SessionController::pushToChatEntryHistory(Dialogs::RowDescriptor row) {
|
||||
if (!_chatEntryHistory.empty()
|
||||
&& _chatEntryHistory[_chatEntryHistoryPosition] == row) {
|
||||
|
||||
@@ -301,6 +301,12 @@ public:
|
||||
rpl::producer<Dialogs::RowDescriptor> activeChatEntryValue() const;
|
||||
rpl::producer<Dialogs::Key> activeChatValue() const;
|
||||
bool jumpToChatListEntry(Dialogs::RowDescriptor row);
|
||||
|
||||
[[nodiscard]] Dialogs::RowDescriptor resolveChatNext(
|
||||
Dialogs::RowDescriptor from = {}) const;
|
||||
[[nodiscard]] Dialogs::RowDescriptor resolveChatPrevious(
|
||||
Dialogs::RowDescriptor from = {}) const;
|
||||
|
||||
void showEditPeerBox(PeerData *peer);
|
||||
|
||||
void enableGifPauseReason(GifPauseReason reason);
|
||||
|
||||
@@ -700,7 +700,7 @@ RUN mkdir tg_owt
|
||||
WORKDIR tg_owt
|
||||
RUN git init
|
||||
RUN git remote add origin $GIT/desktop-app/tg_owt.git
|
||||
RUN git fetch --depth=1 origin 25c8637f5975db830cc5d74477641a8b609e248d
|
||||
RUN git fetch --depth=1 origin 347400dc2377b16be702397ff8db44d5739d2650
|
||||
RUN git reset --hard FETCH_HEAD
|
||||
RUN git submodule init
|
||||
RUN git submodule update
|
||||
|
||||
@@ -4,6 +4,6 @@ pushd `dirname $0` > /dev/null
|
||||
FullScriptPath=`pwd`
|
||||
popd > /dev/null
|
||||
|
||||
python $FullScriptPath/set_version.py $1
|
||||
python3 $FullScriptPath/set_version.py $1
|
||||
|
||||
exit
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
AppVersion 3005001
|
||||
AppVersion 3005002
|
||||
AppVersionStrMajor 3.5
|
||||
AppVersionStrSmall 3.5.1
|
||||
AppVersionStr 3.5.1
|
||||
AppVersionStrSmall 3.5.2
|
||||
AppVersionStr 3.5.2
|
||||
BetaChannel 0
|
||||
AlphaVersion 0
|
||||
AppVersionOriginal 3.5.1
|
||||
AppVersionOriginal 3.5.2
|
||||
|
||||
Submodule Telegram/lib_base updated: 3d5d650991...1ec9a06352
Submodule Telegram/lib_ui updated: 8618812fd6...7e1effeeeb
@@ -1,4 +1,9 @@
|
||||
3.5.1 (03.02.22)
|
||||
3.5.2 (06.02.22)
|
||||
|
||||
- Fix a freeze in audio playback on Linux.
|
||||
- Fix a crash in screen sharing initialization on Linux.
|
||||
|
||||
3.5.1 (04.02.22)
|
||||
|
||||
- Keep the screen on while watching a video or participating in a video chat.
|
||||
- Save experimental settings between relaunches.
|
||||
|
||||
2
cmake
2
cmake
Submodule cmake updated: 6d81711cf8...3604a7f023
Reference in New Issue
Block a user