From 80b0667ff95b83f48bcae8dca56efc83948a3678 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Wed, 6 Apr 2016 15:07:05 +0400
Subject: [PATCH 1/2] Requesting getDifference if some users or channels are
 not loaded while processing updateNewChannelMessage update.

---
 Telegram/SourceFiles/apiwrap.cpp              |  2 +-
 Telegram/SourceFiles/history.h                |  3 +-
 Telegram/SourceFiles/mainwidget.cpp           | 84 ++++++++++++++++++-
 Telegram/SourceFiles/mtproto/file_download.h  |  1 +
 Telegram/SourceFiles/structs.h                |  4 +-
 Telegram/Telegram.vcxproj                     |  5 ++
 .../vc/codegen_style/codegen_style.vcxproj    |  2 +
 7 files changed, 94 insertions(+), 7 deletions(-)

diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index 720e37ccc..643a784e9 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -399,7 +399,7 @@ void ApiWrap::requestLastParticipants(ChannelData *peer, bool fromStart) {
 	if ((needAdmins && adminsOutdated) || peer->lastParticipantsCountOutdated()) {
 		fromStart = true;
 	}
-	QMap<PeerData*, mtpRequestId>::iterator i = _participantsRequests.find(peer);
+	auto i = _participantsRequests.find(peer);
 	if (i != _participantsRequests.cend()) {
 		if (fromStart && i.value() < 0) { // was not loading from start
 			_participantsRequests.erase(i);
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index 4d8350488..b394b1ea9 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -145,6 +145,7 @@ inline MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
 	case OverviewFiles: return MTP_inputMessagesFilterDocument();
 	case OverviewVoiceFiles: return MTP_inputMessagesFilterVoice();
 	case OverviewLinks: return MTP_inputMessagesFilterUrl();
+	case OverviewCount: break;
 	default: type = OverviewCount; break;
 	}
 	return MTPMessagesFilter();
@@ -1756,7 +1757,7 @@ inline MediaOverviewType mediaToOverviewType(HistoryMedia *media) {
 	case MediaTypeMusicFile: return media->getDocument()->isMusic() ? OverviewMusicFiles : OverviewFiles;
 	case MediaTypeVoiceFile: return OverviewVoiceFiles;
 	case MediaTypeGif: return media->getDocument()->isGifv() ? OverviewCount : OverviewFiles;
-//	case MediaTypeSticker: return OverviewFiles;
+	default: break;
 	}
 	return OverviewCount;
 }
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index f5eb63542..46b89bfc1 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -3579,6 +3579,9 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr
 			if (peer->isUser() && peer->asUser()->botInfo && !peer->asUser()->botInfo->cantJoinGroups && !startToken.isEmpty()) {
 				peer->asUser()->botInfo->startGroupToken = startToken;
 				Ui::showLayer(new ContactsBox(peer->asUser()));
+			} else if (peer->isUser() && peer->asUser()->botInfo) {
+				// Always open bot chats, even from mention links.
+				Ui::showPeerHistoryAsync(peer->id, ShowAtUnreadMsgId);
 			} else {
 				showPeerProfile(peer);
 			}
@@ -4242,6 +4245,73 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
 	}
 }
 
+namespace {
+
+enum class DataIsLoadedResult {
+	NotLoaded = 0,
+	FromNotLoaded = 1,
+	Ok = 2,
+};
+DataIsLoadedResult allDataLoadedForMessage(const MTPMessage &msg) {
+	switch (msg.type()) {
+	case mtpc_message: {
+		const MTPDmessage &d(msg.c_message());
+		if (!d.is_post() && d.has_from_id()) {
+			if (!App::userLoaded(peerFromUser(d.vfrom_id))) {
+				return DataIsLoadedResult::FromNotLoaded;
+			}
+		}
+		if (d.has_via_bot_id()) {
+			if (!App::userLoaded(peerFromUser(d.vvia_bot_id))) {
+				return DataIsLoadedResult::NotLoaded;
+			}
+		}
+		if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) {
+			ChannelId fromChannelId = d.vfwd_from.c_messageFwdHeader().vchannel_id.v;
+			if (fromChannelId) {
+				if (!App::channelLoaded(peerFromChannel(fromChannelId))) {
+					return DataIsLoadedResult::NotLoaded;
+				}
+			} else {
+				if (!App::userLoaded(peerFromUser(d.vfwd_from.c_messageFwdHeader().vfrom_id))) {
+					return DataIsLoadedResult::NotLoaded;
+				}
+			}
+		}
+	} break;
+	case mtpc_messageService: {
+		const MTPDmessageService &d(msg.c_messageService());
+		if (!d.is_post() && d.has_from_id()) {
+			if (!App::userLoaded(peerFromUser(d.vfrom_id))) {
+				return DataIsLoadedResult::FromNotLoaded;
+			}
+		}
+		switch (d.vaction.type()) {
+		case mtpc_messageActionChatAddUser: {
+			for_const(const MTPint &userId, d.vaction.c_messageActionChatAddUser().vusers.c_vector().v) {
+				if (!App::userLoaded(peerFromUser(userId))) {
+					return DataIsLoadedResult::NotLoaded;
+				}
+			}
+		} break;
+		case mtpc_messageActionChatJoinedByLink: {
+			if (!App::userLoaded(peerFromUser(d.vaction.c_messageActionChatJoinedByLink().vinviter_id))) {
+				return DataIsLoadedResult::NotLoaded;
+			}
+		} break;
+		case mtpc_messageActionChatDeleteUser: {
+			if (!App::userLoaded(peerFromUser(d.vaction.c_messageActionChatDeleteUser().vuser_id))) {
+				return DataIsLoadedResult::NotLoaded;
+			}
+		} break;
+		}
+	} break;
+	}
+	return DataIsLoadedResult::Ok;
+}
+
+} // namespace
+
 void MainWidget::feedUpdate(const MTPUpdate &update) {
 	if (!MTP::authedId()) return;
 
@@ -4601,8 +4671,18 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	case mtpc_updateNewChannelMessage: {
 		const MTPDupdateNewChannelMessage &d(update.c_updateNewChannelMessage());
 		ChannelData *channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage)));
-		if (!channel && !_ptsWaiter.requesting()) {
-			MTP_LOG(0, ("getDifference { good - after no channel in updateNewChannelMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
+		DataIsLoadedResult isDataLoaded = allDataLoadedForMessage(d.vmessage);
+		if (!_ptsWaiter.requesting() && (!channel || isDataLoaded != DataIsLoadedResult::Ok)) {
+			MTP_LOG(0, ("getDifference { good - after not all data loaded in updateNewChannelMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
+
+			// Request last active supergroup participants if the 'from' user was not loaded yet.
+			// This will optimize similar getDifference() calls for almost all next messages.
+			if (isDataLoaded == DataIsLoadedResult::FromNotLoaded && channel && channel->isMegagroup() && App::api()) {
+				if (channel->mgInfo->lastParticipants.size() < Global::ChatSizeMax() && (channel->mgInfo->lastParticipants.isEmpty() || channel->mgInfo->lastParticipants.size() < channel->count)) {
+					App::api()->requestLastParticipants(channel);
+				}
+			}
+
 			if (!_byMinChannelTimer.isActive()) { // getDifference after timeout
 				_byMinChannelTimer.start(WaitForSkippedTimeout);
 			}
diff --git a/Telegram/SourceFiles/mtproto/file_download.h b/Telegram/SourceFiles/mtproto/file_download.h
index c3097b57c..c07f25ec7 100644
--- a/Telegram/SourceFiles/mtproto/file_download.h
+++ b/Telegram/SourceFiles/mtproto/file_download.h
@@ -60,6 +60,7 @@ inline StorageFileType mtpToStorageType(mtpTypeId type) {
 }
 inline mtpTypeId mtpFromStorageType(StorageFileType type) {
 	switch (type) {
+	case StorageFileJpeg: return mtpc_storage_fileJpeg;
 	case StorageFileGif: return mtpc_storage_fileGif;
 	case StorageFilePng: return mtpc_storage_filePng;
 	case StorageFilePdf: return mtpc_storage_filePdf;
diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h
index 6546a8c03..cd69c15d0 100644
--- a/Telegram/SourceFiles/structs.h
+++ b/Telegram/SourceFiles/structs.h
@@ -118,9 +118,7 @@ inline PeerId peerFromMessage(const MTPmessage &msg) {
 inline MTPDmessage::Flags flagsFromMessage(const MTPmessage &msg) {
 	switch (msg.type()) {
 	case mtpc_message: return msg.c_message().vflags.v;
-
-	// dirty type hack :( we assume that MTPDmessage::Flags has the same flags and perhaps more
-	case mtpc_messageService: return MTPDmessage::Flags(QFlag(msg.c_messageService().vflags.v));
+	case mtpc_messageService: return mtpCastFlags(msg.c_messageService().vflags.v);
 	}
 	return 0;
 }
diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj
index cdde8b981..bce9092bd 100644
--- a/Telegram/Telegram.vcxproj
+++ b/Telegram/Telegram.vcxproj
@@ -79,6 +79,7 @@
       <Optimization>Disabled</Optimization>
       <AdditionalOptions>/Zm152 %(AdditionalOptions)</AdditionalOptions>
       <WarningLevel>Level3</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -109,6 +110,8 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
       <AdditionalOptions>/Zm110 %(AdditionalOptions)</AdditionalOptions>
+      <WarningLevel>Level3</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -140,6 +143,8 @@
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
       <AdditionalOptions>/Zm110 %(AdditionalOptions)</AdditionalOptions>
+      <WarningLevel>Level3</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
diff --git a/Telegram/build/vc/codegen_style/codegen_style.vcxproj b/Telegram/build/vc/codegen_style/codegen_style.vcxproj
index cfff29554..b1f24fc30 100644
--- a/Telegram/build/vc/codegen_style/codegen_style.vcxproj
+++ b/Telegram/build/vc/codegen_style/codegen_style.vcxproj
@@ -71,6 +71,8 @@
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <AdditionalIncludeDirectories>.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+      <TreatWarningAsError>true</TreatWarningAsError>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>

From efbf95ae80668a6d1cf8889fbd2f260bec6a8ed1 Mon Sep 17 00:00:00 2001
From: Christoph <auer.chrisi@gmx.net>
Date: Thu, 7 Apr 2016 01:55:14 +0200
Subject: [PATCH 2/2] Remove unnecessary assignments

Signed-off-by: Christoph <auer.chrisi@gmx.net>
---
 Telegram/SourceFiles/gui/text.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/Telegram/SourceFiles/gui/text.cpp b/Telegram/SourceFiles/gui/text.cpp
index b12fdfe3f..aff4bba1f 100644
--- a/Telegram/SourceFiles/gui/text.cpp
+++ b/Telegram/SourceFiles/gui/text.cpp
@@ -690,7 +690,7 @@ public:
 			} else {
 				int32 i = 0, l = preparsed.size();
 				entities.reserve(l);
-				const QChar *p = text.constData(), s = text.size();
+				const QChar s = text.size();
 				for (; i < l; ++i) {
 					EntityInTextType t = preparsed.at(i).type;
 					if ((t == EntityInTextMention && !parseMentions) ||
@@ -2301,7 +2301,7 @@ public:
 								// neutrals go to R
 								eor = current - 1;
 								eAppendItems(analysis, sor, eor, control, dir);
-								dir = QChar::DirON; status.eor = QChar::DirEN;
+								status.eor = QChar::DirEN;
 								dir = QChar::DirAN;
 							}
 							else if(status.eor == QChar::DirL ||
@@ -2311,11 +2311,11 @@ public:
 								// numbers on both sides, neutrals get right to left direction
 								if(dir != QChar::DirL) {
 									eAppendItems(analysis, sor, eor, control, dir);
-									dir = QChar::DirON; status.eor = QChar::DirON;
+									status.eor = QChar::DirON;
 									eor = current - 1;
 									dir = QChar::DirR;
 									eAppendItems(analysis, sor, eor, control, dir);
-									dir = QChar::DirON; status.eor = QChar::DirON;
+									status.eor = QChar::DirON;
 									dir = QChar::DirAN;
 								} else {
 									eor = current; status.eor = dirCurrent;