From 803d1a429d938ac5a5ee6fb71a60d0d3cb235dbd Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 18 Feb 2016 19:36:33 +0300
Subject: [PATCH] scheme updated, config vars moved to Global namespace

---
 Telegram/SourceFiles/apiwrap.cpp              |   4 +-
 Telegram/SourceFiles/app.cpp                  |  81 +--
 Telegram/SourceFiles/app.h                    |   1 +
 Telegram/SourceFiles/application.cpp          |   8 +-
 Telegram/SourceFiles/boxes/addcontactbox.cpp  |   2 +-
 Telegram/SourceFiles/boxes/confirmbox.cpp     |   2 +-
 Telegram/SourceFiles/boxes/contactsbox.cpp    |  18 +-
 Telegram/SourceFiles/facades.cpp              |  36 +-
 Telegram/SourceFiles/facades.h                |  17 +
 Telegram/SourceFiles/history.cpp              |  59 +--
 Telegram/SourceFiles/history.h                |  48 +-
 Telegram/SourceFiles/historywidget.cpp        |  18 +-
 Telegram/SourceFiles/layout.cpp               |   6 +-
 Telegram/SourceFiles/localstorage.cpp         |  16 +-
 Telegram/SourceFiles/mainwidget.cpp           |  89 +++-
 Telegram/SourceFiles/mediaview.cpp            |  12 +-
 Telegram/SourceFiles/mtproto/mtp.cpp          |  12 +-
 Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp |   4 +
 Telegram/SourceFiles/mtproto/mtpCoreTypes.h   |   7 +-
 Telegram/SourceFiles/mtproto/mtpDC.cpp        |  20 +-
 Telegram/SourceFiles/mtproto/mtpScheme.cpp    | 166 +++++--
 Telegram/SourceFiles/mtproto/mtpScheme.h      | 468 +++++++++++++++---
 Telegram/SourceFiles/mtproto/scheme.tl        |  19 +-
 Telegram/SourceFiles/profilewidget.cpp        |  16 +-
 Telegram/SourceFiles/settings.cpp             |  13 +-
 Telegram/SourceFiles/settings.h               |  11 -
 Telegram/SourceFiles/structs.cpp              |   6 +-
 Telegram/SourceFiles/types.h                  |   4 +-
 Telegram/SourceFiles/window.cpp               |  12 +-
 29 files changed, 848 insertions(+), 327 deletions(-)

diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp
index e529b1f74..295500225 100644
--- a/Telegram/SourceFiles/apiwrap.cpp
+++ b/Telegram/SourceFiles/apiwrap.cpp
@@ -421,13 +421,13 @@ void ApiWrap::requestLastParticipants(ChannelData *peer, bool fromStart) {
 			return;
 		}
 	}
-	mtpRequestId req = MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : peer->mgInfo->lastParticipants.size()), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
+	mtpRequestId req = MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : peer->mgInfo->lastParticipants.size()), MTP_int(Global::ChatSizeMax())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer));
 	_participantsRequests.insert(peer, fromStart ? req : -req);
 }
 
 void ApiWrap::requestBots(ChannelData *peer) {
 	if (!peer || !peer->isMegagroup() || _botsRequests.contains(peer)) return;
-	_botsRequests.insert(peer, MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer)));
+	_botsRequests.insert(peer, MTP::send(MTPchannels_GetParticipants(peer->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(Global::ChatSizeMax())), rpcDone(&ApiWrap::lastParticipantsDone, peer), rpcFail(&ApiWrap::lastParticipantsFail, peer)));
 }
 
 void ApiWrap::gotChat(PeerData *peer, const MTPmessages_Chats &result) {
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 22cad42f6..367f4f90b 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -350,7 +350,7 @@ namespace App {
 		for (QVector<MTPUser>::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) {
 			const MTPuser &user(*i);
             data = 0;
-			bool wasContact = false;
+			bool wasContact = false, minimal = false;
 			const MTPUserStatus *status = 0, emptyStatus = MTP_userStatusEmpty();
 
 			switch (user.type()) {
@@ -372,19 +372,22 @@ namespace App {
 			} break;
 			case mtpc_user: {
 				const MTPDuser &d(user.c_user());
+				minimal = d.is_min();
 
 				PeerId peer(peerFromUser(d.vid.v));
 				data = App::user(peer);
-				data->flags = d.vflags.v;
-				if (d.is_self()) {
-					data->input = MTP_inputPeerSelf();
-					data->inputUser = MTP_inputUserSelf();
-				} else if (!d.has_access_hash()) {
-					data->input = MTP_inputPeerUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
-					data->inputUser = MTP_inputUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
-				} else {
-					data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash);
-					data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash);
+				if (!minimal) {
+					data->flags = d.vflags.v;
+					if (d.is_self()) {
+						data->input = MTP_inputPeerSelf();
+						data->inputUser = MTP_inputUserSelf();
+					} else if (!d.has_access_hash()) {
+						data->input = MTP_inputPeerUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
+						data->inputUser = MTP_inputUser(d.vid, MTP_long((data->access == UserNoAccess) ? 0 : data->access));
+					} else {
+						data->input = MTP_inputPeerUser(d.vid, d.vaccess_hash);
+						data->inputUser = MTP_inputUser(d.vid, d.vaccess_hash);
+					}
 				}
 				if (d.is_deleted()) {
 					data->setPhone(QString());
@@ -393,10 +396,10 @@ namespace App {
 					data->access = UserNoAccess;
 					status = &emptyStatus;
 				} else {
-					QString phone = d.has_phone() ? qs(d.vphone) : QString();
+					QString phone = minimal ? data->phone : (d.has_phone() ? qs(d.vphone) : QString());
 					QString fname = d.has_first_name() ? textOneLine(qs(d.vfirst_name)) : QString();
 					QString lname = d.has_last_name() ? textOneLine(qs(d.vlast_name)) : QString();
-					QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString();
+					QString uname = minimal ? data->username : (d.has_username() ? textOneLine(qs(d.vusername)) : QString());
 
 					bool phoneChanged = (data->phone != phone);
 					if (phoneChanged) data->setPhone(phone);
@@ -420,22 +423,24 @@ namespace App {
 					status = d.has_status() ? &d.vstatus : &emptyStatus;
 				}
 				wasContact = (data->contact > 0);
-				if (d.has_bot_info_version()) {
-					data->setBotInfoVersion(d.vbot_info_version.v);
-					data->botInfo->readsAllHistory = d.is_bot_chat_history();
-					data->botInfo->cantJoinGroups = d.is_bot_nochats();
-					data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString();
-				} else {
-					data->setBotInfoVersion(-1);
-				}
-				data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone.isEmpty() ? -1 : 0);
-				if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsNoButton) != dbiprsNoButton) {
-					cRefReportSpamStatuses().insert(data->id, dbiprsNoButton);
-					Local::writeReportSpamStatuses();
-				}
-				if (d.is_self() && ::self != data) {
-					::self = data;
-					if (App::wnd()) App::wnd()->updateGlobalMenu();
+				if (!minimal) {
+					if (d.has_bot_info_version()) {
+						data->setBotInfoVersion(d.vbot_info_version.v);
+						data->botInfo->readsAllHistory = d.is_bot_chat_history();
+						data->botInfo->cantJoinGroups = d.is_bot_nochats();
+						data->botInfo->inlinePlaceholder = d.has_bot_inline_placeholder() ? '_' + qs(d.vbot_inline_placeholder) : QString();
+					} else {
+						data->setBotInfoVersion(-1);
+					}
+					data->contact = (d.is_contact() || d.is_mutual_contact()) ? 1 : (data->phone.isEmpty() ? -1 : 0);
+					if (data->contact == 1 && cReportSpamStatuses().value(data->id, dbiprsNoButton) != dbiprsNoButton) {
+						cRefReportSpamStatuses().insert(data->id, dbiprsNoButton);
+						Local::writeReportSpamStatuses();
+					}
+					if (d.is_self() && ::self != data) {
+						::self = data;
+						if (App::wnd()) App::wnd()->updateGlobalMenu();
+					}
 				}
 			} break;
 			}
@@ -443,7 +448,7 @@ namespace App {
             if (!data) continue;
 
 			data->loaded = true;
-			if (status) switch (status->type()) {
+			if (status && !minimal) switch (status->type()) {
 			case mtpc_userStatusEmpty: data->onlineTill = 0; break;
 			case mtpc_userStatusRecently:
 				if (data->onlineTill > -10) { // don't modify pseudo-online
@@ -916,13 +921,27 @@ namespace App {
 		return false;
 	}
 
+	void updateEditedMessage(const MTPDmessage &m) {
+		PeerId peerId = peerFromMTP(m.vto_id);
+		if (m.has_from_id() && peerToUser(peerId) == MTP::authedId()) {
+			peerId = peerFromUser(m.vfrom_id);
+		}
+		if (HistoryItem *existing = App::histItemById(peerToChannel(peerId), m.vid.v)) {
+			existing->setText(qs(m.vmessage), m.has_entities() ? entitiesFromMTP(m.ventities.c_vector().v) : EntitiesInText());
+			existing->updateMedia(m.has_media() ? (&m.vmedia) : 0, true);
+			existing->setViewsCount(m.has_views() ? m.vviews.v : -1, false);
+			existing->initDimensions();
+			Notify::historyItemResized(existing);
+		}
+	}
+
 	void addSavedGif(DocumentData *doc) {
 		SavedGifs &saved(cRefSavedGifs());
 		int32 index = saved.indexOf(doc);
 		if (index) {
 			if (index > 0) saved.remove(index);
 			saved.push_front(doc);
-			if (saved.size() > cSavedGifsLimit()) saved.pop_back();
+			if (saved.size() > Global::SavedGifsLimit()) saved.pop_back();
 			Local::writeSavedGifs();
 
 			if (App::main()) emit App::main()->savedGifsUpdated();
diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h
index 2f4144e85..a23c92c39 100644
--- a/Telegram/SourceFiles/app.h
+++ b/Telegram/SourceFiles/app.h
@@ -81,6 +81,7 @@ namespace App {
 	void feedChatAdmins(const MTPDupdateChatAdmins &d, bool emitPeerUpdated = true);
 	void feedParticipantAdmin(const MTPDupdateChatParticipantAdmin &d, bool emitPeerUpdated = true);
 	bool checkEntitiesAndViewsUpdate(const MTPDmessage &m); // returns true if item found and it is not detached
+	void updateEditedMessage(const MTPDmessage &m);
 	void addSavedGif(DocumentData *doc);
 	void checkSavedGif(HistoryItem *item);
 	void feedMsgs(const QVector<MTPMessage> &msgs, NewMessageType type);
diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp
index b414fdb39..2e68ddd31 100644
--- a/Telegram/SourceFiles/application.cpp
+++ b/Telegram/SourceFiles/application.cpp
@@ -384,8 +384,6 @@ void Application::closeApplication() {
 		i->first->close();
 	}
 	_localClients.clear();
-
-	MTP::stop();
 }
 
 #ifndef TDESKTOP_DISABLE_AUTOUPDATE
@@ -808,7 +806,7 @@ AppClass::AppClass() : QObject()
 		checkMapVersion();
 	}
 
-	_window->updateIsActive(cOnlineFocusTimeout());
+	_window->updateIsActive(Global::OnlineFocusTimeout());
 }
 
 void AppClass::regPhotoUpdate(const PeerId &peer, const FullMsgId &msgId) {
@@ -926,7 +924,7 @@ void AppClass::checkLocalTime() {
 void AppClass::onAppStateChanged(Qt::ApplicationState state) {
 	checkLocalTime();
 	if (_window) {
-		_window->updateIsActive((state == Qt::ApplicationActive) ? cOnlineFocusTimeout() : cOfflineBlurTimeout());
+		_window->updateIsActive((state == Qt::ApplicationActive) ? Global::OnlineFocusTimeout() : Global::OfflineBlurTimeout());
 	}
 	if (state != Qt::ApplicationActive) {
 		PopupTooltip::Hide();
@@ -1083,6 +1081,8 @@ AppClass::~AppClass() {
 	App::deinitMedia();
 	deinitImageLinkManager();
 
+	MTP::stop();
+
 	AppObject = 0;
 	deleteAndMark(_uploader);
 	deleteAndMark(_translator);
diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp
index d236862a3..2a710d7aa 100644
--- a/Telegram/SourceFiles/boxes/addcontactbox.cpp
+++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp
@@ -275,7 +275,7 @@ NewGroupBox::NewGroupBox() : AbstractBox(),
 _group(this, qsl("group_type"), 0, lang(lng_create_group_title), true),
 _channel(this, qsl("group_type"), 1, lang(lng_create_channel_title)),
 _aboutGroupWidth(width() - st::boxPadding.left() - st::boxButtonPadding.right() - st::newGroupPadding.left() - st::defaultRadiobutton.textPosition.x()),
-_aboutGroup(st::normalFont, lng_create_group_about(lt_count, cMaxGroupCount()), _defaultOptions, _aboutGroupWidth),
+_aboutGroup(st::normalFont, lng_create_group_about(lt_count, Global::ChatSizeMax()), _defaultOptions, _aboutGroupWidth),
 _aboutChannel(st::normalFont, lang(lng_create_channel_about), _defaultOptions, _aboutGroupWidth),
 _next(this, lang(lng_create_group_next), st::defaultBoxButton),
 _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
diff --git a/Telegram/SourceFiles/boxes/confirmbox.cpp b/Telegram/SourceFiles/boxes/confirmbox.cpp
index b114ffa18..f7d3bfc64 100644
--- a/Telegram/SourceFiles/boxes/confirmbox.cpp
+++ b/Telegram/SourceFiles/boxes/confirmbox.cpp
@@ -189,7 +189,7 @@ void ConfirmLinkBox::onOpenLink() {
 
 MaxInviteBox::MaxInviteBox(const QString &link) : AbstractBox(st::boxWidth)
 , _close(this, lang(lng_box_ok), st::defaultBoxButton)
-, _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, cMaxGroupCount()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right())
+, _text(st::boxTextFont, lng_participant_invite_sorry(lt_count, Global::ChatSizeMax()), _confirmBoxTextOptions, st::boxWidth - st::boxPadding.left() - st::boxButtonPadding.right())
 , _link(link)
 , _linkOver(false)
 , a_goodOpacity(0, 0)
diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp
index e295611fe..80eca9935 100644
--- a/Telegram/SourceFiles/boxes/contactsbox.cpp
+++ b/Telegram/SourceFiles/boxes/contactsbox.cpp
@@ -427,7 +427,7 @@ void ContactsInner::paintDialog(Painter &p, PeerData *peer, ContactData *data, b
 			sel = false;
 		}
 	} else {
-		if (data->inchat || data->check || selectedCount() >= ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) {
+		if (data->inchat || data->check || selectedCount() >= ((_channel && _channel->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
 			sel = false;
 		}
 	}
@@ -767,7 +767,7 @@ void ContactsInner::changeCheckState(ContactData *data, PeerData *peer) {
 		data->check = false;
 		_checkedContacts.remove(peer);
 		--_selCount;
-	} else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())) {
+	} else if (selectedCount() < ((_channel && _channel->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
 		data->check = true;
 		_checkedContacts.insert(peer, true);
 		++_selCount;
@@ -1535,7 +1535,7 @@ void ContactsBox::paintEvent(QPaintEvent *e) {
 		paintTitle(p, lang(lng_channel_admins));
 	} else if (_inner.chat() || _inner.creating() != CreatingGroupNone) {
 		QString title(lang(addingAdmin ? lng_channel_add_admin : lng_profile_add_participant));
-		QString additional(addingAdmin ? QString() : QString("%1 / %2").arg(_inner.selectedCount()).arg(((_inner.channel() && _inner.channel()->isMegagroup()) ? cMaxMegaGroupCount() : cMaxGroupCount())));
+		QString additional(addingAdmin ? QString() : QString("%1 / %2").arg(_inner.selectedCount()).arg(((_inner.channel() && _inner.channel()->isMegagroup()) ? Global::MegagroupSizeMax() : Global::ChatSizeMax())));
 		paintTitle(p, title, additional);
 	} else if (_inner.bot()) {
 		paintTitle(p, lang(lng_bot_choose_group));
@@ -1757,7 +1757,7 @@ bool ContactsBox::creationFail(const RPCError &error) {
 
 MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget()
 , _rowHeight(st::contactsPadding.top() + st::contactsPhotoSize + st::contactsPadding.bottom())
-, _newItemHeight((channel->amCreator() && (channel->count < (channel->isMegagroup() ? cMaxMegaGroupCount() : cMaxGroupCount()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilterAdmins)) ? st::contactsNewItemHeight : 0)
+, _newItemHeight((channel->amCreator() && (channel->count < (channel->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax()) || (!channel->isMegagroup() && !channel->isPublic()) || filter == MembersFilterAdmins)) ? st::contactsNewItemHeight : 0)
 , _newItemSel(false)
 , _channel(channel)
 , _filter(filter)
@@ -1787,7 +1787,7 @@ MembersInner::MembersInner(ChannelData *channel, MembersFilter filter) : TWidget
 
 void MembersInner::load() {
 	if (!_loadingRequestId) {
-		_loadingRequestId = MTP::send(MTPchannels_GetParticipants(_channel->inputChannel, (_filter == MembersFilterRecent) ? MTP_channelParticipantsRecent() : MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(cMaxGroupCount())), rpcDone(&MembersInner::membersReceived), rpcFail(&MembersInner::membersFailed));
+		_loadingRequestId = MTP::send(MTPchannels_GetParticipants(_channel->inputChannel, (_filter == MembersFilterRecent) ? MTP_channelParticipantsRecent() : MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(Global::ChatSizeMax())), rpcDone(&MembersInner::membersReceived), rpcFail(&MembersInner::membersFailed));
 	}
 }
 
@@ -1826,7 +1826,7 @@ void MembersInner::paintEvent(QPaintEvent *e) {
 			paintDialog(p, _rows[from], data(from), sel, kickSel, kickDown);
 			p.translate(0, _rowHeight);
 		}
-		if (to == _rows.size() && _filter == MembersFilterRecent && (_rows.size() < _channel->count || _rows.size() >= cMaxGroupCount())) {
+		if (to == _rows.size() && _filter == MembersFilterRecent && (_rows.size() < _channel->count || _rows.size() >= Global::ChatSizeMax())) {
 			p.setPen(st::stickersReorderFg);
 			_about.draw(p, st::contactsPadding.left(), st::stickersReorderPadding.top(), _aboutWidth, style::al_center);
 		}
@@ -2005,7 +2005,7 @@ void MembersInner::refresh() {
 	} else {
 		_about.setText(st::boxTextFont, lng_channel_only_last_shown(lt_count, _rows.size()));
 		_aboutHeight = st::stickersReorderPadding.top() + _about.countHeight(_aboutWidth) + st::stickersReorderPadding.bottom();
-		if (_filter != MembersFilterRecent || (_rows.size() >= _channel->count && _rows.size() < cMaxGroupCount())) {
+		if (_filter != MembersFilterRecent || (_rows.size() >= _channel->count && _rows.size() < Global::ChatSizeMax())) {
 			_aboutHeight = 0;
 		}
 		resize(width(), st::membersPadding.top() + _newItemHeight + _rows.size() * _rowHeight + st::membersPadding.bottom() + _aboutHeight);
@@ -2220,7 +2220,7 @@ void MembersInner::kickAdminDone(const MTPUpdates &result, mtpRequestId req) {
 
 bool MembersInner::kickFail(const RPCError &error, mtpRequestId req) {
 	if (mtpIsFlood(error)) return false;
-	
+
 	if (_kickBox) _kickBox->onClose();
 	load();
 	return true;
@@ -2297,7 +2297,7 @@ void MembersBox::onScroll() {
 }
 
 void MembersBox::onAdd() {
-	if (_inner.filter() == MembersFilterRecent && _inner.channel()->count >= (_inner.channel()->isMegagroup() ? cMaxMegaGroupCount() : cMaxGroupCount())) {
+	if (_inner.filter() == MembersFilterRecent && _inner.channel()->count >= (_inner.channel()->isMegagroup() ? Global::MegagroupSizeMax() : Global::ChatSizeMax())) {
 		Ui::showLayer(new MaxInviteBox(_inner.channel()->invitationUrl), KeepOtherLayers);
 		return;
 	}
diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp
index d65081f51..70c257e9a 100644
--- a/Telegram/SourceFiles/facades.cpp
+++ b/Telegram/SourceFiles/facades.cpp
@@ -160,7 +160,7 @@ namespace Ui {
 					return w->minimizeToTray();
 				} else if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
 					w->hide();
-					w->updateIsActive(cOfflineBlurTimeout());
+					w->updateIsActive(Global::OfflineBlurTimeout());
 					w->updateGlobalMenu();
 					return true;
 				}
@@ -352,6 +352,23 @@ namespace Sandbox {
 struct GlobalDataStruct {
 	uint64 LaunchId = 0;
 	Adaptive::Layout AdaptiveLayout = Adaptive::NormalLayout;
+
+	// config
+	int32 ChatSizeMax = 200;
+	int32 MegagroupSizeMax = 1000;
+	int32 ForwardedCountMax = 100;
+	int32 OnlineUpdatePeriod = 120000;
+	int32 OfflineBlurTimeout = 5000;
+	int32 OfflineIdleTimeout = 30000;
+	int32 OnlineFocusTimeout = 1000;
+	int32 OnlineCloudTimeout = 300000;
+	int32 NotifyCloudDelay = 30000;
+	int32 NotifyDefaultDelay = 1500;
+	int32 ChatBigSize = 190; // ?
+	int32 PushChatPeriod = 0; // ?
+	int32 PushChatLimit = 0; // ?
+	int32 SavedGifsLimit = 100;
+	int32 EditTimeLimit = 0; // ?
 };
 GlobalDataStruct *GlobalData = 0;
 
@@ -375,4 +392,21 @@ namespace Global {
 	DefineReadOnlyVar(Global, uint64, LaunchId);
 	DefineVar(Global, Adaptive::Layout, AdaptiveLayout);
 
+	// config
+	DefineVar(Global, int32, ChatSizeMax);
+	DefineVar(Global, int32, MegagroupSizeMax);
+	DefineVar(Global, int32, ForwardedCountMax);
+	DefineVar(Global, int32, OnlineUpdatePeriod);
+	DefineVar(Global, int32, OfflineBlurTimeout);
+	DefineVar(Global, int32, OfflineIdleTimeout);
+	DefineVar(Global, int32, OnlineFocusTimeout);
+	DefineVar(Global, int32, OnlineCloudTimeout);
+	DefineVar(Global, int32, NotifyCloudDelay);
+	DefineVar(Global, int32, NotifyDefaultDelay);
+	DefineVar(Global, int32, ChatBigSize);
+	DefineVar(Global, int32, PushChatPeriod);
+	DefineVar(Global, int32, PushChatLimit);
+	DefineVar(Global, int32, SavedGifsLimit);
+	DefineVar(Global, int32, EditTimeLimit);
+
 };
diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h
index e89c2da18..96ee16687 100644
--- a/Telegram/SourceFiles/facades.h
+++ b/Telegram/SourceFiles/facades.h
@@ -140,6 +140,23 @@ namespace Global {
 	DeclareReadOnlyVar(uint64, LaunchId);
 	DeclareVar(Adaptive::Layout, AdaptiveLayout);
 
+	// config
+	DeclareVar(int32, ChatSizeMax);
+	DeclareVar(int32, MegagroupSizeMax);
+	DeclareVar(int32, ForwardedCountMax);
+	DeclareVar(int32, OnlineUpdatePeriod);
+	DeclareVar(int32, OfflineBlurTimeout);
+	DeclareVar(int32, OfflineIdleTimeout);
+	DeclareVar(int32, OnlineFocusTimeout); // not from config
+	DeclareVar(int32, OnlineCloudTimeout);
+	DeclareVar(int32, NotifyCloudDelay);
+	DeclareVar(int32, NotifyDefaultDelay);
+	DeclareVar(int32, ChatBigSize);
+	DeclareVar(int32, PushChatPeriod);
+	DeclareVar(int32, PushChatLimit);
+	DeclareVar(int32, SavedGifsLimit);
+	DeclareVar(int32, EditTimeLimit);
+
 };
 
 namespace Adaptive {
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index 66f360847..a1dcac2c3 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -1389,8 +1389,8 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
 		} else if (badMedia) {
 			result = new HistoryServiceMsg(this, block, m.vid.v, date(m.vdate), lang(lng_message_empty), m.vflags.v, 0, m.has_from_id() ? m.vfrom_id.v : 0);
 		} else {
-			if ((m.has_fwd_date() && m.vfwd_date.v > 0) || (m.has_fwd_from_id() && peerFromMTP(m.vfwd_from_id) != 0)) {
-				result = new HistoryForwarded(this, block, m);
+			if (m.has_fwd_from() && m.vfwd_from.type() == mtpc_messageFwdHeader) {
+				result = new HistoryForwarded(this, block, m, m.vfwd_from.c_messageFwdHeader());
 			} else if (m.has_reply_to_msg_id() && m.vreply_to_msg_id.v > 0) {
 				result = new HistoryReply(this, block, m);
 			} else {
@@ -6832,27 +6832,28 @@ HistoryMessage::~HistoryMessage() {
 	}
 }
 
-HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessage &msg)
+HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessage &msg, const MTPDmessageFwdHeader &f)
 : HistoryMessage(history, block, msg)
-, fwdDate(::date(msg.vfwd_date))
-, fwdFrom(App::peer(peerFromMTP(msg.vfwd_from_id)))
-, fwdFromVersion(fwdFrom->nameVersion)
-, fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) {
+, _fwdDate(::date(f.vdate))
+, _fwdAuthor(App::peer(f.has_channel_id() ? peerFromChannel(f.vchannel_id) : peerFromUser(f.vfrom_id)))
+, _fwdFrom(App::peer(f.has_from_id() ? peerFromUser(f.vfrom_id) : peerFromChannel(f.vchannel_id)))
+, _fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) {
 }
 
 HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, MsgId id, int32 flags, QDateTime date, int32 from, HistoryMessage *msg)
 : HistoryMessage(history, block, id, newForwardedFlags(history->peer, from, msg) | flags, msg->via() ? peerToUser(msg->viaBot()->id) : 0, date, from, msg->HistoryMessage::originalText(), msg->HistoryMessage::originalEntities(), msg->HistoryMessage::viewsCount(), msg->getMedia())
-, fwdDate(msg->dateForwarded())
-, fwdFrom(msg->fromForwarded())
-, fwdFromVersion(fwdFrom->nameVersion)
-, fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) {
+, _fwdDate(msg->fwdDate())
+, _fwdAuthor(msg->fwdAuthor())
+, _fwdFrom(msg->fwdFrom())
+, _fwdAuthorVersion(_fwdAuthor->nameVersion)
+, _fromWidth(st::msgServiceFont->width(lang(lng_forwarded_from)) + st::msgServiceFont->spacew) {
 }
 
 QString HistoryForwarded::selectedText(uint32 selection) const {
 	if (selection != FullSelection) return HistoryMessage::selectedText(selection);
 	QString result, original = HistoryMessage::selectedText(selection);
-	result.reserve(lang(lng_forwarded_from).size() + fwdFrom->name.size() + 4 + original.size());
-	result.append('[').append(lang(lng_forwarded_from)).append(' ').append(fwdFrom->name).append(qsl("]\n")).append(original);
+	result.reserve(lang(lng_forwarded_from).size() + _fwdAuthor->name.size() + 4 + original.size());
+	result.append('[').append(lang(lng_forwarded_from)).append(' ').append(_fwdAuthor->name).append(qsl("]\n")).append(original);
 	return result;
 }
 
@@ -6860,7 +6861,7 @@ void HistoryForwarded::initDimensions() {
 	fwdNameUpdated();
 	HistoryMessage::initDimensions();
 	if (!_media) {
-		int32 _namew = st::msgPadding.left() + fromWidth + fwdFromName.maxWidth() + st::msgPadding.right();
+		int32 _namew = st::msgPadding.left() + _fromWidth + _fwdAuthorName.maxWidth() + st::msgPadding.right();
 		if (via()) {
 			_namew += st::msgServiceFont->spacew + via()->maxWidth;
 		}
@@ -6869,19 +6870,19 @@ void HistoryForwarded::initDimensions() {
 }
 
 void HistoryForwarded::fwdNameUpdated() const {
-	QString fwdName((via() && fwdFrom->isUser()) ? fwdFrom->asUser()->firstName : App::peerName(fwdFrom));
-	fwdFromName.setText(st::msgServiceNameFont, fwdName, _textNameOptions);
+	QString fwdName((via() && _fwdAuthor->isUser()) ? _fwdAuthor->asUser()->firstName : App::peerName(_fwdAuthor));
+	_fwdAuthorName.setText(st::msgServiceNameFont, fwdName, _textNameOptions);
 	if (via()) {
 		int32 l = 0, w = 0;
 		countPositionAndSize(l, w);
-		via()->resize(w - st::msgPadding.left() - st::msgPadding.right() - fromWidth - fwdFromName.maxWidth() - st::msgServiceFont->spacew);
+		via()->resize(w - st::msgPadding.left() - st::msgPadding.right() - _fromWidth - _fwdAuthorName.maxWidth() - st::msgServiceFont->spacew);
 	}
 }
 
 void HistoryForwarded::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const {
-	if (drawBubble() && fwdFrom->nameVersion > fwdFromVersion) {
+	if (drawBubble() && _fwdAuthor->nameVersion > _fwdAuthorVersion) {
 		fwdNameUpdated();
-		fwdFromVersion = fwdFrom->nameVersion;
+		_fwdAuthorVersion = _fwdAuthor->nameVersion;
 	}
 	HistoryMessage::draw(p, r, selection, ms);
 }
@@ -6893,18 +6894,18 @@ void HistoryForwarded::drawForwardedFrom(Painter &p, int32 x, int32 y, int32 w,
 	p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p);
 	p.setFont(serviceFont);
 
-	if (via() && w > fromWidth + fwdFromName.maxWidth() + serviceFont->spacew) {
+	if (via() && w > _fromWidth + _fwdAuthorName.maxWidth() + serviceFont->spacew) {
 		p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
 
 		p.setFont(serviceName);
-		fwdFromName.draw(p, x + fromWidth, y, w - fromWidth);
+		_fwdAuthorName.draw(p, x + _fromWidth, y, w - _fromWidth);
 
-		p.drawText(x + fromWidth + fwdFromName.maxWidth() + serviceFont->spacew, y + serviceFont->ascent, via()->text);
-	} else if (w > fromWidth) {
+		p.drawText(x + _fromWidth + _fwdAuthorName.maxWidth() + serviceFont->spacew, y + serviceFont->ascent, via()->text);
+	} else if (w > _fromWidth) {
 		p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
 
 		p.setFont(serviceName);
-		fwdFromName.drawElided(p, x + fromWidth, y, w - fromWidth);
+		_fwdAuthorName.drawElided(p, x + _fromWidth, y, w - _fromWidth);
 	} else {
 		p.drawText(x, y + serviceFont->ascent, serviceFont->elided(lang(lng_forwarded_from), w));
 	}
@@ -6930,7 +6931,7 @@ int32 HistoryForwarded::resize(int32 width) {
 			if (via()) {
 				int32 l = 0, w = 0;
 				countPositionAndSize(l, w);
-				via()->resize(w - st::msgPadding.left() - st::msgPadding.right() - fromWidth - fwdFromName.maxWidth() - st::msgServiceFont->spacew);
+				via()->resize(w - st::msgPadding.left() - st::msgPadding.right() - _fromWidth - _fwdAuthorName.maxWidth() - st::msgServiceFont->spacew);
 			}
 		}
 	}
@@ -6992,9 +6993,9 @@ void HistoryForwarded::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorSt
 
 void HistoryForwarded::getForwardedState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 w) const {
 	state = HistoryDefaultCursorState;
-	if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) {
-		lnk = fwdFrom->lnk;
-	} else if (via() && x >= fromWidth + fwdFromName.maxWidth() + st::msgServiceFont->spacew && x < w && x < fromWidth + fwdFromName.maxWidth() + st::msgServiceFont->spacew + via()->maxWidth) {
+	if (x >= _fromWidth && x < w && x < _fromWidth + _fwdAuthorName.maxWidth()) {
+		lnk = _fwdAuthor->lnk;
+	} else if (via() && x >= _fromWidth + _fwdAuthorName.maxWidth() + st::msgServiceFont->spacew && x < w && x < _fromWidth + _fwdAuthorName.maxWidth() + st::msgServiceFont->spacew + via()->maxWidth) {
 		lnk = via()->lnk;
 	} else {
 		lnk = TextLinkPtr();
@@ -7121,7 +7122,7 @@ void HistoryReply::replyToNameUpdated() const {
 			w += st::msgServiceFont->spacew + replyToVia()->maxWidth;
 		}
 
-		_maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), 4 * w));
+		_maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), int32(st::maxSignatureSize)));
 	} else {
 		_maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message));
 	}
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index c5f667f25..0435cd00b 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -904,7 +904,7 @@ public:
 	virtual bool serviceMsg() const {
 		return false;
 	}
-	virtual void updateMedia(const MTPMessageMedia *media) {
+	virtual void updateMedia(const MTPMessageMedia *media, bool edited = false) {
 	}
 	virtual int32 addToOverview(AddToOverviewMethod method) {
 		return 0;
@@ -1026,6 +1026,16 @@ public:
 	}
 	bool displayFromPhoto() const;
 
+	virtual QDateTime fwdDate() const { // dynamic_cast optimize
+		return date;
+	}
+	virtual PeerData *fwdFrom() const { // dynamic_cast optimize
+		return from();
+	}
+	virtual PeerData *fwdAuthor() const { // dynamic_cast optimize
+		return author();
+	}
+
 	void clipCallback(ClipReaderNotification notification);
 
 	virtual ~HistoryItem();
@@ -2036,8 +2046,8 @@ public:
     QString notificationHeader() const;
     QString notificationText() const;
 
-	void updateMedia(const MTPMessageMedia *media) {
-		if (media && _media && _media->type() != MediaTypeWebPage) {
+	void updateMedia(const MTPMessageMedia *media, bool edited = false) {
+		if (!edited && media && _media && _media->type() != MediaTypeWebPage) {
 			_media->updateFrom(*media, this);
 		} else {
 			setMedia(media);
@@ -2087,13 +2097,6 @@ public:
 		return HistoryItem::viewsCount();
 	}
 
-	virtual QDateTime dateForwarded() const { // dynamic_cast optimize
-		return date;
-	}
-	virtual PeerData *fromForwarded() const { // dynamic_cast optimize
-		return author();
-	}
-
 	HistoryMessage *toHistoryMessage() { // dynamic_cast optimize
 		return this;
 	}
@@ -2120,7 +2123,7 @@ protected:
 class HistoryForwarded : public HistoryMessage {
 public:
 
-	HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessage &msg);
+	HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessage &msg, const MTPDmessageFwdHeader &f);
 	HistoryForwarded(History *history, HistoryBlock *block, MsgId id, int32 flags, QDateTime date, int32 from, HistoryMessage *msg);
 
 	void initDimensions();
@@ -2136,15 +2139,18 @@ public:
 	void getForwardedState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 w) const;
 	void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
 
-	QDateTime dateForwarded() const {
-		return fwdDate;
+	QDateTime fwdDate() const {
+		return _fwdDate;
 	}
-	PeerData *fromForwarded() const {
-		return fwdFrom;
+	PeerData *fwdAuthor() const {
+		return _fwdAuthor;
+	}
+	PeerData *fwdFrom() const {
+		return _fwdFrom;
 	}
 	QString selectedText(uint32 selection) const;
 	bool displayForwardedFrom() const {
-		return via() || !_media || !_media->isDisplayed() || (fwdFrom->isChannel() || !_media->hideForwardedFrom());
+		return via() || !_media || !_media->isDisplayed() || _fwdAuthor->isChannel() || !_media->hideForwardedFrom();
 	}
 
 	HistoryForwarded *toHistoryForwarded() {
@@ -2156,11 +2162,11 @@ public:
 
 protected:
 
-	QDateTime fwdDate;
-	PeerData *fwdFrom;
-	mutable Text fwdFromName;
-	mutable int32 fwdFromVersion;
-	int32 fromWidth;
+	QDateTime _fwdDate;
+	PeerData *_fwdAuthor, *_fwdFrom;
+	mutable Text _fwdAuthorName;
+	mutable int32 _fwdAuthorVersion;
+	int32 _fromWidth;
 
 };
 
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index 24105a372..d995e8bc5 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -4564,7 +4564,7 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
 	if (showFromName) {
 		flags |= MTPDmessage::flag_from_id;
 	}
-	h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(peer), MTPPeer(), MTPint(), MTPint(), MTPint(), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
+	h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(peer), MTPnullFwdHeader, MTPint(), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname), MTP_int(userId)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
 	h->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_int(sendFlags), p->input, MTP_int(replyTo), MTP_inputMediaContact(MTP_string(phone), MTP_string(fname), MTP_string(lname)), MTP_long(randomId), MTPnullMarkup), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, h->sendRequestId);
 
 	App::historyRegRandom(randomId, newId);
@@ -4894,7 +4894,7 @@ void HistoryWidget::sendBotCommand(const QString &cmd, MsgId replyTo) { // reply
 	bool lastKeyboardUsed = (_keyboard.forMsgId() == FullMsgId(_channel, _history->lastKeyboardId)) && (_keyboard.forMsgId() == FullMsgId(_channel, replyTo));
 
 	QString toSend = cmd;
-	PeerData *bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? (App::hoveredLinkItem()->toHistoryForwarded() ? App::hoveredLinkItem()->toHistoryForwarded()->fromForwarded() : App::hoveredLinkItem()->from()) : 0);
+	PeerData *bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? App::hoveredLinkItem()->toHistoryForwarded()->fwdFrom() : 0);
 	if (bot && (!bot->isUser() || !bot->asUser()->botInfo)) bot = 0;
 	QString username = bot ? bot->asUser()->username : QString();
 	int32 botStatus = _peer->isChat() ? _peer->asChat()->botStatus : (_peer->isMegagroup() ? _peer->asChannel()->mgInfo->botStatus : -1);
@@ -4919,7 +4919,7 @@ bool HistoryWidget::insertBotCommand(const QString &cmd, bool specialGif) {
 
 	QString toInsert = cmd;
 	if (!toInsert.isEmpty() && toInsert.at(0) != '@') {
-		PeerData *bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? (App::hoveredLinkItem()->toHistoryForwarded() ? App::hoveredLinkItem()->toHistoryForwarded()->fromForwarded() : App::hoveredLinkItem()->from()) : 0);
+		PeerData *bot = _peer->isUser() ? _peer : (App::hoveredLinkItem() ? App::hoveredLinkItem()->toHistoryForwarded()->fwdFrom() : 0);
 		if (!bot->isUser() || !bot->asUser()->botInfo) bot = 0;
 		QString username = bot ? bot->asUser()->username : QString();
 		int32 botStatus = _peer->isChat() ? _peer->asChat()->botStatus : (_peer->isMegagroup() ? _peer->asChannel()->mgInfo->botStatus : -1);
@@ -5532,14 +5532,14 @@ void HistoryWidget::confirmSendFile(const FileLoadResultPtr &file, bool ctrlShif
 		flags |= MTPDmessage::flag_from_id;
 	}
 	if (file->type == PreparePhoto) {
-		h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTPint(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
+		h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(file->photo, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
 	} else if (file->type == PrepareDocument) {
-		h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTPint(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
+		h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
 	} else if (file->type == PrepareAudio) {
 		if (!h->peer->isChannel()) {
 			flags |= MTPDmessage::flag_media_unread;
 		}
-		h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPPeer(), MTPint(), MTPint(), MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
+		h->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? 0 : MTP::authedId()), peerToMTP(file->to.peer), MTPnullFwdHeader, MTPint(), MTP_int(file->to.replyTo), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(file->document, MTP_string(file->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
 	}
 
 	if (_peer && file->to.peer == _peer->id) {
@@ -6410,7 +6410,7 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
 				App::feedDocument(document, thumb);
 			}
 			Local::writeStickerImage(mediaKey(DocumentFileLocation, MTP::maindc(), docId), result->data());
-			_history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(_history->peer->id), MTPPeer(), MTPint(), MTPint(), MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(document, MTP_string(result->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
+			_history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(_history->peer->id), MTPnullFwdHeader, MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaDocument(document, MTP_string(result->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
 		} else if (result->type == qstr("photo")) {
 			QImage fileThumb(result->thumb->pix().toImage());
 
@@ -6429,14 +6429,14 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
 			PhotoData *ph = App::photoSet(photoId, 0, 0, unixtime(), thumbPtr, ImagePtr(medium.width(), medium.height()), ImagePtr(result->width, result->height));
 			MTPPhoto photo = MTP_photo(MTP_long(photoId), MTP_long(0), MTP_int(ph->date), MTP_vector<MTPPhotoSize>(photoSizes));
 
-			_history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(_history->peer->id), MTPPeer(), MTPint(), MTPint(), MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(photo, MTP_string(result->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1)), NewMessageUnread);
+			_history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(_history->peer->id), MTPnullFwdHeader, MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(""), MTP_messageMediaPhoto(photo, MTP_string(result->caption)), MTPnullMarkup, MTPnullEntities, MTP_int(1), MTPint()), NewMessageUnread);
 		}
 	} else {
 		flags |= MTPDmessage::flag_entities;
 		if (result->noWebPage) {
 			sendFlags |= MTPmessages_SendMessage::flag_no_webpage;
 		}
-		_history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(_history->peer->id), MTPPeer(), MTPint(), MTPint(), MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(result->message), MTP_messageMediaEmpty(), MTPnullMarkup, linksToMTP(result->entities), MTP_int(1)), NewMessageUnread);
+		_history->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(_history->peer->id), MTPnullFwdHeader, MTP_int(bot ? peerToUser(bot->id) : 0), MTP_int(replyToId()), MTP_int(unixtime()), MTP_string(result->message), MTP_messageMediaEmpty(), MTPnullMarkup, linksToMTP(result->entities), MTP_int(1), MTPint()), NewMessageUnread);
 	}
 	_history->sendRequestId = MTP::send(MTPmessages_SendInlineBotResult(MTP_int(sendFlags), _peer->input, MTP_int(replyToId()), MTP_long(randomId), MTP_long(result->queryId), MTP_string(result->id)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::sendMessageFail), 0, 0, _history->sendRequestId);
 	App::main()->finishForwarding(_history, _broadcast.checked());
diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp
index 549b442e8..bcc91d717 100644
--- a/Telegram/SourceFiles/layout.cpp
+++ b/Telegram/SourceFiles/layout.cpp
@@ -582,7 +582,7 @@ void LayoutOverviewVoice::paint(Painter &p, const QRect &clip, uint32 selection,
 	}
 	bool showPause = updateStatusText();
 	int32 nameVersion = _parent->from()->nameVersion;
-	if (HistoryForwarded *fwd = _parent->toHistoryForwarded()) nameVersion = fwd->fromForwarded()->nameVersion;
+	if (HistoryForwarded *fwd = _parent->toHistoryForwarded()) nameVersion = fwd->fwdFrom()->nameVersion;
 	if (nameVersion > _nameVersion) {
 		updateName();
 	}
@@ -701,8 +701,8 @@ void LayoutOverviewVoice::getState(TextLinkPtr &link, HistoryCursorState &cursor
 void LayoutOverviewVoice::updateName() const {
 	int32 version = 0;
 	if (HistoryForwarded *fwd = _parent->toHistoryForwarded()) {
-		_name.setText(st::semiboldFont, lang(lng_forwarded_from) + ' ' + App::peerName(fwd->fromForwarded()), _textNameOptions);
-		version = fwd->fromForwarded()->nameVersion;
+		_name.setText(st::semiboldFont, lang(lng_forwarded_from) + ' ' + App::peerName(fwd->fwdFrom()), _textNameOptions);
+		version = fwd->fwdFrom()->nameVersion;
 	} else {
 		_name.setText(st::semiboldFont, App::peerName(_parent->from()), _textNameOptions);
 		version = _parent->from()->nameVersion;
diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp
index da64f2cb9..f8e622375 100644
--- a/Telegram/SourceFiles/localstorage.cpp
+++ b/Telegram/SourceFiles/localstorage.cpp
@@ -822,12 +822,12 @@ namespace {
 			if (_dcOpts) _dcOpts->insert(dcIdWithShift, mtpDcOption(dcIdWithShift % _mtp_internal::dcShift, flags, ip.toUtf8().constData(), port));
 		} break;
 
-		case dbiMaxGroupCount: {
+		case dbiChatSizeMax: {
 			qint32 maxSize;
 			stream >> maxSize;
 			if (!_checkStreamStatus(stream)) return false;
 
-			cSetMaxGroupCount(maxSize);
+			Global::SetChatSizeMax(maxSize);
 		} break;
 
 		case dbiSavedGifsLimit: {
@@ -835,15 +835,15 @@ namespace {
 			stream >> limit;
 			if (!_checkStreamStatus(stream)) return false;
 
-			cSetSavedGifsLimit(limit);
+			Global::SetSavedGifsLimit(limit);
 		} break;
 
-		case dbiMaxMegaGroupCount: {
+		case dbiMegagroupSizeMax: {
 			qint32 maxSize;
 			stream >> maxSize;
 			if (!_checkStreamStatus(stream)) return false;
 
-			cSetMaxMegaGroupCount(maxSize);
+			Global::SetMegagroupSizeMax(maxSize);
 		} break;
 
 		case dbiUser: {
@@ -2124,9 +2124,9 @@ namespace Local {
 		size += sizeof(quint32) + sizeof(qint32) * 6;
 
 		EncryptedDescriptor data(size);
-		data.stream << quint32(dbiMaxGroupCount) << qint32(cMaxGroupCount());
-		data.stream << quint32(dbiMaxMegaGroupCount) << qint32(cMaxMegaGroupCount());
-		data.stream << quint32(dbiSavedGifsLimit) << qint32(cSavedGifsLimit());
+		data.stream << quint32(dbiChatSizeMax) << qint32(Global::ChatSizeMax());
+		data.stream << quint32(dbiMegagroupSizeMax) << qint32(Global::MegagroupSizeMax());
+		data.stream << quint32(dbiSavedGifsLimit) << qint32(Global::SavedGifsLimit());
 		data.stream << quint32(dbiAutoStart) << qint32(cAutoStart());
 		data.stream << quint32(dbiStartMinimized) << qint32(cStartMinimized());
 		data.stream << quint32(dbiSendToMenu) << qint32(cSendToMenu());
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 181fd9b84..8d45382be 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -537,11 +537,7 @@ void MainWidget::fillForwardingInfo(Text *&from, Text *&text, bool &serviceColor
 	if (_toForward.isEmpty()) return;
 	int32 version = 0;
 	for (SelectedItemSet::const_iterator i = _toForward.cbegin(), e = _toForward.cend(); i != e; ++i) {
-		if (HistoryForwarded *fwd = i.value()->toHistoryForwarded()) {
-			version += fwd->fromForwarded()->nameVersion;
-		} else {
-			version += i.value()->author()->nameVersion;
-		}
+		version += i.value()->fwdAuthor()->nameVersion;
 	}
 	if (version != _toForwardNameVersion) {
 		updateForwardingTexts();
@@ -562,10 +558,7 @@ void MainWidget::updateForwardingTexts() {
 		QVector<PeerData*> fromUsers;
 		fromUsers.reserve(_toForward.size());
 		for (SelectedItemSet::const_iterator i = _toForward.cbegin(), e = _toForward.cend(); i != e; ++i) {
-			PeerData *from = i.value()->author();
-			if (HistoryForwarded *fwd = i.value()->toHistoryForwarded()) {
-				from = fwd->fromForwarded();
-			}
+			PeerData *from = i.value()->fwdAuthor();
 			if (!fromUsersMap.contains(from)) {
 				fromUsersMap.insert(from, true);
 				fromUsers.push_back(from);
@@ -1328,7 +1321,7 @@ void MainWidget::sendMessage(History *hist, const QString &text, MsgId replyTo,
 		if (!sentEntities.c_vector().v.isEmpty()) {
 			sendFlags |= MTPmessages_SendMessage::flag_entities;
 		}
-		hist->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(hist->peer->id), MTPPeer(), MTPint(), MTPint(), MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media, MTPnullMarkup, localEntities, MTP_int(1)), NewMessageUnread);
+		hist->addNewMessage(MTP_message(MTP_int(flags), MTP_int(newId.msg), MTP_int(showFromName ? MTP::authedId() : 0), peerToMTP(hist->peer->id), MTPnullFwdHeader, MTPint(), MTP_int(replyTo), MTP_int(unixtime()), msgText, media, MTPnullMarkup, localEntities, MTP_int(1), MTPint()), NewMessageUnread);
 		hist->sendRequestId = MTP::send(MTPmessages_SendMessage(MTP_int(sendFlags), hist->peer->input, MTP_int(replyTo), msgText, MTP_long(randomId), MTPnullMarkup, sentEntities), rpcDone(&MainWidget::sentUpdatesReceived, randomId), rpcFail(&MainWidget::sendMessageFail), 0, 0, hist->sendRequestId);
 	}
 
@@ -1912,7 +1905,7 @@ void MainWidget::serviceNotification(const QString &msg, const MTPMessageMedia &
 	HistoryItem *item = 0;
 	while (textSplit(sendingText, sendingEntities, leftText, leftEntities, MaxMessageSize)) {
 		MTPVector<MTPMessageEntity> localEntities = linksToMTP(sendingEntities);
-		item = App::histories().addNewMessage(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPPeer(), MTPint(), MTPint(), MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup, localEntities, MTPint()), NewMessageUnread);
+		item = App::histories().addNewMessage(MTP_message(MTP_int(flags), MTP_int(clientMsgId()), MTP_int(ServiceUserId), MTP_peerUser(MTP_int(MTP::authedId())), MTPnullFwdHeader, MTPint(), MTPint(), MTP_int(unixtime()), MTP_string(sendingText), media, MTPnullMarkup, localEntities, MTPint(), MTPint()), NewMessageUnread);
 	}
 	if (item) {
 		history.peerMessagesUpdated(item->history()->peer->id);
@@ -3461,7 +3454,7 @@ void MainWidget::openPeerByName(const QString &username, MsgId msgId, const QStr
 				showPeerProfile(peer);
 			}
 		} else {
-			if (msgId == ShowAtProfileMsgId) {
+			if (msgId == ShowAtProfileMsgId || !peer->isChannel()) { // show specific posts only in channels / supergroups
 				msgId = ShowAtUnreadMsgId;
 			}
 			if (peer->isUser() && peer->asUser()->botInfo) {
@@ -3541,7 +3534,7 @@ void MainWidget::usernameResolveDone(QPair<MsgId, QString> msgIdAndStartToken, c
 			showPeerProfile(peer);
 		}
 	} else {
-		if (msgId == ShowAtProfileMsgId) {
+		if (msgId == ShowAtProfileMsgId || !peer->isChannel()) { // show specific posts only in channels / supergroups
 			msgId = ShowAtUnreadMsgId;
 		}
 		if (peer->isUser() && peer->asUser()->botInfo) {
@@ -3892,21 +3885,21 @@ void MainWidget::updateOnline(bool gotOtherOffline) {
 	App::wnd()->checkAutoLock();
 
 	bool isOnline = App::wnd()->isActive();
-	int updateIn = cOnlineUpdatePeriod();
+	int updateIn = Global::OnlineUpdatePeriod();
 	if (isOnline) {
 		uint64 idle = psIdleTime();
-		if (idle >= uint64(cOfflineIdleTimeout())) {
+		if (idle >= uint64(Global::OfflineIdleTimeout())) {
 			isOnline = false;
 			if (!_isIdle) {
 				_isIdle = true;
 				_idleFinishTimer.start(900);
 			}
 		} else {
-			updateIn = qMin(updateIn, int(cOfflineIdleTimeout() - idle));
+			updateIn = qMin(updateIn, int(Global::OfflineIdleTimeout() - idle));
 		}
 	}
 	uint64 ms = getms(true);
-	if (isOnline != _lastWasOnline || (isOnline && _lastSetOnline + cOnlineUpdatePeriod() <= ms) || (isOnline && gotOtherOffline)) {
+	if (isOnline != _lastWasOnline || (isOnline && _lastSetOnline + Global::OnlineUpdatePeriod() <= ms) || (isOnline && gotOtherOffline)) {
 		if (_onlineRequest) {
 			MTP::cancel(_onlineRequest);
 			_onlineRequest = 0;
@@ -3916,20 +3909,20 @@ void MainWidget::updateOnline(bool gotOtherOffline) {
 		_lastSetOnline = ms;
 		_onlineRequest = MTP::send(MTPaccount_UpdateStatus(MTP_bool(!isOnline)));
 
-		if (App::self()) App::self()->onlineTill = unixtime() + (isOnline ? (cOnlineUpdatePeriod() / 1000) : -1);
+		if (App::self()) App::self()->onlineTill = unixtime() + (isOnline ? (Global::OnlineUpdatePeriod() / 1000) : -1);
 
 		_lastSetOnline = getms(true);
 
 		updateOnlineDisplay();
 	} else if (isOnline) {
-		updateIn = qMin(updateIn, int(_lastSetOnline + cOnlineUpdatePeriod() - ms));
+		updateIn = qMin(updateIn, int(_lastSetOnline + Global::OnlineUpdatePeriod() - ms));
 	}
 	_onlineTimer.start(updateIn);
 }
 
 void MainWidget::checkIdleFinish() {
 	if (this != App::main()) return;
-	if (psIdleTime() < uint64(cOfflineIdleTimeout())) {
+	if (psIdleTime() < uint64(Global::OfflineIdleTimeout())) {
 		_idleFinishTimer.stop();
 		_isIdle = false;
 		updateOnline();
@@ -4011,18 +4004,28 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
 
 	case mtpc_updateShortMessage: {
 		const MTPDupdateShortMessage &d(updates.c_updateShortMessage());
-		if (!App::userLoaded(d.vuser_id.v) || (d.has_fwd_from_id() && !App::peerLoaded(peerFromMTP(d.vfwd_from_id))) || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) {
+		if (!App::userLoaded(d.vuser_id.v) || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) {
 			MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
 			return getDifference();
 		}
-
+		if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) {
+			const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader());
+			if (f.has_from_id() && !App::peerLoaded(peerFromUser(f.vfrom_id))) {
+				MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
+				return getDifference();
+			}
+			if (f.has_channel_id() && !App::peerLoaded(peerFromChannel(f.vchannel_id))) {
+				MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
+				return getDifference();
+			}
+		}
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, updates)) {
 			return;
 		}
 
 		// update before applying skipped
 		int32 flags = d.vflags.v | MTPDmessage::flag_from_id;
-		HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from_id, d.vfwd_date, d.vfwd_post, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint()), NewMessageUnread);
+		HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, d.is_out() ? MTP_int(MTP::authedId()) : d.vuser_id, MTP_peerUser(d.is_out() ? d.vuser_id : MTP_int(MTP::authedId())), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread);
 		if (item) {
 			history.peerMessagesUpdated(item->history()->peer->id);
 		}
@@ -4035,19 +4038,29 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) {
 	case mtpc_updateShortChatMessage: {
 		const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage());
 		bool noFrom = !App::userLoaded(d.vfrom_id.v);
-		if (!App::chatLoaded(d.vchat_id.v) || noFrom || (d.has_fwd_from_id() && !App::peerLoaded(peerFromMTP(d.vfwd_from_id))) || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) {
+		if (!App::chatLoaded(d.vchat_id.v) || noFrom || (d.has_via_bot_id() && !App::peerLoaded(peerFromUser(d.vvia_bot_id)))) {
 			MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
 			if (noFrom && App::api()) App::api()->requestFullPeer(App::chatLoaded(d.vchat_id.v));
 			return getDifference();
 		}
-
+		if (d.has_fwd_from() && d.vfwd_from.type() == mtpc_messageFwdHeader) {
+			const MTPDmessageFwdHeader &f(d.vfwd_from.c_messageFwdHeader());
+			if (f.has_from_id() && !App::peerLoaded(peerFromUser(f.vfrom_id))) {
+				MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
+				return getDifference();
+			}
+			if (f.has_channel_id() && !App::peerLoaded(peerFromChannel(f.vchannel_id))) {
+				MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }%1").arg(cTestMode() ? " TESTMODE" : ""));
+				return getDifference();
+			}
+		}
 		if (!ptsUpdated(d.vpts.v, d.vpts_count.v, updates)) {
 			return;
 		}
 
 		// update before applying skipped
 		int32 flags = d.vflags.v | MTPDmessage::flag_from_id;
-		HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from_id, d.vfwd_date, d.vfwd_post, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint()), NewMessageUnread);
+		HistoryItem *item = App::histories().addNewMessage(MTP_message(MTP_int(flags), d.vid, d.vfrom_id, MTP_peerChat(d.vchat_id), d.vfwd_from, d.vvia_bot_id, d.vreply_to_msg_id, d.vdate, d.vmessage, MTP_messageMediaEmpty(), MTPnullMarkup, d.has_entities() ? d.ventities : MTPnullEntities, MTPint(), MTPint()), NewMessageUnread);
 		if (item) {
 			history.peerMessagesUpdated(item->history()->peer->id);
 		}
@@ -4436,6 +4449,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		const MTPDupdatePrivacy &d(update.c_updatePrivacy());
 	} break;
 
+	/////// Channel updates
 	case mtpc_updateChannel: {
 		const MTPDupdateChannel &d(update.c_updateChannel());
 		if (ChannelData *channel = App::channelLoaded(d.vchannel_id.v)) {
@@ -4481,6 +4495,27 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		}
 	} break;
 
+	case mtpc_updateEditChannelMessage: {
+		const MTPDupdateEditChannelMessage &d(update.c_updateEditChannelMessage());
+		ChannelData *channel = App::channelLoaded(peerToChannel(peerFromMessage(d.vmessage)));
+
+		if (channel && !_handlingChannelDifference) {
+			if (channel->ptsRequesting()) { // skip global updates while getting channel difference
+				return;
+			} else if (!channel->ptsUpdated(d.vpts.v, d.vpts_count.v, update)) {
+				return;
+			}
+		}
+
+		// update before applying skipped
+		if (d.vmessage.type() == mtpc_message) { // apply message edit
+			App::updateEditedMessage(d.vmessage.c_message());
+		}
+		if (channel && !_handlingChannelDifference) {
+			channel->ptsApplySkippedUpdates();
+		}
+	} break;
+
 	case mtpc_updateReadChannelInbox: {
 		const MTPDupdateReadChannelInbox &d(update.c_updateReadChannelInbox());
 		ChannelData *channel = App::channelLoaded(d.vchannel_id.v);
@@ -4528,6 +4563,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		}
 	} break;
 
+	////// Cloud sticker sets
 	case mtpc_updateNewStickerSet: {
 		const MTPDupdateNewStickerSet &d(update.c_updateNewStickerSet());
 		if (d.vstickerset.type() == mtpc_messages_stickerSet) {
@@ -4624,6 +4660,5 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 		cSetLastSavedGifsUpdate(0);
 		App::main()->updateStickers();
 	} break;
-
 	}
 }
diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp
index c8719fb3f..56fe2baec 100644
--- a/Telegram/SourceFiles/mediaview.cpp
+++ b/Telegram/SourceFiles/mediaview.cpp
@@ -909,11 +909,7 @@ void MediaView::displayPhoto(PhotoData *photo, HistoryItem *item) {
 	_y = (height() - _h) / 2;
 	_width = _w;
 	if (_msgid && item) {
-		if (HistoryForwarded *fwd = item->toHistoryForwarded()) {
-			_from = fwd->fromForwarded();
-		} else {
-			_from = item->author();
-		}
+		_from = item->fwdAuthor();
 	} else {
 		_from = _user;
 	}
@@ -1062,11 +1058,7 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
 	}
 	_x = (width() - _w) / 2;
 	_y = (height() - _h) / 2;
-	if (HistoryForwarded *fwd = item->toHistoryForwarded()) {
-		_from = fwd->fromForwarded();
-	} else {
-		_from = item->author();
-	}
+	_from = item->fwdAuthor();
 	_full = 1;
 	updateControls();
 	if (isHidden()) {
diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp
index fdd03e122..a6847bf34 100644
--- a/Telegram/SourceFiles/mtproto/mtp.cpp
+++ b/Telegram/SourceFiles/mtproto/mtp.cpp
@@ -39,7 +39,7 @@ namespace {
 	bool _started = false;
 
 	uint32 layer;
-	
+
 	typedef QMap<mtpRequestId, RPCResponseHandler> ParserMap;
 	ParserMap parserMap;
 	QMutex parserMapLock;
@@ -209,7 +209,7 @@ namespace {
 			return true;
 		} else if (code < 0 || code >= 500 || (m = QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err)).hasMatch()) {
 			if (!requestId) return false;
-			
+
 			int32 secs = 1;
 			if (code < 0 || code >= 500) {
 				RequestsDelays::iterator i = requestsDelays.find(requestId);
@@ -366,13 +366,13 @@ namespace _mtp_internal {
 		if (!(dcWithShift % _mtp_internal::dcShift)) {
 			dcWithShift += (mainSession->getDcWithShift() % _mtp_internal::dcShift);
 		}
-		
+
 		Sessions::const_iterator i = sessions.constFind(dcWithShift);
 		if (i != sessions.cend()) return *i;
 
 		MTProtoSessionPtr result(new MTProtoSession());
 		result->start(dcWithShift);
-		
+
 		sessions.insert(dcWithShift, result);
 		return result;
 	}
@@ -380,7 +380,7 @@ namespace _mtp_internal {
 	bool paused() {
 		return _paused;
 	}
-	
+
 	void registerRequest(mtpRequestId requestId, int32 dcWithShift) {
 		{
 			QMutexLocker locker(&requestByDCLock);
@@ -704,7 +704,7 @@ namespace MTP {
 		if (!(dc % _mtp_internal::dcShift)) {
 			dc += (mainSession->getDcWithShift() % _mtp_internal::dcShift);
 		}
-		
+
 		Sessions::const_iterator i = sessions.constFind(dc);
 		if (i != sessions.cend()) return (*i)->getState();
 
diff --git a/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp b/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp
index 858394a31..48bd7fd52 100644
--- a/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp
+++ b/Telegram/SourceFiles/mtproto/mtpCoreTypes.cpp
@@ -149,6 +149,10 @@ void mtpTextSerializeCore(MTPStringLogger &to, const mtpPrime *&from, const mtpP
 	}
 }
 
+const MTPReplyMarkup MTPnullMarkup = MTP_replyKeyboardMarkup(MTP_int(0), MTP_vector<MTPKeyboardButtonRow>(0));
+const MTPVector<MTPMessageEntity> MTPnullEntities = MTP_vector<MTPMessageEntity>(0);
+const MTPMessageFwdHeader MTPnullFwdHeader = MTP_messageFwdHeader(MTPint(), MTPint(), MTPint(), MTPint(), MTPint());
+
 QString stickerSetTitle(const MTPDstickerSet &s) {
 	QString title = qs(s.vtitle);
 	if ((s.vflags.v & MTPDstickerSet::flag_official) && !title.compare(qstr("Great Minds"), Qt::CaseInsensitive)) {
diff --git a/Telegram/SourceFiles/mtproto/mtpCoreTypes.h b/Telegram/SourceFiles/mtproto/mtpCoreTypes.h
index b1f655dc4..dc16848d7 100644
--- a/Telegram/SourceFiles/mtproto/mtpCoreTypes.h
+++ b/Telegram/SourceFiles/mtproto/mtpCoreTypes.h
@@ -985,7 +985,8 @@ enum { // client side flags
 	MTPDstickerSet_flag_NOT_LOADED = (1 << 31), // sticker set is not yet loaded
 };
 
-static const MTPReplyMarkup MTPnullMarkup = MTP_replyKeyboardMarkup(MTP_int(0), MTP_vector<MTPKeyboardButtonRow>(0));
-static const MTPVector<MTPMessageEntity> MTPnullEntities = MTP_vector<MTPMessageEntity>(0);
+extern const MTPReplyMarkup MTPnullMarkup;
+extern const MTPVector<MTPMessageEntity> MTPnullEntities;
+extern const MTPMessageFwdHeader MTPnullFwdHeader;
 
-QString stickerSetTitle(const MTPDstickerSet &s);
\ No newline at end of file
+QString stickerSetTitle(const MTPDstickerSet &s);
diff --git a/Telegram/SourceFiles/mtproto/mtpDC.cpp b/Telegram/SourceFiles/mtproto/mtpDC.cpp
index 1a9bf11d7..899e21a2c 100644
--- a/Telegram/SourceFiles/mtproto/mtpDC.cpp
+++ b/Telegram/SourceFiles/mtproto/mtpDC.cpp
@@ -25,7 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "localstorage.h"
 
 namespace {
-	
+
 	MTProtoDCMap gDCs;
 	bool configLoadedOnce = false;
 	bool mainDCChanged = false;
@@ -152,9 +152,21 @@ namespace {
 		DEBUG_LOG(("MTP Info: got config, chat_size_max: %1, date: %2, test_mode: %3, this_dc: %4, dc_options.length: %5").arg(data.vchat_size_max.v).arg(data.vdate.v).arg(mtpIsTrue(data.vtest_mode)).arg(data.vthis_dc.v).arg(data.vdc_options.c_vector().v.size()));
 
 		mtpUpdateDcOptions(data.vdc_options.c_vector().v);
-		cSetMaxGroupCount(data.vchat_size_max.v);
-		cSetMaxMegaGroupCount(data.vmegagroup_size_max.v);
-		cSetSavedGifsLimit(data.vsaved_gifs_limit.v);
+
+		Global::SetChatSizeMax(data.vchat_size_max.v);
+		Global::SetMegagroupSizeMax(data.vmegagroup_size_max.v);
+		Global::SetForwardedCountMax(data.vforwarded_count_max.v);
+		Global::SetOnlineUpdatePeriod(data.vonline_update_period_ms.v);
+		Global::SetOfflineBlurTimeout(data.voffline_blur_timeout_ms.v);
+		Global::SetOfflineIdleTimeout(data.voffline_idle_timeout_ms.v);
+		Global::SetOnlineCloudTimeout(data.vonline_cloud_timeout_ms.v);
+		Global::SetNotifyCloudDelay(data.vnotify_cloud_delay_ms.v);
+		Global::SetNotifyDefaultDelay(data.vnotify_default_delay_ms.v);
+		Global::SetChatBigSize(data.vchat_big_size.v); // ?
+		Global::SetPushChatPeriod(data.vpush_chat_period_ms.v); // ?
+		Global::SetPushChatLimit(data.vpush_chat_limit.v); // ?
+		Global::SetSavedGifsLimit(data.vsaved_gifs_limit.v);
+		Global::SetEditTimeLimit(data.vedit_time_limit.v); // ?
 
 		configLoadedOnce = true;
 		Local::writeSettings();
diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.cpp b/Telegram/SourceFiles/mtproto/mtpScheme.cpp
index 462d46aea..0d1eb87c2 100644
--- a/Telegram/SourceFiles/mtproto/mtpScheme.cpp
+++ b/Telegram/SourceFiles/mtproto/mtpScheme.cpp
@@ -1007,17 +1007,18 @@ void _serialize_user(MTPStringLogger &to, int32 stage, int32 lev, Types &types,
 	case 7: to.add("  bot_nochats: "); ++stages.back(); if (flag & MTPDuser::flag_bot_nochats) { to.add("YES [ BY BIT 16 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 16 IN FIELD flags ]"); } break;
 	case 8: to.add("  verified: "); ++stages.back(); if (flag & MTPDuser::flag_verified) { to.add("YES [ BY BIT 17 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 17 IN FIELD flags ]"); } break;
 	case 9: to.add("  restricted: "); ++stages.back(); if (flag & MTPDuser::flag_restricted) { to.add("YES [ BY BIT 18 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 18 IN FIELD flags ]"); } break;
-	case 10: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 11: to.add("  access_hash: "); ++stages.back(); if (flag & MTPDuser::flag_access_hash) { types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
-	case 12: to.add("  first_name: "); ++stages.back(); if (flag & MTPDuser::flag_first_name) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
-	case 13: to.add("  last_name: "); ++stages.back(); if (flag & MTPDuser::flag_last_name) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 14: to.add("  username: "); ++stages.back(); if (flag & MTPDuser::flag_username) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
-	case 15: to.add("  phone: "); ++stages.back(); if (flag & MTPDuser::flag_phone) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break;
-	case 16: to.add("  photo: "); ++stages.back(); if (flag & MTPDuser::flag_photo) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
-	case 17: to.add("  status: "); ++stages.back(); if (flag & MTPDuser::flag_status) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
-	case 18: to.add("  bot_info_version: "); ++stages.back(); if (flag & MTPDuser::flag_bot_info_version) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 14 IN FIELD flags ]"); } break;
-	case 19: to.add("  restriction_reason: "); ++stages.back(); if (flag & MTPDuser::flag_restriction_reason) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 18 IN FIELD flags ]"); } break;
-	case 20: to.add("  bot_inline_placeholder: "); ++stages.back(); if (flag & MTPDuser::flag_bot_inline_placeholder) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 19 IN FIELD flags ]"); } break;
+	case 10: to.add("  min: "); ++stages.back(); if (flag & MTPDuser::flag_min) { to.add("YES [ BY BIT 20 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 20 IN FIELD flags ]"); } break;
+	case 11: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 12: to.add("  access_hash: "); ++stages.back(); if (flag & MTPDuser::flag_access_hash) { types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	case 13: to.add("  first_name: "); ++stages.back(); if (flag & MTPDuser::flag_first_name) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 14: to.add("  last_name: "); ++stages.back(); if (flag & MTPDuser::flag_last_name) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
+	case 15: to.add("  username: "); ++stages.back(); if (flag & MTPDuser::flag_username) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
+	case 16: to.add("  phone: "); ++stages.back(); if (flag & MTPDuser::flag_phone) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break;
+	case 17: to.add("  photo: "); ++stages.back(); if (flag & MTPDuser::flag_photo) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
+	case 18: to.add("  status: "); ++stages.back(); if (flag & MTPDuser::flag_status) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
+	case 19: to.add("  bot_info_version: "); ++stages.back(); if (flag & MTPDuser::flag_bot_info_version) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 14 IN FIELD flags ]"); } break;
+	case 20: to.add("  restriction_reason: "); ++stages.back(); if (flag & MTPDuser::flag_restriction_reason) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 18 IN FIELD flags ]"); } break;
+	case 21: to.add("  bot_inline_placeholder: "); ++stages.back(); if (flag & MTPDuser::flag_bot_inline_placeholder) { types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 19 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -1351,17 +1352,16 @@ void _serialize_message(MTPStringLogger &to, int32 stage, int32 lev, Types &type
 	case 7: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 8: to.add("  from_id: "); ++stages.back(); if (flag & MTPDmessage::flag_from_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 8 IN FIELD flags ]"); } break;
 	case 9: to.add("  to_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 10: to.add("  fwd_from_id: "); ++stages.back(); if (flag & MTPDmessage::flag_fwd_from_id) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 11: to.add("  fwd_date: "); ++stages.back(); if (flag & MTPDmessage::flag_fwd_date) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 12: to.add("  fwd_post: "); ++stages.back(); if (flag & MTPDmessage::flag_fwd_post) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 12 IN FIELD flags ]"); } break;
-	case 13: to.add("  via_bot_id: "); ++stages.back(); if (flag & MTPDmessage::flag_via_bot_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 11 IN FIELD flags ]"); } break;
-	case 14: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDmessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
-	case 15: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 16: to.add("  message: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 17: to.add("  media: "); ++stages.back(); if (flag & MTPDmessage::flag_media) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 9 IN FIELD flags ]"); } break;
-	case 18: to.add("  reply_markup: "); ++stages.back(); if (flag & MTPDmessage::flag_reply_markup) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
-	case 19: to.add("  entities: "); ++stages.back(); if (flag & MTPDmessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
-	case 20: to.add("  views: "); ++stages.back(); if (flag & MTPDmessage::flag_views) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 10 IN FIELD flags ]"); } break;
+	case 10: to.add("  fwd_from: "); ++stages.back(); if (flag & MTPDmessage::flag_fwd_from) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
+	case 11: to.add("  via_bot_id: "); ++stages.back(); if (flag & MTPDmessage::flag_via_bot_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 11 IN FIELD flags ]"); } break;
+	case 12: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDmessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
+	case 13: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 14: to.add("  message: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 15: to.add("  media: "); ++stages.back(); if (flag & MTPDmessage::flag_media) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 9 IN FIELD flags ]"); } break;
+	case 16: to.add("  reply_markup: "); ++stages.back(); if (flag & MTPDmessage::flag_reply_markup) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
+	case 17: to.add("  entities: "); ++stages.back(); if (flag & MTPDmessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
+	case 18: to.add("  views: "); ++stages.back(); if (flag & MTPDmessage::flag_views) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 10 IN FIELD flags ]"); } break;
+	case 19: to.add("  edit_date: "); ++stages.back(); if (flag & MTPDmessage::flag_edit_date) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 15 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -1379,11 +1379,13 @@ void _serialize_messageService(MTPStringLogger &to, int32 stage, int32 lev, Type
 	case 2: to.add("  out: "); ++stages.back(); if (flag & MTPDmessageService::flag_out) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
 	case 3: to.add("  mentioned: "); ++stages.back(); if (flag & MTPDmessageService::flag_mentioned) { to.add("YES [ BY BIT 4 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 4 IN FIELD flags ]"); } break;
 	case 4: to.add("  media_unread: "); ++stages.back(); if (flag & MTPDmessageService::flag_media_unread) { to.add("YES [ BY BIT 5 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
-	case 5: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 6: to.add("  from_id: "); ++stages.back(); if (flag & MTPDmessageService::flag_from_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 8 IN FIELD flags ]"); } break;
-	case 7: to.add("  to_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 8: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 9: to.add("  action: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 5: to.add("  silent: "); ++stages.back(); if (flag & MTPDmessageService::flag_silent) { to.add("YES [ BY BIT 13 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 13 IN FIELD flags ]"); } break;
+	case 6: to.add("  post: "); ++stages.back(); if (flag & MTPDmessageService::flag_post) { to.add("YES [ BY BIT 14 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 14 IN FIELD flags ]"); } break;
+	case 7: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 8: to.add("  from_id: "); ++stages.back(); if (flag & MTPDmessageService::flag_from_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 8 IN FIELD flags ]"); } break;
+	case 9: to.add("  to_id: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 10: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 11: to.add("  action: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -2872,6 +2874,21 @@ void _serialize_updateBotInlineSend(MTPStringLogger &to, int32 stage, int32 lev,
 	}
 }
 
+void _serialize_updateEditChannelMessage(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ updateEditChannelMessage");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  message: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  pts: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 2: to.add("  pts_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_updates_state(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
@@ -2963,12 +2980,10 @@ void _serialize_updateShortMessage(MTPStringLogger &to, int32 stage, int32 lev,
 	case 9: to.add("  pts: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 10: to.add("  pts_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 11: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 12: to.add("  fwd_from_id: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_fwd_from_id) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 13: to.add("  fwd_date: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_fwd_date) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 14: to.add("  fwd_post: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_fwd_post) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 12 IN FIELD flags ]"); } break;
-	case 15: to.add("  via_bot_id: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_via_bot_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 11 IN FIELD flags ]"); } break;
-	case 16: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
-	case 17: to.add("  entities: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
+	case 12: to.add("  fwd_from: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_fwd_from) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
+	case 13: to.add("  via_bot_id: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_via_bot_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 11 IN FIELD flags ]"); } break;
+	case 14: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
+	case 15: to.add("  entities: "); ++stages.back(); if (flag & MTPDupdateShortMessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -2994,12 +3009,10 @@ void _serialize_updateShortChatMessage(MTPStringLogger &to, int32 stage, int32 l
 	case 10: to.add("  pts: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 11: to.add("  pts_count: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 12: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 13: to.add("  fwd_from_id: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_fwd_from_id) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 14: to.add("  fwd_date: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_fwd_date) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
-	case 15: to.add("  fwd_post: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_fwd_post) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 12 IN FIELD flags ]"); } break;
-	case 16: to.add("  via_bot_id: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_via_bot_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 11 IN FIELD flags ]"); } break;
-	case 17: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
-	case 18: to.add("  entities: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
+	case 13: to.add("  fwd_from: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_fwd_from) { types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
+	case 14: to.add("  via_bot_id: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_via_bot_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 11 IN FIELD flags ]"); } break;
+	case 15: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_reply_to_msg_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
+	case 16: to.add("  entities: "); ++stages.back(); if (flag & MTPDupdateShortChatMessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -3177,7 +3190,8 @@ void _serialize_config(MTPStringLogger &to, int32 stage, int32 lev, Types &types
 	case 15: to.add("  push_chat_period_ms: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 16: to.add("  push_chat_limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 17: to.add("  saved_gifs_limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 18: to.add("  disabled_features: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 18: to.add("  edit_time_limit: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 19: to.add("  disabled_features: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
 	}
 }
@@ -5093,6 +5107,41 @@ void _serialize_exportedMessageLink(MTPStringLogger &to, int32 stage, int32 lev,
 	}
 }
 
+void _serialize_messageFwdHeader(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ messageFwdHeader");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  from_id: "); ++stages.back(); if (flag & MTPDmessageFwdHeader::flag_from_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	case 2: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  channel_id: "); ++stages.back(); if (flag & MTPDmessageFwdHeader::flag_channel_id) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 4: to.add("  channel_post: "); ++stages.back(); if (flag & MTPDmessageFwdHeader::flag_channel_post) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 2 IN FIELD flags ]"); } break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
+void _serialize_channels_messageEditData(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ channels_messageEditData");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  caption: "); ++stages.back(); if (flag & MTPDchannels_messageEditData::flag_caption) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 2: to.add("  from_id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  edit_by: "); ++stages.back(); if (flag & MTPDchannels_messageEditData::flag_edit_by) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	case 4: to.add("  edit_date: "); ++stages.back(); if (flag & MTPDchannels_messageEditData::flag_edit_date) { types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	case 5: to.add("  users: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_req_pq(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
@@ -6868,6 +6917,24 @@ void _serialize_channels_toggleSignatures(MTPStringLogger &to, int32 stage, int3
 	}
 }
 
+void _serialize_channels_editMessage(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ channels_editMessage");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  no_webpage: "); ++stages.back(); if (flag & MTPchannels_editMessage::flag_no_webpage) { to.add("YES [ BY BIT 1 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 1 IN FIELD flags ]"); } break;
+	case 2: to.add("  channel: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 4: to.add("  message: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 5: to.add("  entities: "); ++stages.back(); if (flag & MTPchannels_editMessage::flag_entities) { types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 3 IN FIELD flags ]"); } break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_messages_getChats(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
@@ -7395,6 +7462,20 @@ void _serialize_channels_exportMessageLink(MTPStringLogger &to, int32 stage, int
 	}
 }
 
+void _serialize_channels_getMessageEditData(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
+	if (stage) {
+		to.add(",\n").addSpaces(lev);
+	} else {
+		to.add("{ channels_getMessageEditData");
+		to.add("\n").addSpaces(lev);
+	}
+	switch (stage) {
+	case 0: to.add("  channel: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
+	}
+}
+
 void _serialize_rpc_result(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 flag) {
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
@@ -7676,6 +7757,7 @@ namespace {
 		_serializers.insert(mtpc_updateSavedGifs, _serialize_updateSavedGifs);
 		_serializers.insert(mtpc_updateBotInlineQuery, _serialize_updateBotInlineQuery);
 		_serializers.insert(mtpc_updateBotInlineSend, _serialize_updateBotInlineSend);
+		_serializers.insert(mtpc_updateEditChannelMessage, _serialize_updateEditChannelMessage);
 		_serializers.insert(mtpc_updates_state, _serialize_updates_state);
 		_serializers.insert(mtpc_updates_differenceEmpty, _serialize_updates_differenceEmpty);
 		_serializers.insert(mtpc_updates_difference, _serialize_updates_difference);
@@ -7854,6 +7936,8 @@ namespace {
 		_serializers.insert(mtpc_botInlineResult, _serialize_botInlineResult);
 		_serializers.insert(mtpc_messages_botResults, _serialize_messages_botResults);
 		_serializers.insert(mtpc_exportedMessageLink, _serialize_exportedMessageLink);
+		_serializers.insert(mtpc_messageFwdHeader, _serialize_messageFwdHeader);
+		_serializers.insert(mtpc_channels_messageEditData, _serialize_channels_messageEditData);
 
 		_serializers.insert(mtpc_req_pq, _serialize_req_pq);
 		_serializers.insert(mtpc_req_DH_params, _serialize_req_DH_params);
@@ -7985,6 +8069,7 @@ namespace {
 		_serializers.insert(mtpc_channels_deleteChannel, _serialize_channels_deleteChannel);
 		_serializers.insert(mtpc_channels_toggleInvites, _serialize_channels_toggleInvites);
 		_serializers.insert(mtpc_channels_toggleSignatures, _serialize_channels_toggleSignatures);
+		_serializers.insert(mtpc_channels_editMessage, _serialize_channels_editMessage);
 		_serializers.insert(mtpc_messages_getChats, _serialize_messages_getChats);
 		_serializers.insert(mtpc_channels_getChannels, _serialize_channels_getChannels);
 		_serializers.insert(mtpc_messages_getFullChat, _serialize_messages_getFullChat);
@@ -8025,6 +8110,7 @@ namespace {
 		_serializers.insert(mtpc_channels_getParticipants, _serialize_channels_getParticipants);
 		_serializers.insert(mtpc_channels_getParticipant, _serialize_channels_getParticipant);
 		_serializers.insert(mtpc_channels_exportMessageLink, _serialize_channels_exportMessageLink);
+		_serializers.insert(mtpc_channels_getMessageEditData, _serialize_channels_getMessageEditData);
 
 		_serializers.insert(mtpc_rpc_result, _serialize_rpc_result);
 		_serializers.insert(mtpc_msg_container, _serialize_msg_container);
diff --git a/Telegram/SourceFiles/mtproto/mtpScheme.h b/Telegram/SourceFiles/mtproto/mtpScheme.h
index 0f15155a1..87a972c7e 100644
--- a/Telegram/SourceFiles/mtproto/mtpScheme.h
+++ b/Telegram/SourceFiles/mtproto/mtpScheme.h
@@ -145,7 +145,7 @@ enum {
 	mtpc_chatPhotoEmpty = 0x37c1011c,
 	mtpc_chatPhoto = 0x6153276a,
 	mtpc_messageEmpty = 0x83e5de54,
-	mtpc_message = 0xef11cef6,
+	mtpc_message = 0xc09be45f,
 	mtpc_messageService = 0xc06b9607,
 	mtpc_messageMediaEmpty = 0x3ded6320,
 	mtpc_messageMediaPhoto = 0x3d8ce53d,
@@ -269,13 +269,14 @@ enum {
 	mtpc_updateSavedGifs = 0x9375341e,
 	mtpc_updateBotInlineQuery = 0xc01eea08,
 	mtpc_updateBotInlineSend = 0xf69e113,
+	mtpc_updateEditChannelMessage = 0x1b3f4df7,
 	mtpc_updates_state = 0xa56c2a3e,
 	mtpc_updates_differenceEmpty = 0x5d75a138,
 	mtpc_updates_difference = 0xf49ca0,
 	mtpc_updates_differenceSlice = 0xa8fb1981,
 	mtpc_updatesTooLong = 0xe317af7e,
-	mtpc_updateShortMessage = 0x3afbe9d1,
-	mtpc_updateShortChatMessage = 0xca2ef195,
+	mtpc_updateShortMessage = 0x914fbf11,
+	mtpc_updateShortChatMessage = 0x16812688,
 	mtpc_updateShort = 0x78d4dec1,
 	mtpc_updatesCombined = 0x725b04c3,
 	mtpc_updates = 0x74ae4240,
@@ -285,7 +286,7 @@ enum {
 	mtpc_photos_photo = 0x20212ca8,
 	mtpc_upload_file = 0x96a18d5,
 	mtpc_dcOption = 0x5d8c6cc,
-	mtpc_config = 0x6bbc5f8,
+	mtpc_config = 0x317ceef4,
 	mtpc_nearestDc = 0x8e1a1775,
 	mtpc_help_appUpdate = 0x8987f311,
 	mtpc_help_noAppUpdate = 0xc45a6536,
@@ -447,6 +448,8 @@ enum {
 	mtpc_botInlineResult = 0x9bebaeb9,
 	mtpc_messages_botResults = 0x1170b0a3,
 	mtpc_exportedMessageLink = 0x1f486803,
+	mtpc_messageFwdHeader = 0xc786ddcb,
+	mtpc_channels_messageEditData = 0xb86fd3cf,
 	mtpc_invokeAfterMsg = 0xcb9f372d,
 	mtpc_invokeAfterMsgs = 0x3dc4b4f0,
 	mtpc_initConnection = 0x69796de9,
@@ -607,7 +610,9 @@ enum {
 	mtpc_channels_deleteChannel = 0xc0111fe3,
 	mtpc_channels_toggleInvites = 0x49609307,
 	mtpc_channels_exportMessageLink = 0xc846d22d,
-	mtpc_channels_toggleSignatures = 0x1f69b606
+	mtpc_channels_toggleSignatures = 0x1f69b606,
+	mtpc_channels_getMessageEditData = 0x27ea3a28,
+	mtpc_channels_editMessage = 0xdcda80ed
 };
 
 // Type forward declarations
@@ -944,6 +949,7 @@ class MTPDupdateNewStickerSet;
 class MTPDupdateStickerSetsOrder;
 class MTPDupdateBotInlineQuery;
 class MTPDupdateBotInlineSend;
+class MTPDupdateEditChannelMessage;
 
 class MTPupdates_state;
 class MTPDupdates_state;
@@ -1233,6 +1239,12 @@ class MTPDmessages_botResults;
 class MTPexportedMessageLink;
 class MTPDexportedMessageLink;
 
+class MTPmessageFwdHeader;
+class MTPDmessageFwdHeader;
+
+class MTPchannels_messageEditData;
+class MTPDchannels_messageEditData;
+
 
 // Boxed types definitions
 typedef MTPBoxed<MTPresPQ> MTPResPQ;
@@ -1395,6 +1407,8 @@ typedef MTPBoxed<MTPbotInlineMessage> MTPBotInlineMessage;
 typedef MTPBoxed<MTPbotInlineResult> MTPBotInlineResult;
 typedef MTPBoxed<MTPmessages_botResults> MTPmessages_BotResults;
 typedef MTPBoxed<MTPexportedMessageLink> MTPExportedMessageLink;
+typedef MTPBoxed<MTPmessageFwdHeader> MTPMessageFwdHeader;
+typedef MTPBoxed<MTPchannels_messageEditData> MTPchannels_MessageEditData;
 
 // Type classes definitions
 
@@ -3518,7 +3532,7 @@ private:
 	explicit MTPmessage(MTPDmessageService *_data);
 
 	friend MTPmessage MTP_messageEmpty(MTPint _id);
-	friend MTPmessage MTP_message(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media, const MTPReplyMarkup &_reply_markup, const MTPVector<MTPMessageEntity> &_entities, MTPint _views);
+	friend MTPmessage MTP_message(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media, const MTPReplyMarkup &_reply_markup, const MTPVector<MTPMessageEntity> &_entities, MTPint _views, MTPint _edit_date);
 	friend MTPmessage MTP_messageService(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPint _date, const MTPMessageAction &_action);
 
 	mtpTypeId _type;
@@ -5432,6 +5446,18 @@ public:
 		return *(const MTPDupdateBotInlineSend*)data;
 	}
 
+	MTPDupdateEditChannelMessage &_updateEditChannelMessage() {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_updateEditChannelMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateEditChannelMessage);
+		split();
+		return *(MTPDupdateEditChannelMessage*)data;
+	}
+	const MTPDupdateEditChannelMessage &c_updateEditChannelMessage() const {
+		if (!data) throw mtpErrorUninitialized();
+		if (_type != mtpc_updateEditChannelMessage) throw mtpErrorWrongTypeId(_type, mtpc_updateEditChannelMessage);
+		return *(const MTPDupdateEditChannelMessage*)data;
+	}
+
 	uint32 innerLength() const;
 	mtpTypeId type() const;
 	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
@@ -5482,6 +5508,7 @@ private:
 	explicit MTPupdate(MTPDupdateStickerSetsOrder *_data);
 	explicit MTPupdate(MTPDupdateBotInlineQuery *_data);
 	explicit MTPupdate(MTPDupdateBotInlineSend *_data);
+	explicit MTPupdate(MTPDupdateEditChannelMessage *_data);
 
 	friend MTPupdate MTP_updateNewMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count);
 	friend MTPupdate MTP_updateMessageID(MTPint _id, const MTPlong &_random_id);
@@ -5526,6 +5553,7 @@ private:
 	friend MTPupdate MTP_updateSavedGifs();
 	friend MTPupdate MTP_updateBotInlineQuery(const MTPlong &_query_id, MTPint _user_id, const MTPstring &_query, const MTPstring &_offset);
 	friend MTPupdate MTP_updateBotInlineSend(MTPint _user_id, const MTPstring &_query, const MTPstring &_id);
+	friend MTPupdate MTP_updateEditChannelMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count);
 
 	mtpTypeId _type;
 };
@@ -5724,8 +5752,8 @@ private:
 	explicit MTPupdates(MTPDupdateShortSentMessage *_data);
 
 	friend MTPupdates MTP_updatesTooLong();
-	friend MTPupdates MTP_updateShortMessage(MTPint _flags, MTPint _id, MTPint _user_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities);
-	friend MTPupdates MTP_updateShortChatMessage(MTPint _flags, MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities);
+	friend MTPupdates MTP_updateShortMessage(MTPint _flags, MTPint _id, MTPint _user_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities);
+	friend MTPupdates MTP_updateShortChatMessage(MTPint _flags, MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities);
 	friend MTPupdates MTP_updateShort(const MTPUpdate &_update, MTPint _date);
 	friend MTPupdates MTP_updatesCombined(const MTPVector<MTPUpdate> &_updates, const MTPVector<MTPUser> &_users, const MTPVector<MTPChat> &_chats, MTPint _date, MTPint _seq_start, MTPint _seq);
 	friend MTPupdates MTP_updates(const MTPVector<MTPUpdate> &_updates, const MTPVector<MTPUser> &_users, const MTPVector<MTPChat> &_chats, MTPint _date, MTPint _seq);
@@ -5906,7 +5934,7 @@ public:
 private:
 	explicit MTPconfig(MTPDconfig *_data);
 
-	friend MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, const MTPVector<MTPDisabledFeature> &_disabled_features);
+	friend MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, const MTPVector<MTPDisabledFeature> &_disabled_features);
 };
 typedef MTPBoxed<MTPconfig> MTPConfig;
 
@@ -8994,6 +9022,68 @@ private:
 };
 typedef MTPBoxed<MTPexportedMessageLink> MTPExportedMessageLink;
 
+class MTPmessageFwdHeader : private mtpDataOwner {
+public:
+	MTPmessageFwdHeader();
+	MTPmessageFwdHeader(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messageFwdHeader) : mtpDataOwner(0) {
+		read(from, end, cons);
+	}
+
+	MTPDmessageFwdHeader &_messageFwdHeader() {
+		if (!data) throw mtpErrorUninitialized();
+		split();
+		return *(MTPDmessageFwdHeader*)data;
+	}
+	const MTPDmessageFwdHeader &c_messageFwdHeader() const {
+		if (!data) throw mtpErrorUninitialized();
+		return *(const MTPDmessageFwdHeader*)data;
+	}
+
+	uint32 innerLength() const;
+	mtpTypeId type() const;
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messageFwdHeader);
+	void write(mtpBuffer &to) const;
+
+	typedef void ResponseType;
+
+private:
+	explicit MTPmessageFwdHeader(MTPDmessageFwdHeader *_data);
+
+	friend MTPmessageFwdHeader MTP_messageFwdHeader(MTPint _flags, MTPint _from_id, MTPint _date, MTPint _channel_id, MTPint _channel_post);
+};
+typedef MTPBoxed<MTPmessageFwdHeader> MTPMessageFwdHeader;
+
+class MTPchannels_messageEditData : private mtpDataOwner {
+public:
+	MTPchannels_messageEditData();
+	MTPchannels_messageEditData(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_messageEditData) : mtpDataOwner(0) {
+		read(from, end, cons);
+	}
+
+	MTPDchannels_messageEditData &_channels_messageEditData() {
+		if (!data) throw mtpErrorUninitialized();
+		split();
+		return *(MTPDchannels_messageEditData*)data;
+	}
+	const MTPDchannels_messageEditData &c_channels_messageEditData() const {
+		if (!data) throw mtpErrorUninitialized();
+		return *(const MTPDchannels_messageEditData*)data;
+	}
+
+	uint32 innerLength() const;
+	mtpTypeId type() const;
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_messageEditData);
+	void write(mtpBuffer &to) const;
+
+	typedef void ResponseType;
+
+private:
+	explicit MTPchannels_messageEditData(MTPDchannels_messageEditData *_data);
+
+	friend MTPchannels_messageEditData MTP_channels_messageEditData(MTPint _flags, MTPint _from_id, MTPint _edit_by, MTPint _edit_date, const MTPVector<MTPUser> &_users);
+};
+typedef MTPBoxed<MTPchannels_messageEditData> MTPchannels_MessageEditData;
+
 // Type constructors with data
 
 class MTPDresPQ : public mtpDataImpl<MTPDresPQ> {
@@ -9713,6 +9803,7 @@ public:
 		flag_bot_nochats = (1 << 16),
 		flag_verified = (1 << 17),
 		flag_restricted = (1 << 18),
+		flag_min = (1 << 20),
 		flag_access_hash = (1 << 0),
 		flag_first_name = (1 << 1),
 		flag_last_name = (1 << 2),
@@ -9734,6 +9825,7 @@ public:
 	bool is_bot_nochats() const { return vflags.v & flag_bot_nochats; }
 	bool is_verified() const { return vflags.v & flag_verified; }
 	bool is_restricted() const { return vflags.v & flag_restricted; }
+	bool is_min() const { return vflags.v & flag_min; }
 	bool has_access_hash() const { return vflags.v & flag_access_hash; }
 	bool has_first_name() const { return vflags.v & flag_first_name; }
 	bool has_last_name() const { return vflags.v & flag_last_name; }
@@ -10038,16 +10130,14 @@ class MTPDmessage : public mtpDataImpl<MTPDmessage> {
 public:
 	MTPDmessage() {
 	}
-	MTPDmessage(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media, const MTPReplyMarkup &_reply_markup, const MTPVector<MTPMessageEntity> &_entities, MTPint _views) : vflags(_flags), vid(_id), vfrom_id(_from_id), vto_id(_to_id), vfwd_from_id(_fwd_from_id), vfwd_date(_fwd_date), vfwd_post(_fwd_post), vvia_bot_id(_via_bot_id), vreply_to_msg_id(_reply_to_msg_id), vdate(_date), vmessage(_message), vmedia(_media), vreply_markup(_reply_markup), ventities(_entities), vviews(_views) {
+	MTPDmessage(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media, const MTPReplyMarkup &_reply_markup, const MTPVector<MTPMessageEntity> &_entities, MTPint _views, MTPint _edit_date) : vflags(_flags), vid(_id), vfrom_id(_from_id), vto_id(_to_id), vfwd_from(_fwd_from), vvia_bot_id(_via_bot_id), vreply_to_msg_id(_reply_to_msg_id), vdate(_date), vmessage(_message), vmedia(_media), vreply_markup(_reply_markup), ventities(_entities), vviews(_views), vedit_date(_edit_date) {
 	}
 
 	MTPint vflags;
 	MTPint vid;
 	MTPint vfrom_id;
 	MTPPeer vto_id;
-	MTPPeer vfwd_from_id;
-	MTPint vfwd_date;
-	MTPint vfwd_post;
+	MTPMessageFwdHeader vfwd_from;
 	MTPint vvia_bot_id;
 	MTPint vreply_to_msg_id;
 	MTPint vdate;
@@ -10056,6 +10146,7 @@ public:
 	MTPReplyMarkup vreply_markup;
 	MTPVector<MTPMessageEntity> ventities;
 	MTPint vviews;
+	MTPint vedit_date;
 
 	enum {
 		flag_unread = (1 << 0),
@@ -10065,15 +10156,14 @@ public:
 		flag_silent = (1 << 13),
 		flag_post = (1 << 14),
 		flag_from_id = (1 << 8),
-		flag_fwd_from_id = (1 << 2),
-		flag_fwd_date = (1 << 2),
-		flag_fwd_post = (1 << 12),
+		flag_fwd_from = (1 << 2),
 		flag_via_bot_id = (1 << 11),
 		flag_reply_to_msg_id = (1 << 3),
 		flag_media = (1 << 9),
 		flag_reply_markup = (1 << 6),
 		flag_entities = (1 << 7),
 		flag_views = (1 << 10),
+		flag_edit_date = (1 << 15),
 	};
 
 	bool is_unread() const { return vflags.v & flag_unread; }
@@ -10083,15 +10173,14 @@ public:
 	bool is_silent() const { return vflags.v & flag_silent; }
 	bool is_post() const { return vflags.v & flag_post; }
 	bool has_from_id() const { return vflags.v & flag_from_id; }
-	bool has_fwd_from_id() const { return vflags.v & flag_fwd_from_id; }
-	bool has_fwd_date() const { return vflags.v & flag_fwd_date; }
-	bool has_fwd_post() const { return vflags.v & flag_fwd_post; }
+	bool has_fwd_from() const { return vflags.v & flag_fwd_from; }
 	bool has_via_bot_id() const { return vflags.v & flag_via_bot_id; }
 	bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
 	bool has_media() const { return vflags.v & flag_media; }
 	bool has_reply_markup() const { return vflags.v & flag_reply_markup; }
 	bool has_entities() const { return vflags.v & flag_entities; }
 	bool has_views() const { return vflags.v & flag_views; }
+	bool has_edit_date() const { return vflags.v & flag_edit_date; }
 };
 
 class MTPDmessageService : public mtpDataImpl<MTPDmessageService> {
@@ -10113,6 +10202,8 @@ public:
 		flag_out = (1 << 1),
 		flag_mentioned = (1 << 4),
 		flag_media_unread = (1 << 5),
+		flag_silent = (1 << 13),
+		flag_post = (1 << 14),
 		flag_from_id = (1 << 8),
 	};
 
@@ -10120,6 +10211,8 @@ public:
 	bool is_out() const { return vflags.v & flag_out; }
 	bool is_mentioned() const { return vflags.v & flag_mentioned; }
 	bool is_media_unread() const { return vflags.v & flag_media_unread; }
+	bool is_silent() const { return vflags.v & flag_silent; }
+	bool is_post() const { return vflags.v & flag_post; }
 	bool has_from_id() const { return vflags.v & flag_from_id; }
 };
 
@@ -11218,6 +11311,18 @@ public:
 	MTPstring vid;
 };
 
+class MTPDupdateEditChannelMessage : public mtpDataImpl<MTPDupdateEditChannelMessage> {
+public:
+	MTPDupdateEditChannelMessage() {
+	}
+	MTPDupdateEditChannelMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) : vmessage(_message), vpts(_pts), vpts_count(_pts_count) {
+	}
+
+	MTPMessage vmessage;
+	MTPint vpts;
+	MTPint vpts_count;
+};
+
 class MTPDupdates_state : public mtpDataImpl<MTPDupdates_state> {
 public:
 	MTPDupdates_state() {
@@ -11277,7 +11382,7 @@ class MTPDupdateShortMessage : public mtpDataImpl<MTPDupdateShortMessage> {
 public:
 	MTPDupdateShortMessage() {
 	}
-	MTPDupdateShortMessage(MTPint _flags, MTPint _id, MTPint _user_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) : vflags(_flags), vid(_id), vuser_id(_user_id), vmessage(_message), vpts(_pts), vpts_count(_pts_count), vdate(_date), vfwd_from_id(_fwd_from_id), vfwd_date(_fwd_date), vfwd_post(_fwd_post), vvia_bot_id(_via_bot_id), vreply_to_msg_id(_reply_to_msg_id), ventities(_entities) {
+	MTPDupdateShortMessage(MTPint _flags, MTPint _id, MTPint _user_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) : vflags(_flags), vid(_id), vuser_id(_user_id), vmessage(_message), vpts(_pts), vpts_count(_pts_count), vdate(_date), vfwd_from(_fwd_from), vvia_bot_id(_via_bot_id), vreply_to_msg_id(_reply_to_msg_id), ventities(_entities) {
 	}
 
 	MTPint vflags;
@@ -11287,9 +11392,7 @@ public:
 	MTPint vpts;
 	MTPint vpts_count;
 	MTPint vdate;
-	MTPPeer vfwd_from_id;
-	MTPint vfwd_date;
-	MTPint vfwd_post;
+	MTPMessageFwdHeader vfwd_from;
 	MTPint vvia_bot_id;
 	MTPint vreply_to_msg_id;
 	MTPVector<MTPMessageEntity> ventities;
@@ -11300,9 +11403,7 @@ public:
 		flag_mentioned = (1 << 4),
 		flag_media_unread = (1 << 5),
 		flag_silent = (1 << 13),
-		flag_fwd_from_id = (1 << 2),
-		flag_fwd_date = (1 << 2),
-		flag_fwd_post = (1 << 12),
+		flag_fwd_from = (1 << 2),
 		flag_via_bot_id = (1 << 11),
 		flag_reply_to_msg_id = (1 << 3),
 		flag_entities = (1 << 7),
@@ -11313,9 +11414,7 @@ public:
 	bool is_mentioned() const { return vflags.v & flag_mentioned; }
 	bool is_media_unread() const { return vflags.v & flag_media_unread; }
 	bool is_silent() const { return vflags.v & flag_silent; }
-	bool has_fwd_from_id() const { return vflags.v & flag_fwd_from_id; }
-	bool has_fwd_date() const { return vflags.v & flag_fwd_date; }
-	bool has_fwd_post() const { return vflags.v & flag_fwd_post; }
+	bool has_fwd_from() const { return vflags.v & flag_fwd_from; }
 	bool has_via_bot_id() const { return vflags.v & flag_via_bot_id; }
 	bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
 	bool has_entities() const { return vflags.v & flag_entities; }
@@ -11325,7 +11424,7 @@ class MTPDupdateShortChatMessage : public mtpDataImpl<MTPDupdateShortChatMessage
 public:
 	MTPDupdateShortChatMessage() {
 	}
-	MTPDupdateShortChatMessage(MTPint _flags, MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) : vflags(_flags), vid(_id), vfrom_id(_from_id), vchat_id(_chat_id), vmessage(_message), vpts(_pts), vpts_count(_pts_count), vdate(_date), vfwd_from_id(_fwd_from_id), vfwd_date(_fwd_date), vfwd_post(_fwd_post), vvia_bot_id(_via_bot_id), vreply_to_msg_id(_reply_to_msg_id), ventities(_entities) {
+	MTPDupdateShortChatMessage(MTPint _flags, MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) : vflags(_flags), vid(_id), vfrom_id(_from_id), vchat_id(_chat_id), vmessage(_message), vpts(_pts), vpts_count(_pts_count), vdate(_date), vfwd_from(_fwd_from), vvia_bot_id(_via_bot_id), vreply_to_msg_id(_reply_to_msg_id), ventities(_entities) {
 	}
 
 	MTPint vflags;
@@ -11336,9 +11435,7 @@ public:
 	MTPint vpts;
 	MTPint vpts_count;
 	MTPint vdate;
-	MTPPeer vfwd_from_id;
-	MTPint vfwd_date;
-	MTPint vfwd_post;
+	MTPMessageFwdHeader vfwd_from;
 	MTPint vvia_bot_id;
 	MTPint vreply_to_msg_id;
 	MTPVector<MTPMessageEntity> ventities;
@@ -11349,9 +11446,7 @@ public:
 		flag_mentioned = (1 << 4),
 		flag_media_unread = (1 << 5),
 		flag_silent = (1 << 13),
-		flag_fwd_from_id = (1 << 2),
-		flag_fwd_date = (1 << 2),
-		flag_fwd_post = (1 << 12),
+		flag_fwd_from = (1 << 2),
 		flag_via_bot_id = (1 << 11),
 		flag_reply_to_msg_id = (1 << 3),
 		flag_entities = (1 << 7),
@@ -11362,9 +11457,7 @@ public:
 	bool is_mentioned() const { return vflags.v & flag_mentioned; }
 	bool is_media_unread() const { return vflags.v & flag_media_unread; }
 	bool is_silent() const { return vflags.v & flag_silent; }
-	bool has_fwd_from_id() const { return vflags.v & flag_fwd_from_id; }
-	bool has_fwd_date() const { return vflags.v & flag_fwd_date; }
-	bool has_fwd_post() const { return vflags.v & flag_fwd_post; }
+	bool has_fwd_from() const { return vflags.v & flag_fwd_from; }
 	bool has_via_bot_id() const { return vflags.v & flag_via_bot_id; }
 	bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
 	bool has_entities() const { return vflags.v & flag_entities; }
@@ -11511,7 +11604,7 @@ class MTPDconfig : public mtpDataImpl<MTPDconfig> {
 public:
 	MTPDconfig() {
 	}
-	MTPDconfig(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) : vdate(_date), vexpires(_expires), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vmegagroup_size_max(_megagroup_size_max), vforwarded_count_max(_forwarded_count_max), vonline_update_period_ms(_online_update_period_ms), voffline_blur_timeout_ms(_offline_blur_timeout_ms), voffline_idle_timeout_ms(_offline_idle_timeout_ms), vonline_cloud_timeout_ms(_online_cloud_timeout_ms), vnotify_cloud_delay_ms(_notify_cloud_delay_ms), vnotify_default_delay_ms(_notify_default_delay_ms), vchat_big_size(_chat_big_size), vpush_chat_period_ms(_push_chat_period_ms), vpush_chat_limit(_push_chat_limit), vsaved_gifs_limit(_saved_gifs_limit), vdisabled_features(_disabled_features) {
+	MTPDconfig(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) : vdate(_date), vexpires(_expires), vtest_mode(_test_mode), vthis_dc(_this_dc), vdc_options(_dc_options), vchat_size_max(_chat_size_max), vmegagroup_size_max(_megagroup_size_max), vforwarded_count_max(_forwarded_count_max), vonline_update_period_ms(_online_update_period_ms), voffline_blur_timeout_ms(_offline_blur_timeout_ms), voffline_idle_timeout_ms(_offline_idle_timeout_ms), vonline_cloud_timeout_ms(_online_cloud_timeout_ms), vnotify_cloud_delay_ms(_notify_cloud_delay_ms), vnotify_default_delay_ms(_notify_default_delay_ms), vchat_big_size(_chat_big_size), vpush_chat_period_ms(_push_chat_period_ms), vpush_chat_limit(_push_chat_limit), vsaved_gifs_limit(_saved_gifs_limit), vedit_time_limit(_edit_time_limit), vdisabled_features(_disabled_features) {
 	}
 
 	MTPint vdate;
@@ -11532,6 +11625,7 @@ public:
 	MTPint vpush_chat_period_ms;
 	MTPint vpush_chat_limit;
 	MTPint vsaved_gifs_limit;
+	MTPint vedit_time_limit;
 	MTPVector<MTPDisabledFeature> vdisabled_features;
 };
 
@@ -13092,6 +13186,54 @@ public:
 	MTPstring vlink;
 };
 
+class MTPDmessageFwdHeader : public mtpDataImpl<MTPDmessageFwdHeader> {
+public:
+	MTPDmessageFwdHeader() {
+	}
+	MTPDmessageFwdHeader(MTPint _flags, MTPint _from_id, MTPint _date, MTPint _channel_id, MTPint _channel_post) : vflags(_flags), vfrom_id(_from_id), vdate(_date), vchannel_id(_channel_id), vchannel_post(_channel_post) {
+	}
+
+	MTPint vflags;
+	MTPint vfrom_id;
+	MTPint vdate;
+	MTPint vchannel_id;
+	MTPint vchannel_post;
+
+	enum {
+		flag_from_id = (1 << 0),
+		flag_channel_id = (1 << 1),
+		flag_channel_post = (1 << 2),
+	};
+
+	bool has_from_id() const { return vflags.v & flag_from_id; }
+	bool has_channel_id() const { return vflags.v & flag_channel_id; }
+	bool has_channel_post() const { return vflags.v & flag_channel_post; }
+};
+
+class MTPDchannels_messageEditData : public mtpDataImpl<MTPDchannels_messageEditData> {
+public:
+	MTPDchannels_messageEditData() {
+	}
+	MTPDchannels_messageEditData(MTPint _flags, MTPint _from_id, MTPint _edit_by, MTPint _edit_date, const MTPVector<MTPUser> &_users) : vflags(_flags), vfrom_id(_from_id), vedit_by(_edit_by), vedit_date(_edit_date), vusers(_users) {
+	}
+
+	MTPint vflags;
+	MTPint vfrom_id;
+	MTPint vedit_by;
+	MTPint vedit_date;
+	MTPVector<MTPUser> vusers;
+
+	enum {
+		flag_caption = (1 << 1),
+		flag_edit_by = (1 << 0),
+		flag_edit_date = (1 << 0),
+	};
+
+	bool is_caption() const { return vflags.v & flag_caption; }
+	bool has_edit_by() const { return vflags.v & flag_edit_by; }
+	bool has_edit_date() const { return vflags.v & flag_edit_date; }
+};
+
 // RPC methods
 
 class MTPreq_pq { // RPC method 'req_pq'
@@ -20294,6 +20436,107 @@ public:
 	}
 };
 
+class MTPchannels_getMessageEditData { // RPC method 'channels.getMessageEditData'
+public:
+	MTPInputChannel vchannel;
+	MTPint vid;
+
+	MTPchannels_getMessageEditData() {
+	}
+	MTPchannels_getMessageEditData(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_getMessageEditData) {
+		read(from, end, cons);
+	}
+	MTPchannels_getMessageEditData(const MTPInputChannel &_channel, MTPint _id) : vchannel(_channel), vid(_id) {
+	}
+
+	uint32 innerLength() const {
+		return vchannel.innerLength() + vid.innerLength();
+	}
+	mtpTypeId type() const {
+		return mtpc_channels_getMessageEditData;
+	}
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_getMessageEditData) {
+		vchannel.read(from, end);
+		vid.read(from, end);
+	}
+	void write(mtpBuffer &to) const {
+		vchannel.write(to);
+		vid.write(to);
+	}
+
+	typedef MTPchannels_MessageEditData ResponseType;
+};
+class MTPchannels_GetMessageEditData : public MTPBoxed<MTPchannels_getMessageEditData> {
+public:
+	MTPchannels_GetMessageEditData() {
+	}
+	MTPchannels_GetMessageEditData(const MTPchannels_getMessageEditData &v) : MTPBoxed<MTPchannels_getMessageEditData>(v) {
+	}
+	MTPchannels_GetMessageEditData(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPchannels_getMessageEditData>(from, end, cons) {
+	}
+	MTPchannels_GetMessageEditData(const MTPInputChannel &_channel, MTPint _id) : MTPBoxed<MTPchannels_getMessageEditData>(MTPchannels_getMessageEditData(_channel, _id)) {
+	}
+};
+
+class MTPchannels_editMessage { // RPC method 'channels.editMessage'
+public:
+	MTPint vflags;
+	MTPInputChannel vchannel;
+	MTPint vid;
+	MTPstring vmessage;
+	MTPVector<MTPMessageEntity> ventities;
+
+	MTPchannels_editMessage() {
+	}
+	MTPchannels_editMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_editMessage) {
+		read(from, end, cons);
+	}
+	MTPchannels_editMessage(MTPint _flags, const MTPInputChannel &_channel, MTPint _id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities) : vflags(_flags), vchannel(_channel), vid(_id), vmessage(_message), ventities(_entities) {
+	}
+
+	enum {
+		flag_no_webpage = (1 << 1),
+		flag_entities = (1 << 3),
+	};
+
+	bool is_no_webpage() const { return vflags.v & flag_no_webpage; }
+	bool has_entities() const { return vflags.v & flag_entities; }
+
+	uint32 innerLength() const {
+		return vflags.innerLength() + vchannel.innerLength() + vid.innerLength() + vmessage.innerLength() + (has_entities() ? ventities.innerLength() : 0);
+	}
+	mtpTypeId type() const {
+		return mtpc_channels_editMessage;
+	}
+	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_channels_editMessage) {
+		vflags.read(from, end);
+		vchannel.read(from, end);
+		vid.read(from, end);
+		vmessage.read(from, end);
+		if (has_entities()) { ventities.read(from, end); } else { ventities = MTPVector<MTPMessageEntity>(); }
+	}
+	void write(mtpBuffer &to) const {
+		vflags.write(to);
+		vchannel.write(to);
+		vid.write(to);
+		vmessage.write(to);
+		if (has_entities()) ventities.write(to);
+	}
+
+	typedef MTPUpdates ResponseType;
+};
+class MTPchannels_EditMessage : public MTPBoxed<MTPchannels_editMessage> {
+public:
+	MTPchannels_EditMessage() {
+	}
+	MTPchannels_EditMessage(const MTPchannels_editMessage &v) : MTPBoxed<MTPchannels_editMessage>(v) {
+	}
+	MTPchannels_EditMessage(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPchannels_editMessage>(from, end, cons) {
+	}
+	MTPchannels_EditMessage(MTPint _flags, const MTPInputChannel &_channel, MTPint _id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities) : MTPBoxed<MTPchannels_editMessage>(MTPchannels_editMessage(_flags, _channel, _id, _message, _entities)) {
+	}
+};
+
 // Inline methods definition
 
 inline MTPresPQ::MTPresPQ() : mtpDataOwner(new MTPDresPQ()) {
@@ -23046,7 +23289,7 @@ inline uint32 MTPmessage::innerLength() const {
 		}
 		case mtpc_message: {
 			const MTPDmessage &v(c_message());
-			return v.vflags.innerLength() + v.vid.innerLength() + (v.has_from_id() ? v.vfrom_id.innerLength() : 0) + v.vto_id.innerLength() + (v.has_fwd_from_id() ? v.vfwd_from_id.innerLength() : 0) + (v.has_fwd_date() ? v.vfwd_date.innerLength() : 0) + (v.has_fwd_post() ? v.vfwd_post.innerLength() : 0) + (v.has_via_bot_id() ? v.vvia_bot_id.innerLength() : 0) + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + v.vdate.innerLength() + v.vmessage.innerLength() + (v.has_media() ? v.vmedia.innerLength() : 0) + (v.has_reply_markup() ? v.vreply_markup.innerLength() : 0) + (v.has_entities() ? v.ventities.innerLength() : 0) + (v.has_views() ? v.vviews.innerLength() : 0);
+			return v.vflags.innerLength() + v.vid.innerLength() + (v.has_from_id() ? v.vfrom_id.innerLength() : 0) + v.vto_id.innerLength() + (v.has_fwd_from() ? v.vfwd_from.innerLength() : 0) + (v.has_via_bot_id() ? v.vvia_bot_id.innerLength() : 0) + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + v.vdate.innerLength() + v.vmessage.innerLength() + (v.has_media() ? v.vmedia.innerLength() : 0) + (v.has_reply_markup() ? v.vreply_markup.innerLength() : 0) + (v.has_entities() ? v.ventities.innerLength() : 0) + (v.has_views() ? v.vviews.innerLength() : 0) + (v.has_edit_date() ? v.vedit_date.innerLength() : 0);
 		}
 		case mtpc_messageService: {
 			const MTPDmessageService &v(c_messageService());
@@ -23074,9 +23317,7 @@ inline void MTPmessage::read(const mtpPrime *&from, const mtpPrime *end, mtpType
 			v.vid.read(from, end);
 			if (v.has_from_id()) { v.vfrom_id.read(from, end); } else { v.vfrom_id = MTPint(); }
 			v.vto_id.read(from, end);
-			if (v.has_fwd_from_id()) { v.vfwd_from_id.read(from, end); } else { v.vfwd_from_id = MTPPeer(); }
-			if (v.has_fwd_date()) { v.vfwd_date.read(from, end); } else { v.vfwd_date = MTPint(); }
-			if (v.has_fwd_post()) { v.vfwd_post.read(from, end); } else { v.vfwd_post = MTPint(); }
+			if (v.has_fwd_from()) { v.vfwd_from.read(from, end); } else { v.vfwd_from = MTPMessageFwdHeader(); }
 			if (v.has_via_bot_id()) { v.vvia_bot_id.read(from, end); } else { v.vvia_bot_id = MTPint(); }
 			if (v.has_reply_to_msg_id()) { v.vreply_to_msg_id.read(from, end); } else { v.vreply_to_msg_id = MTPint(); }
 			v.vdate.read(from, end);
@@ -23085,6 +23326,7 @@ inline void MTPmessage::read(const mtpPrime *&from, const mtpPrime *end, mtpType
 			if (v.has_reply_markup()) { v.vreply_markup.read(from, end); } else { v.vreply_markup = MTPReplyMarkup(); }
 			if (v.has_entities()) { v.ventities.read(from, end); } else { v.ventities = MTPVector<MTPMessageEntity>(); }
 			if (v.has_views()) { v.vviews.read(from, end); } else { v.vviews = MTPint(); }
+			if (v.has_edit_date()) { v.vedit_date.read(from, end); } else { v.vedit_date = MTPint(); }
 		} break;
 		case mtpc_messageService: _type = cons; {
 			if (!data) setData(new MTPDmessageService());
@@ -23111,9 +23353,7 @@ inline void MTPmessage::write(mtpBuffer &to) const {
 			v.vid.write(to);
 			if (v.has_from_id()) v.vfrom_id.write(to);
 			v.vto_id.write(to);
-			if (v.has_fwd_from_id()) v.vfwd_from_id.write(to);
-			if (v.has_fwd_date()) v.vfwd_date.write(to);
-			if (v.has_fwd_post()) v.vfwd_post.write(to);
+			if (v.has_fwd_from()) v.vfwd_from.write(to);
 			if (v.has_via_bot_id()) v.vvia_bot_id.write(to);
 			if (v.has_reply_to_msg_id()) v.vreply_to_msg_id.write(to);
 			v.vdate.write(to);
@@ -23122,6 +23362,7 @@ inline void MTPmessage::write(mtpBuffer &to) const {
 			if (v.has_reply_markup()) v.vreply_markup.write(to);
 			if (v.has_entities()) v.ventities.write(to);
 			if (v.has_views()) v.vviews.write(to);
+			if (v.has_edit_date()) v.vedit_date.write(to);
 		} break;
 		case mtpc_messageService: {
 			const MTPDmessageService &v(c_messageService());
@@ -23151,8 +23392,8 @@ inline MTPmessage::MTPmessage(MTPDmessageService *_data) : mtpDataOwner(_data),
 inline MTPmessage MTP_messageEmpty(MTPint _id) {
 	return MTPmessage(new MTPDmessageEmpty(_id));
 }
-inline MTPmessage MTP_message(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media, const MTPReplyMarkup &_reply_markup, const MTPVector<MTPMessageEntity> &_entities, MTPint _views) {
-	return MTPmessage(new MTPDmessage(_flags, _id, _from_id, _to_id, _fwd_from_id, _fwd_date, _fwd_post, _via_bot_id, _reply_to_msg_id, _date, _message, _media, _reply_markup, _entities, _views));
+inline MTPmessage MTP_message(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, MTPint _date, const MTPstring &_message, const MTPMessageMedia &_media, const MTPReplyMarkup &_reply_markup, const MTPVector<MTPMessageEntity> &_entities, MTPint _views, MTPint _edit_date) {
+	return MTPmessage(new MTPDmessage(_flags, _id, _from_id, _to_id, _fwd_from, _via_bot_id, _reply_to_msg_id, _date, _message, _media, _reply_markup, _entities, _views, _edit_date));
 }
 inline MTPmessage MTP_messageService(MTPint _flags, MTPint _id, MTPint _from_id, const MTPPeer &_to_id, MTPint _date, const MTPMessageAction &_action) {
 	return MTPmessage(new MTPDmessageService(_flags, _id, _from_id, _to_id, _date, _action));
@@ -25184,6 +25425,10 @@ inline uint32 MTPupdate::innerLength() const {
 			const MTPDupdateBotInlineSend &v(c_updateBotInlineSend());
 			return v.vuser_id.innerLength() + v.vquery.innerLength() + v.vid.innerLength();
 		}
+		case mtpc_updateEditChannelMessage: {
+			const MTPDupdateEditChannelMessage &v(c_updateEditChannelMessage());
+			return v.vmessage.innerLength() + v.vpts.innerLength() + v.vpts_count.innerLength();
+		}
 	}
 	return 0;
 }
@@ -25468,6 +25713,13 @@ inline void MTPupdate::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
 			v.vquery.read(from, end);
 			v.vid.read(from, end);
 		} break;
+		case mtpc_updateEditChannelMessage: _type = cons; {
+			if (!data) setData(new MTPDupdateEditChannelMessage());
+			MTPDupdateEditChannelMessage &v(_updateEditChannelMessage());
+			v.vmessage.read(from, end);
+			v.vpts.read(from, end);
+			v.vpts_count.read(from, end);
+		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPupdate");
 	}
 }
@@ -25704,6 +25956,12 @@ inline void MTPupdate::write(mtpBuffer &to) const {
 			v.vquery.write(to);
 			v.vid.write(to);
 		} break;
+		case mtpc_updateEditChannelMessage: {
+			const MTPDupdateEditChannelMessage &v(c_updateEditChannelMessage());
+			v.vmessage.write(to);
+			v.vpts.write(to);
+			v.vpts_count.write(to);
+		} break;
 	}
 }
 inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) {
@@ -25751,6 +26009,7 @@ inline MTPupdate::MTPupdate(mtpTypeId type) : mtpDataOwner(0), _type(type) {
 		case mtpc_updateSavedGifs: break;
 		case mtpc_updateBotInlineQuery: setData(new MTPDupdateBotInlineQuery()); break;
 		case mtpc_updateBotInlineSend: setData(new MTPDupdateBotInlineSend()); break;
+		case mtpc_updateEditChannelMessage: setData(new MTPDupdateEditChannelMessage()); break;
 		default: throw mtpErrorBadTypeId(type, "MTPupdate");
 	}
 }
@@ -25836,6 +26095,8 @@ inline MTPupdate::MTPupdate(MTPDupdateBotInlineQuery *_data) : mtpDataOwner(_dat
 }
 inline MTPupdate::MTPupdate(MTPDupdateBotInlineSend *_data) : mtpDataOwner(_data), _type(mtpc_updateBotInlineSend) {
 }
+inline MTPupdate::MTPupdate(MTPDupdateEditChannelMessage *_data) : mtpDataOwner(_data), _type(mtpc_updateEditChannelMessage) {
+}
 inline MTPupdate MTP_updateNewMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) {
 	return MTPupdate(new MTPDupdateNewMessage(_message, _pts, _pts_count));
 }
@@ -25965,6 +26226,9 @@ inline MTPupdate MTP_updateBotInlineQuery(const MTPlong &_query_id, MTPint _user
 inline MTPupdate MTP_updateBotInlineSend(MTPint _user_id, const MTPstring &_query, const MTPstring &_id) {
 	return MTPupdate(new MTPDupdateBotInlineSend(_user_id, _query, _id));
 }
+inline MTPupdate MTP_updateEditChannelMessage(const MTPMessage &_message, MTPint _pts, MTPint _pts_count) {
+	return MTPupdate(new MTPDupdateEditChannelMessage(_message, _pts, _pts_count));
+}
 
 inline MTPupdates_state::MTPupdates_state() : mtpDataOwner(new MTPDupdates_state()) {
 }
@@ -26109,11 +26373,11 @@ inline uint32 MTPupdates::innerLength() const {
 	switch (_type) {
 		case mtpc_updateShortMessage: {
 			const MTPDupdateShortMessage &v(c_updateShortMessage());
-			return v.vflags.innerLength() + v.vid.innerLength() + v.vuser_id.innerLength() + v.vmessage.innerLength() + v.vpts.innerLength() + v.vpts_count.innerLength() + v.vdate.innerLength() + (v.has_fwd_from_id() ? v.vfwd_from_id.innerLength() : 0) + (v.has_fwd_date() ? v.vfwd_date.innerLength() : 0) + (v.has_fwd_post() ? v.vfwd_post.innerLength() : 0) + (v.has_via_bot_id() ? v.vvia_bot_id.innerLength() : 0) + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + (v.has_entities() ? v.ventities.innerLength() : 0);
+			return v.vflags.innerLength() + v.vid.innerLength() + v.vuser_id.innerLength() + v.vmessage.innerLength() + v.vpts.innerLength() + v.vpts_count.innerLength() + v.vdate.innerLength() + (v.has_fwd_from() ? v.vfwd_from.innerLength() : 0) + (v.has_via_bot_id() ? v.vvia_bot_id.innerLength() : 0) + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + (v.has_entities() ? v.ventities.innerLength() : 0);
 		}
 		case mtpc_updateShortChatMessage: {
 			const MTPDupdateShortChatMessage &v(c_updateShortChatMessage());
-			return v.vflags.innerLength() + v.vid.innerLength() + v.vfrom_id.innerLength() + v.vchat_id.innerLength() + v.vmessage.innerLength() + v.vpts.innerLength() + v.vpts_count.innerLength() + v.vdate.innerLength() + (v.has_fwd_from_id() ? v.vfwd_from_id.innerLength() : 0) + (v.has_fwd_date() ? v.vfwd_date.innerLength() : 0) + (v.has_fwd_post() ? v.vfwd_post.innerLength() : 0) + (v.has_via_bot_id() ? v.vvia_bot_id.innerLength() : 0) + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + (v.has_entities() ? v.ventities.innerLength() : 0);
+			return v.vflags.innerLength() + v.vid.innerLength() + v.vfrom_id.innerLength() + v.vchat_id.innerLength() + v.vmessage.innerLength() + v.vpts.innerLength() + v.vpts_count.innerLength() + v.vdate.innerLength() + (v.has_fwd_from() ? v.vfwd_from.innerLength() : 0) + (v.has_via_bot_id() ? v.vvia_bot_id.innerLength() : 0) + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + (v.has_entities() ? v.ventities.innerLength() : 0);
 		}
 		case mtpc_updateShort: {
 			const MTPDupdateShort &v(c_updateShort());
@@ -26152,9 +26416,7 @@ inline void MTPupdates::read(const mtpPrime *&from, const mtpPrime *end, mtpType
 			v.vpts.read(from, end);
 			v.vpts_count.read(from, end);
 			v.vdate.read(from, end);
-			if (v.has_fwd_from_id()) { v.vfwd_from_id.read(from, end); } else { v.vfwd_from_id = MTPPeer(); }
-			if (v.has_fwd_date()) { v.vfwd_date.read(from, end); } else { v.vfwd_date = MTPint(); }
-			if (v.has_fwd_post()) { v.vfwd_post.read(from, end); } else { v.vfwd_post = MTPint(); }
+			if (v.has_fwd_from()) { v.vfwd_from.read(from, end); } else { v.vfwd_from = MTPMessageFwdHeader(); }
 			if (v.has_via_bot_id()) { v.vvia_bot_id.read(from, end); } else { v.vvia_bot_id = MTPint(); }
 			if (v.has_reply_to_msg_id()) { v.vreply_to_msg_id.read(from, end); } else { v.vreply_to_msg_id = MTPint(); }
 			if (v.has_entities()) { v.ventities.read(from, end); } else { v.ventities = MTPVector<MTPMessageEntity>(); }
@@ -26170,9 +26432,7 @@ inline void MTPupdates::read(const mtpPrime *&from, const mtpPrime *end, mtpType
 			v.vpts.read(from, end);
 			v.vpts_count.read(from, end);
 			v.vdate.read(from, end);
-			if (v.has_fwd_from_id()) { v.vfwd_from_id.read(from, end); } else { v.vfwd_from_id = MTPPeer(); }
-			if (v.has_fwd_date()) { v.vfwd_date.read(from, end); } else { v.vfwd_date = MTPint(); }
-			if (v.has_fwd_post()) { v.vfwd_post.read(from, end); } else { v.vfwd_post = MTPint(); }
+			if (v.has_fwd_from()) { v.vfwd_from.read(from, end); } else { v.vfwd_from = MTPMessageFwdHeader(); }
 			if (v.has_via_bot_id()) { v.vvia_bot_id.read(from, end); } else { v.vvia_bot_id = MTPint(); }
 			if (v.has_reply_to_msg_id()) { v.vreply_to_msg_id.read(from, end); } else { v.vreply_to_msg_id = MTPint(); }
 			if (v.has_entities()) { v.ventities.read(from, end); } else { v.ventities = MTPVector<MTPMessageEntity>(); }
@@ -26227,9 +26487,7 @@ inline void MTPupdates::write(mtpBuffer &to) const {
 			v.vpts.write(to);
 			v.vpts_count.write(to);
 			v.vdate.write(to);
-			if (v.has_fwd_from_id()) v.vfwd_from_id.write(to);
-			if (v.has_fwd_date()) v.vfwd_date.write(to);
-			if (v.has_fwd_post()) v.vfwd_post.write(to);
+			if (v.has_fwd_from()) v.vfwd_from.write(to);
 			if (v.has_via_bot_id()) v.vvia_bot_id.write(to);
 			if (v.has_reply_to_msg_id()) v.vreply_to_msg_id.write(to);
 			if (v.has_entities()) v.ventities.write(to);
@@ -26244,9 +26502,7 @@ inline void MTPupdates::write(mtpBuffer &to) const {
 			v.vpts.write(to);
 			v.vpts_count.write(to);
 			v.vdate.write(to);
-			if (v.has_fwd_from_id()) v.vfwd_from_id.write(to);
-			if (v.has_fwd_date()) v.vfwd_date.write(to);
-			if (v.has_fwd_post()) v.vfwd_post.write(to);
+			if (v.has_fwd_from()) v.vfwd_from.write(to);
 			if (v.has_via_bot_id()) v.vvia_bot_id.write(to);
 			if (v.has_reply_to_msg_id()) v.vreply_to_msg_id.write(to);
 			if (v.has_entities()) v.ventities.write(to);
@@ -26312,11 +26568,11 @@ inline MTPupdates::MTPupdates(MTPDupdateShortSentMessage *_data) : mtpDataOwner(
 inline MTPupdates MTP_updatesTooLong() {
 	return MTPupdates(mtpc_updatesTooLong);
 }
-inline MTPupdates MTP_updateShortMessage(MTPint _flags, MTPint _id, MTPint _user_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) {
-	return MTPupdates(new MTPDupdateShortMessage(_flags, _id, _user_id, _message, _pts, _pts_count, _date, _fwd_from_id, _fwd_date, _fwd_post, _via_bot_id, _reply_to_msg_id, _entities));
+inline MTPupdates MTP_updateShortMessage(MTPint _flags, MTPint _id, MTPint _user_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) {
+	return MTPupdates(new MTPDupdateShortMessage(_flags, _id, _user_id, _message, _pts, _pts_count, _date, _fwd_from, _via_bot_id, _reply_to_msg_id, _entities));
 }
-inline MTPupdates MTP_updateShortChatMessage(MTPint _flags, MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPPeer &_fwd_from_id, MTPint _fwd_date, MTPint _fwd_post, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) {
-	return MTPupdates(new MTPDupdateShortChatMessage(_flags, _id, _from_id, _chat_id, _message, _pts, _pts_count, _date, _fwd_from_id, _fwd_date, _fwd_post, _via_bot_id, _reply_to_msg_id, _entities));
+inline MTPupdates MTP_updateShortChatMessage(MTPint _flags, MTPint _id, MTPint _from_id, MTPint _chat_id, const MTPstring &_message, MTPint _pts, MTPint _pts_count, MTPint _date, const MTPMessageFwdHeader &_fwd_from, MTPint _via_bot_id, MTPint _reply_to_msg_id, const MTPVector<MTPMessageEntity> &_entities) {
+	return MTPupdates(new MTPDupdateShortChatMessage(_flags, _id, _from_id, _chat_id, _message, _pts, _pts_count, _date, _fwd_from, _via_bot_id, _reply_to_msg_id, _entities));
 }
 inline MTPupdates MTP_updateShort(const MTPUpdate &_update, MTPint _date) {
 	return MTPupdates(new MTPDupdateShort(_update, _date));
@@ -26498,7 +26754,7 @@ inline MTPconfig::MTPconfig() : mtpDataOwner(new MTPDconfig()) {
 
 inline uint32 MTPconfig::innerLength() const {
 	const MTPDconfig &v(c_config());
-	return v.vdate.innerLength() + v.vexpires.innerLength() + v.vtest_mode.innerLength() + v.vthis_dc.innerLength() + v.vdc_options.innerLength() + v.vchat_size_max.innerLength() + v.vmegagroup_size_max.innerLength() + v.vforwarded_count_max.innerLength() + v.vonline_update_period_ms.innerLength() + v.voffline_blur_timeout_ms.innerLength() + v.voffline_idle_timeout_ms.innerLength() + v.vonline_cloud_timeout_ms.innerLength() + v.vnotify_cloud_delay_ms.innerLength() + v.vnotify_default_delay_ms.innerLength() + v.vchat_big_size.innerLength() + v.vpush_chat_period_ms.innerLength() + v.vpush_chat_limit.innerLength() + v.vsaved_gifs_limit.innerLength() + v.vdisabled_features.innerLength();
+	return v.vdate.innerLength() + v.vexpires.innerLength() + v.vtest_mode.innerLength() + v.vthis_dc.innerLength() + v.vdc_options.innerLength() + v.vchat_size_max.innerLength() + v.vmegagroup_size_max.innerLength() + v.vforwarded_count_max.innerLength() + v.vonline_update_period_ms.innerLength() + v.voffline_blur_timeout_ms.innerLength() + v.voffline_idle_timeout_ms.innerLength() + v.vonline_cloud_timeout_ms.innerLength() + v.vnotify_cloud_delay_ms.innerLength() + v.vnotify_default_delay_ms.innerLength() + v.vchat_big_size.innerLength() + v.vpush_chat_period_ms.innerLength() + v.vpush_chat_limit.innerLength() + v.vsaved_gifs_limit.innerLength() + v.vedit_time_limit.innerLength() + v.vdisabled_features.innerLength();
 }
 inline mtpTypeId MTPconfig::type() const {
 	return mtpc_config;
@@ -26526,6 +26782,7 @@ inline void MTPconfig::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeI
 	v.vpush_chat_period_ms.read(from, end);
 	v.vpush_chat_limit.read(from, end);
 	v.vsaved_gifs_limit.read(from, end);
+	v.vedit_time_limit.read(from, end);
 	v.vdisabled_features.read(from, end);
 }
 inline void MTPconfig::write(mtpBuffer &to) const {
@@ -26548,12 +26805,13 @@ inline void MTPconfig::write(mtpBuffer &to) const {
 	v.vpush_chat_period_ms.write(to);
 	v.vpush_chat_limit.write(to);
 	v.vsaved_gifs_limit.write(to);
+	v.vedit_time_limit.write(to);
 	v.vdisabled_features.write(to);
 }
 inline MTPconfig::MTPconfig(MTPDconfig *_data) : mtpDataOwner(_data) {
 }
-inline MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) {
-	return MTPconfig(new MTPDconfig(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _disabled_features));
+inline MTPconfig MTP_config(MTPint _date, MTPint _expires, MTPBool _test_mode, MTPint _this_dc, const MTPVector<MTPDcOption> &_dc_options, MTPint _chat_size_max, MTPint _megagroup_size_max, MTPint _forwarded_count_max, MTPint _online_update_period_ms, MTPint _offline_blur_timeout_ms, MTPint _offline_idle_timeout_ms, MTPint _online_cloud_timeout_ms, MTPint _notify_cloud_delay_ms, MTPint _notify_default_delay_ms, MTPint _chat_big_size, MTPint _push_chat_period_ms, MTPint _push_chat_limit, MTPint _saved_gifs_limit, MTPint _edit_time_limit, const MTPVector<MTPDisabledFeature> &_disabled_features) {
+	return MTPconfig(new MTPDconfig(_date, _expires, _test_mode, _this_dc, _dc_options, _chat_size_max, _megagroup_size_max, _forwarded_count_max, _online_update_period_ms, _offline_blur_timeout_ms, _offline_idle_timeout_ms, _online_cloud_timeout_ms, _notify_cloud_delay_ms, _notify_default_delay_ms, _chat_big_size, _push_chat_period_ms, _push_chat_limit, _saved_gifs_limit, _edit_time_limit, _disabled_features));
 }
 
 inline MTPnearestDc::MTPnearestDc() : mtpDataOwner(new MTPDnearestDc()) {
@@ -30611,5 +30869,75 @@ inline MTPexportedMessageLink MTP_exportedMessageLink(const MTPstring &_link) {
 	return MTPexportedMessageLink(new MTPDexportedMessageLink(_link));
 }
 
+inline MTPmessageFwdHeader::MTPmessageFwdHeader() : mtpDataOwner(new MTPDmessageFwdHeader()) {
+}
+
+inline uint32 MTPmessageFwdHeader::innerLength() const {
+	const MTPDmessageFwdHeader &v(c_messageFwdHeader());
+	return v.vflags.innerLength() + (v.has_from_id() ? v.vfrom_id.innerLength() : 0) + v.vdate.innerLength() + (v.has_channel_id() ? v.vchannel_id.innerLength() : 0) + (v.has_channel_post() ? v.vchannel_post.innerLength() : 0);
+}
+inline mtpTypeId MTPmessageFwdHeader::type() const {
+	return mtpc_messageFwdHeader;
+}
+inline void MTPmessageFwdHeader::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
+	if (cons != mtpc_messageFwdHeader) throw mtpErrorUnexpected(cons, "MTPmessageFwdHeader");
+
+	if (!data) setData(new MTPDmessageFwdHeader());
+	MTPDmessageFwdHeader &v(_messageFwdHeader());
+	v.vflags.read(from, end);
+	if (v.has_from_id()) { v.vfrom_id.read(from, end); } else { v.vfrom_id = MTPint(); }
+	v.vdate.read(from, end);
+	if (v.has_channel_id()) { v.vchannel_id.read(from, end); } else { v.vchannel_id = MTPint(); }
+	if (v.has_channel_post()) { v.vchannel_post.read(from, end); } else { v.vchannel_post = MTPint(); }
+}
+inline void MTPmessageFwdHeader::write(mtpBuffer &to) const {
+	const MTPDmessageFwdHeader &v(c_messageFwdHeader());
+	v.vflags.write(to);
+	if (v.has_from_id()) v.vfrom_id.write(to);
+	v.vdate.write(to);
+	if (v.has_channel_id()) v.vchannel_id.write(to);
+	if (v.has_channel_post()) v.vchannel_post.write(to);
+}
+inline MTPmessageFwdHeader::MTPmessageFwdHeader(MTPDmessageFwdHeader *_data) : mtpDataOwner(_data) {
+}
+inline MTPmessageFwdHeader MTP_messageFwdHeader(MTPint _flags, MTPint _from_id, MTPint _date, MTPint _channel_id, MTPint _channel_post) {
+	return MTPmessageFwdHeader(new MTPDmessageFwdHeader(_flags, _from_id, _date, _channel_id, _channel_post));
+}
+
+inline MTPchannels_messageEditData::MTPchannels_messageEditData() : mtpDataOwner(new MTPDchannels_messageEditData()) {
+}
+
+inline uint32 MTPchannels_messageEditData::innerLength() const {
+	const MTPDchannels_messageEditData &v(c_channels_messageEditData());
+	return v.vflags.innerLength() + v.vfrom_id.innerLength() + (v.has_edit_by() ? v.vedit_by.innerLength() : 0) + (v.has_edit_date() ? v.vedit_date.innerLength() : 0) + v.vusers.innerLength();
+}
+inline mtpTypeId MTPchannels_messageEditData::type() const {
+	return mtpc_channels_messageEditData;
+}
+inline void MTPchannels_messageEditData::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
+	if (cons != mtpc_channels_messageEditData) throw mtpErrorUnexpected(cons, "MTPchannels_messageEditData");
+
+	if (!data) setData(new MTPDchannels_messageEditData());
+	MTPDchannels_messageEditData &v(_channels_messageEditData());
+	v.vflags.read(from, end);
+	v.vfrom_id.read(from, end);
+	if (v.has_edit_by()) { v.vedit_by.read(from, end); } else { v.vedit_by = MTPint(); }
+	if (v.has_edit_date()) { v.vedit_date.read(from, end); } else { v.vedit_date = MTPint(); }
+	v.vusers.read(from, end);
+}
+inline void MTPchannels_messageEditData::write(mtpBuffer &to) const {
+	const MTPDchannels_messageEditData &v(c_channels_messageEditData());
+	v.vflags.write(to);
+	v.vfrom_id.write(to);
+	if (v.has_edit_by()) v.vedit_by.write(to);
+	if (v.has_edit_date()) v.vedit_date.write(to);
+	v.vusers.write(to);
+}
+inline MTPchannels_messageEditData::MTPchannels_messageEditData(MTPDchannels_messageEditData *_data) : mtpDataOwner(_data) {
+}
+inline MTPchannels_messageEditData MTP_channels_messageEditData(MTPint _flags, MTPint _from_id, MTPint _edit_by, MTPint _edit_date, const MTPVector<MTPUser> &_users) {
+	return MTPchannels_messageEditData(new MTPDchannels_messageEditData(_flags, _from_id, _edit_by, _edit_date, _users));
+}
+
 // Human-readable text serialization
 void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpPrime *end, mtpPrime cons, uint32 level, mtpPrime vcons);
diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl
index 8c3a8a5dd..94df0ec3e 100644
--- a/Telegram/SourceFiles/mtproto/scheme.tl
+++ b/Telegram/SourceFiles/mtproto/scheme.tl
@@ -194,7 +194,7 @@ fileLocationUnavailable#7c596b46 volume_id:long local_id:int secret:long = FileL
 fileLocation#53d69076 dc_id:int volume_id:long local_id:int secret:long = FileLocation;
 
 userEmpty#200250ba id:int = User;
-user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User;
+user#d10d979a flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true id:int access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?string bot_inline_placeholder:flags.19?string = User;
 
 userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto;
 userProfilePhoto#d559d8c8 photo_id:long photo_small:FileLocation photo_big:FileLocation = UserProfilePhoto;
@@ -226,8 +226,8 @@ chatPhotoEmpty#37c1011c = ChatPhoto;
 chatPhoto#6153276a photo_small:FileLocation photo_big:FileLocation = ChatPhoto;
 
 messageEmpty#83e5de54 id:int = Message;
-message#ef11cef6 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from_id:flags.2?Peer fwd_date:flags.2?int fwd_post:flags.12?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int = Message;
-messageService#c06b9607 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message;
+message#c09be45f flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector<MessageEntity> views:flags.10?int edit_date:flags.15?int = Message;
+messageService#c06b9607 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true id:int from_id:flags.8?int to_id:Peer date:int action:MessageAction = Message;
 
 messageMediaEmpty#3ded6320 = MessageMedia;
 messageMediaPhoto#3d8ce53d photo:Photo caption:string = MessageMedia;
@@ -383,6 +383,7 @@ updateStickerSets#43ae3dec = Update;
 updateSavedGifs#9375341e = Update;
 updateBotInlineQuery#c01eea08 query_id:long user_id:int query:string offset:string = Update;
 updateBotInlineSend#f69e113 user_id:int query:string id:string = Update;
+updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update;
 
 updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
 
@@ -391,8 +392,8 @@ updates.difference#f49ca0 new_messages:Vector<Message> new_encrypted_messages:Ve
 updates.differenceSlice#a8fb1981 new_messages:Vector<Message> new_encrypted_messages:Vector<EncryptedMessage> other_updates:Vector<Update> chats:Vector<Chat> users:Vector<User> intermediate_state:updates.State = updates.Difference;
 
 updatesTooLong#e317af7e = Updates;
-updateShortMessage#3afbe9d1 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int fwd_post:flags.12?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
-updateShortChatMessage#ca2ef195 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from_id:flags.2?Peer fwd_date:flags.2?int fwd_post:flags.12?int via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
+updateShortMessage#914fbf11 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
+updateShortChatMessage#16812688 flags:# unread:flags.0?true out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:int chat_id:int message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?int reply_to_msg_id:flags.3?int entities:flags.7?Vector<MessageEntity> = Updates;
 updateShort#78d4dec1 update:Update date:int = Updates;
 updatesCombined#725b04c3 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq_start:int seq:int = Updates;
 updates#74ae4240 updates:Vector<Update> users:Vector<User> chats:Vector<Chat> date:int seq:int = Updates;
@@ -407,7 +408,7 @@ upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File;
 
 dcOption#5d8c6cc flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true id:int ip_address:string port:int = DcOption;
 
-config#6bbc5f8 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int disabled_features:Vector<DisabledFeature> = Config;
+config#317ceef4 date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int disabled_features:Vector<DisabledFeature> = Config;
 
 nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
 
@@ -641,6 +642,10 @@ messages.botResults#1170b0a3 flags:# gallery:flags.0?true query_id:long next_off
 
 exportedMessageLink#1f486803 link:string = ExportedMessageLink;
 
+messageFwdHeader#c786ddcb flags:# from_id:flags.0?int date:int channel_id:flags.1?int channel_post:flags.2?int = MessageFwdHeader;
+
+channels.messageEditData#b86fd3cf flags:# caption:flags.1?true from_id:int edit_by:flags.0?int edit_date:flags.0?int users:Vector<User> = channels.MessageEditData;
+
 ---functions---
 
 invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -814,3 +819,5 @@ channels.deleteChannel#c0111fe3 channel:InputChannel = Updates;
 channels.toggleInvites#49609307 channel:InputChannel enabled:Bool = Updates;
 channels.exportMessageLink#c846d22d channel:InputChannel id:int = ExportedMessageLink;
 channels.toggleSignatures#1f69b606 channel:InputChannel enabled:Bool = Updates;
+channels.getMessageEditData#27ea3a28 channel:InputChannel id:int = channels.MessageEditData;
+channels.editMessage#dcda80ed flags:# no_webpage:flags.1?true channel:InputChannel id:int message:string entities:flags.3?Vector<MessageEntity> = Updates;
diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp
index 665ed2b66..19f23036c 100644
--- a/Telegram/SourceFiles/profilewidget.cpp
+++ b/Telegram/SourceFiles/profilewidget.cpp
@@ -72,7 +72,7 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, PeerData
 , _photoOver(false)
 
 // migrate to megagroup
-, _showMigrate(_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= cMaxGroupCount())
+, _showMigrate(_peerChat && _amCreator && !_peerChat->isMigrated() && _peerChat->count >= Global::ChatSizeMax())
 , _forceShowMigrate(false)
 , _aboutMigrate(st::normalFont, lang(lng_profile_migrate_about), _defaultOptions, st::wndMinWidth - st::profilePadding.left() - st::profilePadding.right())
 , _migrate(this, lang(lng_profile_migrate_button), st::btnMigrateToMega)
@@ -537,7 +537,7 @@ void ProfileInner::onFullPeerUpdated(PeerData *peer) {
 		}
 	} else if (_peerChat) {
 		updateInvitationLink();
-		_showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && (_forceShowMigrate || _peerChat->count >= cMaxGroupCount()));
+		_showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && (_forceShowMigrate || _peerChat->count >= Global::ChatSizeMax()));
 		showAll();
 		resizeEvent(0);
 		_admins.setText(lng_channel_admins_link(lt_count, _peerChat->adminsEnabled() ? (_peerChat->admins.size() + 1) : 0));
@@ -597,7 +597,7 @@ void ProfileInner::peerUpdated(PeerData *data) {
 		} else if (_peerChat) {
 			if (_peerChat->photoId && _peerChat->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChat->photoId);
 			_admins.setText(lng_channel_admins_link(lt_count, _peerChat->adminsEnabled() ? (_peerChat->admins.size() + 1) : 0));
-			_showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && (_forceShowMigrate || _peerChat->count >= cMaxGroupCount()));
+			_showMigrate = (_peerChat && _amCreator && !_peerChat->isMigrated() && (_forceShowMigrate || _peerChat->count >= Global::ChatSizeMax()));
 			if (App::main()) App::main()->topBar()->showAll();
 		} else if (_peerChannel) {
 			if (_peerChannel->photoId && _peerChannel->photoId != UnknownPeerPhotoId) photo = App::photo(_peerChannel->photoId);
@@ -838,13 +838,13 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
 	if (_showMigrate) {
 		p.setFont(st::profileHeaderFont->f);
 		p.setPen(st::profileHeaderColor->p);
-		p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lng_profile_migrate_reached(lt_count, cMaxGroupCount()));
+		p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lng_profile_migrate_reached(lt_count, Global::ChatSizeMax()));
 		top += st::profileHeaderSkip;
 
 		_aboutMigrate.draw(p, _left, top, _width); top += _aboutMigrate.countHeight(_width) + st::setLittleSkip;
 		p.setFont(st::normalFont);
 		p.setPen(st::black);
-		p.drawText(_left, top + st::normalFont->ascent, lng_profile_migrate_feature1(lt_count, cMaxMegaGroupCount())); top += st::normalFont->height + st::setLittleSkip;
+		p.drawText(_left, top + st::normalFont->ascent, lng_profile_migrate_feature1(lt_count, Global::MegagroupSizeMax())); top += st::normalFont->height + st::setLittleSkip;
 		p.drawText(_left, top + st::normalFont->ascent, lang(lng_profile_migrate_feature2)); top += st::normalFont->height + st::setLittleSkip;
 		p.drawText(_left, top + st::normalFont->ascent, lang(lng_profile_migrate_feature3)); top += st::normalFont->height + st::setLittleSkip;
 		p.drawText(_left, top + st::normalFont->ascent, lang(lng_profile_migrate_feature4)); top += st::normalFont->height + st::setSectionSkip;
@@ -1296,7 +1296,7 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
 	top += st::profileButtonTop;
 
 	_uploadPhoto.setGeometry(_left, top, btnWidth, _uploadPhoto.height());
-	if (_peerChannel && _peerChannel->count < cMaxMegaGroupCount() && _peerChannel->isMegagroup() && !_amCreator && !_peerChannel->amEditor() && _peerChannel->canAddParticipants()) {
+	if (_peerChannel && _peerChannel->count < Global::MegagroupSizeMax() && _peerChannel->isMegagroup() && !_amCreator && !_peerChannel->amEditor() && _peerChannel->canAddParticipants()) {
 		_addParticipant.setGeometry(_left, top, btnWidth, _addParticipant.height());
 	} else {
 		_addParticipant.setGeometry(_left + _width - btnWidth, top, btnWidth, _addParticipant.height());
@@ -1592,7 +1592,7 @@ void ProfileInner::showAll() {
 				_createInvitationLink.hide();
 				_invitationLink.hide();
 			}
-			if (_peerChat->count < cMaxGroupCount() && !_showMigrate) {
+			if (_peerChat->count < Global::ChatSizeMax() && !_showMigrate) {
 				_addParticipant.show();
 			} else {
 				_addParticipant.hide();
@@ -1640,7 +1640,7 @@ void ProfileInner::showAll() {
 				_invitationLink.hide();
 			}
 		}
-		if (_peerChannel->count < cMaxMegaGroupCount() && _peerChannel->isMegagroup() && _peerChannel->canAddParticipants()) {
+		if (_peerChannel->count < Global::MegagroupSizeMax() && _peerChannel->isMegagroup() && _peerChannel->canAddParticipants()) {
 			_addParticipant.show();
 		} else {
 			_addParticipant.hide();
diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp
index bd6578eb7..c98fe4a55 100644
--- a/Telegram/SourceFiles/settings.cpp
+++ b/Telegram/SourceFiles/settings.cpp
@@ -74,8 +74,6 @@ bool gRestartingUpdate = false, gRestarting = false, gRestartingToSettings = fal
 int32 gLastUpdateCheck = 0;
 bool gNoStartUpdate = false;
 bool gStartToSettings = false;
-int32 gMaxGroupCount = 200;
-int32 gMaxMegaGroupCount = 500;
 DBIDefaultAttach gDefaultAttach = dbidaDocument;
 bool gReplaceEmojis = true;
 bool gAskDownloadPath = false;
@@ -119,7 +117,6 @@ uint64 gLastStickersUpdate = 0;
 SavedGifs gSavedGifs;
 uint64 gLastSavedGifsUpdate = 0;
 bool gShowingSavedGifs = false;
-int32 gSavedGifsLimit = 100;
 
 RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags;
 
@@ -155,14 +152,6 @@ bool gIsElCapitan = false;
 bool gContactsReceived = false;
 bool gDialogsReceived = false;
 
-int gOnlineUpdatePeriod = 120000;
-int gOfflineBlurTimeout = 5000;
-int gOfflineIdleTimeout = 30000;
-int gOnlineFocusTimeout = 1000;
-int gOnlineCloudTimeout = 300000;
-int gNotifyCloudDelay = 30000;
-int gNotifyDefaultDelay = 1500;
-
 int gOtherOnline = 0;
 
 float64 gSongVolume = 0.9;
@@ -185,7 +174,7 @@ void settingsParseArgs(int argc, char *argv[]) {
 		gPlatform = dbipMacOld;
 	}
 #endif
-	
+
 	switch (cPlatform()) {
 	case dbipWindows:
 		gUpdateURL = QUrl(qsl("http://tdesktop.com/win/tupdates/current"));
diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h
index dc4adaaa6..b57a6b4f1 100644
--- a/Telegram/SourceFiles/settings.h
+++ b/Telegram/SourceFiles/settings.h
@@ -140,8 +140,6 @@ DeclareSetting(bool, WriteProtected);
 DeclareSetting(int32, LastUpdateCheck);
 DeclareSetting(bool, NoStartUpdate);
 DeclareSetting(bool, StartToSettings);
-DeclareSetting(int32, MaxGroupCount);
-DeclareSetting(int32, MaxMegaGroupCount);
 DeclareSetting(bool, ReplaceEmojis);
 DeclareReadSetting(bool, ManyInstance);
 DeclareSetting(bool, AskDownloadPath);
@@ -240,7 +238,6 @@ typedef QVector<DocumentData*> SavedGifs;
 DeclareRefSetting(SavedGifs, SavedGifs);
 DeclareSetting(uint64, LastSavedGifsUpdate);
 DeclareSetting(bool, ShowingSavedGifs);
-DeclareSetting(int32, SavedGifsLimit);
 
 typedef QList<QPair<QString, ushort> > RecentHashtagPack;
 DeclareRefSetting(RecentHashtagPack, RecentWriteHashtags);
@@ -324,14 +321,6 @@ DeclareReadSetting(QUrl, UpdateURL);
 DeclareSetting(bool, ContactsReceived);
 DeclareSetting(bool, DialogsReceived);
 
-DeclareSetting(int, OnlineUpdatePeriod);
-DeclareSetting(int, OfflineBlurTimeout);
-DeclareSetting(int, OfflineIdleTimeout);
-DeclareSetting(int, OnlineFocusTimeout);
-DeclareSetting(int, OnlineCloudTimeout);
-DeclareSetting(int, NotifyCloudDelay);
-DeclareSetting(int, NotifyDefaultDelay);
-
 DeclareSetting(int, OtherOnline);
 
 DeclareSetting(float64, SongVolume);
diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp
index 1c05b266a..0ce99caad 100644
--- a/Telegram/SourceFiles/structs.cpp
+++ b/Telegram/SourceFiles/structs.cpp
@@ -98,15 +98,15 @@ ImagePtr channelDefPhoto(int32 index) {
 NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats;
 NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings;
 
-PeerData::PeerData(const PeerId &id) : id(id), lnk(new PeerLink(this))
+PeerData::PeerData(const PeerId &id) : id(id)
+, lnk(new PeerLink(this))
 , loaded(false)
 , colorIndex(peerColorIndex(id))
 , color(peerColor(colorIndex))
 , photo((isChat() || isMegagroup()) ? chatDefPhoto(colorIndex) : (isChannel() ? channelDefPhoto(colorIndex) : userDefPhoto(colorIndex)))
 , photoId(UnknownPeerPhotoId)
 , nameVersion(0)
-, notify(UnknownNotifySettings)
-{
+, notify(UnknownNotifySettings) {
 	if (!peerIsUser(id) && !peerIsChannel(id)) updateName(QString(), QString(), QString());
 }
 
diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h
index b93bf822d..2e983d570 100644
--- a/Telegram/SourceFiles/types.h
+++ b/Telegram/SourceFiles/types.h
@@ -305,7 +305,7 @@ enum DataBlockId {
 	dbiKey                  = 0x00,
 	dbiUser                 = 0x01,
 	dbiDcOptionOld          = 0x02,
-	dbiMaxGroupCount        = 0x03,
+	dbiChatSizeMax          = 0x03,
 	dbiMutePeer             = 0x04,
 	dbiSendKey              = 0x05,
 	dbiAutoStart            = 0x06,
@@ -346,7 +346,7 @@ enum DataBlockId {
 	dbiSongVolume           = 0x29,
 	dbiWindowsNotifications = 0x30,
 	dbiIncludeMuted         = 0x31,
-	dbiMaxMegaGroupCount    = 0x32,
+	dbiMegagroupSizeMax     = 0x32,
 	dbiDownloadPath         = 0x33,
 	dbiAutoDownload         = 0x34,
 	dbiSavedGifsLimit       = 0x35,
diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp
index 83679b68d..24c24101f 100644
--- a/Telegram/SourceFiles/window.cpp
+++ b/Telegram/SourceFiles/window.cpp
@@ -435,7 +435,7 @@ void Window::onInactiveTimer() {
 void Window::stateChanged(Qt::WindowState state) {
 	psUserActionDone();
 
-	updateIsActive((state == Qt::WindowMinimized) ? cOfflineBlurTimeout() : cOnlineFocusTimeout());
+	updateIsActive((state == Qt::WindowMinimized) ? Global::OfflineBlurTimeout() : Global::OnlineFocusTimeout());
 
 	psUpdateSysMenu(state);
 	if (state == Qt::WindowMinimized && cWorkMode() == dbiwmTrayOnly) {
@@ -1075,7 +1075,7 @@ bool Window::minimizeToTray() {
 		cSetSeenTrayTooltip(true);
 		Local::writeSettings();
 	}
-	updateIsActive(cOfflineBlurTimeout());
+	updateIsActive(Global::OfflineBlurTimeout());
 	updateTrayMenu();
 	updateGlobalMenu();
 	return true;
@@ -1157,7 +1157,7 @@ void Window::activate() {
 	setVisible(true);
 	psActivateProcess();
 	activateWindow();
-	updateIsActive(cOnlineFocusTimeout());
+	updateIsActive(Global::OnlineFocusTimeout());
 	if (wasHidden) {
 		if (main) {
 			main->windowShown();
@@ -1382,12 +1382,12 @@ void Window::notifySchedule(History *history, HistoryItem *item) {
 	HistoryForwarded *fwd = item->toHistoryForwarded();
 	int delay = fwd ? 500 : 100, t = unixtime();
 	uint64 ms = getms(true);
-	bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + cOnlineCloudTimeout() > t * uint64(1000));
+	bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + Global::OnlineCloudTimeout() > t * uint64(1000));
 	bool otherLaterThanMe = (cOtherOnline() * uint64(1000) + (ms - main->lastSetOnline()) > t * uint64(1000));
 	if (!isOnline && otherNotOld && otherLaterThanMe) {
-		delay = cNotifyCloudDelay();
+		delay = Global::NotifyCloudDelay();
 	} else if (cOtherOnline() >= t) {
-		delay = cNotifyDefaultDelay();
+		delay = Global::NotifyDefaultDelay();
 	}
 
 	uint64 when = getms(true) + delay;