Compare commits

..

15 Commits

Author SHA1 Message Date
John Preston
6ce3f9bb71 Version 3.5.2.
- Fix a freeze in audio playback on Linux.
- Fix a crash in screen sharing initialization on Linux.
2022-02-08 19:18:14 +03:00
John Preston
a5483a5113 Fix build on Linux. 2022-02-08 19:17:44 +03:00
John Preston
7f5e646db5 Disable PortalPreventAppSuspention for now.
A lot of freezing reports:
- https://bugs.telegram.org/c/14426
- XFCE X11, Ubuntu X11, XCinnamon X11 reports to support
- tdesktop/issues/24032
- tdesktop/issues/24043
2022-02-08 16:47:37 +03:00
John Preston
666251f23e Allow to set custom app icon on macOS. 2022-02-08 00:24:11 +03:00
John Preston
d89d8b09da Preload chats in support switch. 2022-02-08 00:24:11 +03:00
John Preston
0aa20b4479 Decrypt shiftedDcId / protocolDcId in mtp_ logs. 2022-02-07 15:26:26 +03:00
John Preston
8658dba97a Improve mtproto connections logging. 2022-02-07 14:44:00 +03:00
23rd
20c911651f Replaced universal initializers with constructors in Ui::Text::Link. 2022-02-06 18:29:38 +03:00
John Preston
bef20ba4a2 Fix loading libdrm before first use.
Fixes #24022.
2022-02-06 13:50:23 +03:00
John Preston
ee325031a0 Fix build without wayland integration. 2022-02-05 19:20:40 +03:00
John Preston
b57549546d Update lib_ui for the indexed links fixes. 2022-02-05 19:19:54 +03:00
23rd
1e4d278604 Fixed formatting text of pinned messages in service messages. 2022-02-05 18:39:43 +03:00
23rd
80aa596310 Fixed possible incorrect order of links in Ui. 2022-02-05 18:39:43 +03:00
John Preston
4913288061 Fix "Fix chats order" toggle in support mode. 2022-02-05 15:09:18 +03:00
John Preston
1a43cd8a67 Fix the date in the latest changelog entry. 2022-02-05 01:41:41 +03:00
43 changed files with 563 additions and 227 deletions

View File

@@ -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>

View File

@@ -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"

View File

@@ -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"

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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());

View File

@@ -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 {

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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({});
}

View File

@@ -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);

View File

@@ -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({});

View File

@@ -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 {

View File

@@ -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];

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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());

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

Submodule cmake updated: 6d81711cf8...3604a7f023