diff --git a/Telegram/Resources/basic.style b/Telegram/Resources/basic.style
index 44d123c2c4..318c94387d 100644
--- a/Telegram/Resources/basic.style
+++ b/Telegram/Resources/basic.style
@@ -949,7 +949,7 @@ dlgDateColor: #a8a8a8;
 dlgDateSkip: 5px;
 
 dlgUnreadColor: #FFF;
-dlgUnreadBG: #6fc766;
+dlgUnreadBG: #009ce6;//#6fc766;
 dlgUnreadMutedBG: #bbb;
 dlgUnreadFont: font(12px bold);
 dlgUnreadHeight: 19px;
diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 1bb38049c7..31c2cf8b70 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -622,7 +622,7 @@ namespace {
 
 				ChannelData *cdata = data->asChannel();
 				if (minimal) {
-					int32 mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy;
+					auto mask = MTPDchannel::Flag::f_broadcast | MTPDchannel::Flag::f_verified | MTPDchannel::Flag::f_megagroup | MTPDchannel::Flag::f_democracy;
 					cdata->flags = (cdata->flags & ~mask) | (d.vflags.v & mask);
 				} else {
 					cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
@@ -655,6 +655,9 @@ namespace {
 				ChannelData *cdata = data->asChannel();
 				cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash);
 
+				auto mask = mtpCastFlags(MTPDchannelForbidden::Flag::f_broadcast | MTPDchannelForbidden::Flag::f_megagroup);
+				cdata->flags = (cdata->flags & ~mask) | (mtpCastFlags(d.vflags) & mask);
+
 				cdata->setName(qs(d.vtitle), QString());
 
 				cdata->access = d.vaccess_hash.v;
@@ -662,6 +665,7 @@ namespace {
 				cdata->date = 0;
 				cdata->count = 0;
 				cdata->isForbidden = true;
+				cdata->flagsUpdated();
 			} break;
 			}
 			if (!data) continue;
diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
index e05231b279..3358bcd730 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
+++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp
@@ -134,6 +134,8 @@ QImage colorizeCircleHalf(int size, int half, int xoffset, style::color color) {
 	return result;
 }
 
+} // namepsace
+
 void paintUnreadBadge(Painter &p, const QRect &rect, bool active, bool muted) {
 	int index = (active ? 0x01 : 0x00) | (muted ? 0x02 : 0x00);
 	int size = rect.height(), sizehalf = size / 2;
@@ -155,16 +157,21 @@ void paintUnreadBadge(Painter &p, const QRect &rect, bool active, bool muted) {
 	p.drawPixmap(rect.x() + sizehalf + bar, rect.y(), unreadBadgeStyle->right[index]);
 }
 
-void paintUnreadCount(Painter &p, const QString &text, int top, int w, bool active, bool muted, int *outAvailableWidth) {
+void paintUnreadCount(Painter &p, const QString &text, int x, int y, style::align align, bool active, bool muted, int *outUnreadWidth) {
 	int unreadWidth = st::dlgUnreadFont->width(text);
 	int unreadRectWidth = unreadWidth + 2 * st::dlgUnreadPaddingHor;
 	int unreadRectHeight = st::dlgUnreadHeight;
 	accumulate_max(unreadRectWidth, unreadRectHeight);
 
-	int unreadRectLeft = w - st::dlgPaddingHor - unreadRectWidth;
-	int unreadRectTop =top;
-	if (outAvailableWidth) {
-		*outAvailableWidth -= unreadRectWidth + st::dlgUnreadPaddingHor;
+	int unreadRectLeft = x;
+	if ((align & Qt::AlignHorizontal_Mask) & style::al_center) {
+		unreadRectLeft = (x - unreadRectWidth) / 2;
+	} else if ((align & Qt::AlignHorizontal_Mask) & style::al_right) {
+		unreadRectLeft = x - unreadRectWidth;
+	}
+	int unreadRectTop = y;
+	if (outUnreadWidth) {
+		*outUnreadWidth = unreadRectWidth;
 	}
 
 	paintUnreadBadge(p, QRect(unreadRectLeft, unreadRectTop, unreadRectWidth, unreadRectHeight), active, muted);
@@ -174,8 +181,6 @@ void paintUnreadCount(Painter &p, const QString &text, int top, int w, bool acti
 	p.drawText(unreadRectLeft + (unreadRectWidth - unreadWidth) / 2, unreadRectTop + st::dlgUnreadTop + st::dlgUnreadFont->ascent, text);
 }
 
-} // namepsace
-
 void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool selected, bool onlyBackground) {
 	auto history = row->history();
 	auto item = history->lastMsg;
@@ -189,8 +194,11 @@ void RowPainter::paint(Painter &p, const Row *row, int w, bool active, bool sele
 		int availableWidth = namewidth;
 		int texttop = st::dlgPaddingVer + st::dlgFont->height + st::dlgSep;
 		if (unread) {
+			int unreadRight = w - st::dlgPaddingHor;
 			int unreadTop = texttop + st::dlgHistFont->ascent - st::dlgUnreadFont->ascent - st::dlgUnreadTop;
-			paintUnreadCount(p, QString::number(unread), unreadTop, w, active, history->mute(), &availableWidth);
+			int unreadWidth = 0;
+			paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, style::al_right, active, history->mute(), &unreadWidth);
+			availableWidth -= unreadWidth + st::dlgUnreadPaddingHor;
 		}
 		if (history->typing.isEmpty() && history->sendActions.isEmpty()) {
 			item->drawInDialog(p, QRect(nameleft, texttop, availableWidth, st::dlgFont->height), active, history->textCachedFor, history->lastItemTextCache);
@@ -227,7 +235,8 @@ void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool o
 
 	if (mutedHidden) {
 		if (int32 unread = App::histories().unreadMutedCount()) {
-			paintUnreadCount(p, QString::number(unread), unreadTop, w, false, true, nullptr);
+			int unreadRight = w - st::dlgPaddingHor;
+			paintUnreadCount(p, QString::number(unread), unreadRight, unreadTop, style::al_right, false, true, nullptr);
 		}
 	}
 }
diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.h b/Telegram/SourceFiles/dialogs/dialogs_layout.h
index 1c0de56a15..3f3cdd8683 100644
--- a/Telegram/SourceFiles/dialogs/dialogs_layout.h
+++ b/Telegram/SourceFiles/dialogs/dialogs_layout.h
@@ -35,6 +35,9 @@ public:
 
 void paintImportantSwitch(Painter &p, Mode current, int w, bool selected, bool onlyBackground);
 
+void paintUnreadCount(Painter &p, const QString &text, int x, int y, style::align align, bool active, bool muted, int *outUnreadWidth);
+void paintUnreadBadge(Painter &p, const QRect &rect, bool active, bool muted);
+
 // This will be moved somewhere outside as soon as anyone starts using that.
 class StyleSheet {
 public:
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index 65d25a519f..64b0d810b1 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -1354,6 +1354,8 @@ void History::setUnreadCount(int newUnreadCount) {
 		} else if (!newUnreadCount) {
 			showFrom = nullptr;
 			inboxReadBefore = qMax(inboxReadBefore, msgIdForRead() + 1);
+		} else {
+			if (!showFrom && !unreadBar && loadedAtBottom()) updateShowFrom();
 		}
 		if (inChatList(Dialogs::Mode::All)) {
 			App::histories().unreadIncrement(newUnreadCount - _unreadCount, mute());
@@ -1362,6 +1364,9 @@ void History::setUnreadCount(int newUnreadCount) {
 			}
 		}
 		_unreadCount = newUnreadCount;
+		if (auto main = App::main()) {
+			main->unreadCountChanged(this);
+		}
 		if (unreadBar) {
 			int32 count = _unreadCount;
 			if (peer->migrateTo()) {
@@ -1743,6 +1748,10 @@ const ChannelHistory *History::asChannelHistory() const {
 	return isChannel() ? static_cast<const ChannelHistory*>(this) : 0;
 }
 
+bool History::isDisplayedEmpty() const {
+	return isEmpty() || (blocks.size() == 1) && blocks.front()->items.size() == 1 && blocks.front()->items.front()->isEmpty();
+}
+
 void History::clear(bool leaveItems) {
 	if (unreadBar) {
 		unreadBar = nullptr;
@@ -7579,6 +7588,10 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
 		}
 	} break;
 
+	case mtpc_messageActionHistoryClear: {
+		text = QString();
+	} break;
+
 	case mtpc_messageActionChatDeletePhoto: {
 		text = isPost() ? lang(lng_action_removed_photo_channel) : lng_action_removed_photo(lt_from, from);
 	} break;
@@ -7885,34 +7898,40 @@ void HistoryService::draw(Painter &p, const QRect &r, TextSelection selection, u
 }
 
 int32 HistoryService::resizeGetHeight_(int32 width) {
-	int32 maxwidth = _history->width;
-	if (Adaptive::Wide()) {
-		maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
-	}
-	if (width > maxwidth) width = maxwidth;
-	width -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins
-	if (width < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) width = st::msgServicePadding.left() + st::msgServicePadding.right() + 1;
-
-	int32 nwidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 0);
-	if (nwidth != _textWidth) {
-		_textWidth = nwidth;
-		textstyleSet(&st::serviceTextStyle);
-		_textHeight = _text.countHeight(nwidth);
-		textstyleRestore();
-	}
-	if (width >= _maxw) {
-		_height = _minh;
-	} else {
-		_height = _textHeight;
-	}
-	_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
-	if (_media) {
-		_height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth());
-	}
-	_height += displayedDateHeight();
+	_height = displayedDateHeight();
 	if (auto unreadbar = Get<HistoryMessageUnreadBar>()) {
 		_height += unreadbar->height();
 	}
+
+	if (_text.isEmpty()) {
+		_textHeight = 0;
+	} else {
+		int32 maxwidth = _history->width;
+		if (Adaptive::Wide()) {
+			maxwidth = qMin(maxwidth, int32(st::msgMaxWidth + 2 * st::msgPhotoSkip + 2 * st::msgMargin.left()));
+		}
+		if (width > maxwidth) width = maxwidth;
+		width -= st::msgServiceMargin.left() + st::msgServiceMargin.left(); // two small margins
+		if (width < st::msgServicePadding.left() + st::msgServicePadding.right() + 1) width = st::msgServicePadding.left() + st::msgServicePadding.right() + 1;
+
+		int32 nwidth = qMax(width - st::msgPadding.left() - st::msgPadding.right(), 0);
+		if (nwidth != _textWidth) {
+			_textWidth = nwidth;
+			textstyleSet(&st::serviceTextStyle);
+			_textHeight = _text.countHeight(nwidth);
+			textstyleRestore();
+		}
+		if (width >= _maxw) {
+			_height += _minh;
+		} else {
+			_height += _textHeight;
+		}
+		_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
+		if (_media) {
+			_height += st::msgServiceMargin.top() + _media->resizeGetHeight(_media->currentWidth());
+		}
+	}
+
 	return _height;
 }
 
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index b5400d9222..4487816435 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -227,6 +227,8 @@ public:
 	bool isEmpty() const {
 		return blocks.isEmpty();
 	}
+	bool isDisplayedEmpty() const;
+
 	void clear(bool leaveItems = false);
 
 	virtual ~History();
@@ -1423,6 +1425,10 @@ public:
 		return _flags & MTPDmessage_ClientFlag::f_attach_to_previous;
 	}
 
+	bool isEmpty() const {
+		return _text.isEmpty() && !_media;
+	}
+
 	void clipCallback(ClipReaderNotification notification);
 
 	virtual ~HistoryItem();
diff --git a/Telegram/SourceFiles/history/history.style b/Telegram/SourceFiles/history/history.style
index 1e7a72cc2a..1a5d33f1d7 100644
--- a/Telegram/SourceFiles/history/history.style
+++ b/Telegram/SourceFiles/history/history.style
@@ -28,3 +28,4 @@ historyToDownPosition: point(12px, 10px);
 historyToDownArrow: icon {
 	{ "history_down_arrow", #b9b9b9, point(14px, 19px) },
 };
+historyToDownPaddingTop: 10px;
diff --git a/Telegram/SourceFiles/history/history_common.h b/Telegram/SourceFiles/history/history_common.h
index f5e807d5bf..2875d01b11 100644
--- a/Telegram/SourceFiles/history/history_common.h
+++ b/Telegram/SourceFiles/history/history_common.h
@@ -26,3 +26,8 @@ enum DragState {
 	DragStatePhotoFiles = 0x02,
 	DragStateImage = 0x03,
 };
+
+enum class ReadServerHistoryChecks {
+	OnlyIfUnread,
+	ForceRequest,
+};
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index f76ed930fb..0c4a05c3cc 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -258,6 +258,8 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 	}
 	uint64 ms = getms();
 
+	bool historyDisplayedEmpty = (_history->isDisplayedEmpty() && (!_migrated || _migrated->isDisplayedEmpty()));
+	bool noHistoryDisplayed = _firstLoading || historyDisplayedEmpty;
 	if (!_firstLoading && _botAbout && !_botAbout->info->text.isEmpty() && _botAbout->height > 0) {
 		if (r.y() < _botAbout->rect.y() + _botAbout->rect.height() && r.y() + r.height() > _botAbout->rect.y()) {
 			textstyleSet(&st::inTextStyle);
@@ -271,11 +273,11 @@ void HistoryInner::paintEvent(QPaintEvent *e) {
 
 			textstyleRestore();
 		}
-	} else if (_firstLoading || (_history->isEmpty() && (!_migrated || _migrated->isEmpty()))) {
+	} else if (noHistoryDisplayed) {
 		QPoint dogPos((width() - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
 		p.drawPixmap(dogPos, *cChatDogImage());
 	}
-	if (!_firstLoading) {
+	if (!noHistoryDisplayed) {
 		adjustCurrent(r.top());
 
 		SelectedItems::const_iterator selEnd = _selected.cend();
@@ -3862,6 +3864,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
 			if (wasHistory) _peer->asUser()->botInfo->inlineReturnPeerId = wasHistory->peer->id;
 			onBotStart();
 		}
+		unreadCountChanged(_history); // set _historyToEnd badge.
 	} else {
 		clearFieldText();
 		doneShow();
@@ -4276,25 +4279,17 @@ void HistoryWidget::destroyUnreadBar() {
 }
 
 void HistoryWidget::newUnreadMsg(History *history, HistoryItem *item) {
-	if (App::wnd()->historyIsActive()) {
-		if (_history == history) {
-			historyWasRead();
-			if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) {
-				destroyUnreadBar();
-			}
-		} else {
-			App::wnd()->notifySchedule(history, item);
-			history->setUnreadCount(history->unreadCount() + 1);
+	if (_history == history) {
+		if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) {
+			destroyUnreadBar();
 		}
-	} else {
-		if (_history == history) {
-			if (_scroll.scrollTop() + 1 > _scroll.scrollTopMax()) {
-				destroyUnreadBar();
-			}
+		if (App::wnd()->doWeReadServerHistory()) {
+			historyWasRead(ReadServerHistoryChecks::ForceRequest);
+			return;
 		}
-		App::wnd()->notifySchedule(history, item);
-		history->setUnreadCount(history->unreadCount() + 1);
 	}
+	App::wnd()->notifySchedule(history, item);
+	history->setUnreadCount(history->unreadCount() + 1);
 }
 
 void HistoryWidget::historyToDown(History *history) {
@@ -4307,9 +4302,20 @@ void HistoryWidget::historyToDown(History *history) {
 	}
 }
 
-void HistoryWidget::historyWasRead(bool force) {
-	App::main()->readServerHistory(_history, force);
-	if (_migrated) App::main()->readServerHistory(_migrated, force);
+void HistoryWidget::historyWasRead(ReadServerHistoryChecks checks) {
+	App::main()->readServerHistory(_history, checks);
+	if (_migrated) {
+		App::main()->readServerHistory(_migrated, ReadServerHistoryChecks::OnlyIfUnread);
+	}
+}
+
+void HistoryWidget::unreadCountChanged(History *history) {
+	if (history == _history || history == _migrated) {
+		updateToEndVisibility();
+		if (_historyToEnd) {
+			_historyToEnd->setUnreadCount(_history->unreadCount() + (_migrated ? _migrated->unreadCount() : 0));
+		}
+	}
 }
 
 void HistoryWidget::historyCleared(History *history) {
@@ -4469,10 +4475,19 @@ void HistoryWidget::windowShown() {
 	resizeEvent(0);
 }
 
-bool HistoryWidget::isActive() const {
-	if (!_history) return true;
+bool HistoryWidget::doWeReadServerHistory() const {
+	if (!_history || !_list) return true;
 	if (_firstLoadRequest || _a_show.animating()) return false;
-	if (_history->loadedAtBottom()) return true;
+	if (_history->loadedAtBottom()) {
+		int scrollTop = _scroll.scrollTop();
+		if (scrollTop + 1 > _scroll.scrollTopMax()) return true;
+
+		auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr);
+		if (showFrom && !showFrom->detached()) {
+			int scrollBottom = scrollTop + _scroll.height();
+			if (scrollBottom > _list->itemTop(showFrom)) return true;
+		}
+	}
 	if (_history->showFrom && !_history->showFrom->detached() && _history->unreadBar) return true;
 	if (_migrated && _migrated->showFrom && !_migrated->showFrom->detached() && _migrated->unreadBar) return true;
 	return false;
@@ -4604,8 +4619,15 @@ void HistoryWidget::onScroll() {
 
 void HistoryWidget::visibleAreaUpdated() {
 	if (_list && !_scroll.isHidden()) {
-		int st = _scroll.scrollTop();
-		_list->visibleAreaUpdated(st, st + _scroll.height());
+		int scrollTop = _scroll.scrollTop();
+		int scrollBottom = scrollTop + _scroll.height();
+		_list->visibleAreaUpdated(scrollTop, scrollBottom);
+		if (_history->loadedAtBottom() && (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0))) {
+			auto showFrom = (_migrated && _migrated->showFrom) ? _migrated->showFrom : (_history ? _history->showFrom : nullptr);
+			if (showFrom && !showFrom->detached() && scrollBottom > _list->itemTop(showFrom) && App::wnd()->doWeReadServerHistory()) {
+				historyWasRead(ReadServerHistoryChecks::OnlyIfUnread);
+			}
+		}
 	}
 }
 
@@ -4872,13 +4894,13 @@ void HistoryWidget::onShareContact(const PeerId &peer, UserData *contact) {
 }
 
 void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const QString &fname, const QString &lname, MsgId replyTo, int32 userId) {
-	History *h = App::history(peer);
+	auto history = App::history(peer);
 
 	uint64 randomId = rand_value<uint64>();
 	FullMsgId newId(peerToChannel(peer), clientMsgId());
 
-	App::main()->readServerHistory(h, false);
-	fastShowAtEnd(h);
+	App::main()->readServerHistory(history);
+	fastShowAtEnd(history);
 
 	PeerData *p = App::peer(peer);
 	MTPDmessage::Flags flags = newMessageFlags(p) | MTPDmessage::Flag::f_media; // unread, out
@@ -4904,12 +4926,12 @@ void HistoryWidget::shareContact(const PeerId &peer, const QString &phone, const
 	if (silentPost) {
 		sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
 	}
-	h->addNewMessage(MTP_message(MTP_flags(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_flags(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);
+	history->addNewMessage(MTP_message(MTP_flags(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);
+	history->sendRequestId = MTP::send(MTPmessages_SendMedia(MTP_flags(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, history->sendRequestId);
 
 	App::historyRegRandom(randomId, newId);
 
-	App::main()->finishForwarding(h, _silent.checked());
+	App::main()->finishForwarding(history, _silent.checked());
 	cancelReply(lastKeyboardUsed);
 }
 
@@ -6678,7 +6700,7 @@ void HistoryWidget::countHistoryShowFrom() {
 		_migrated->updateShowFrom();
 	}
 	if ((_migrated && _migrated->showFrom) || _showAtMsgId != ShowAtUnreadMsgId || !_history->unreadCount()) {
-		_history->showFrom = 0;
+		_history->showFrom = nullptr;
 		return;
 	}
 	_history->updateShowFrom();
@@ -6768,7 +6790,22 @@ void HistoryWidget::updateBotKeyboard(History *h, bool force) {
 }
 
 void HistoryWidget::updateToEndVisibility() {
-	bool toEndVisible = !_a_show.animating() && _history && !_firstLoadRequest && (!_history->loadedAtBottom() || _replyReturn || _scroll.scrollTop() + st::wndMinHeight < _scroll.scrollTopMax());
+	auto isToEndVisible = [this]() {
+		if (!_history || _a_show.animating() || _firstLoadRequest) {
+			return false;
+		}
+		if (!_history->loadedAtBottom() || _replyReturn) {
+			return true;
+		}
+		if (_scroll.scrollTop() + st::wndMinHeight < _scroll.scrollTopMax()) {
+			return true;
+		}
+		if (_history->unreadCount() > 0 || (_migrated && _migrated->unreadCount() > 0)) {
+			return true;
+		}
+		return false;
+	};
+	bool toEndVisible = isToEndVisible();
 	if (toEndVisible && _historyToEnd->isHidden()) {
 		_historyToEnd->show();
 	} else if (!toEndVisible && !_historyToEnd->isHidden()) {
@@ -6849,7 +6886,7 @@ void HistoryWidget::onPhotoSend(PhotoData *photo) {
 void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot) {
 	if (!_history || !result || !canSendMessages(_peer)) return;
 
-	App::main()->readServerHistory(_history, false);
+	App::main()->readServerHistory(_history);
 	fastShowAtEnd(_history);
 
 	uint64 randomId = rand_value<uint64>();
@@ -7029,7 +7066,7 @@ void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
 		return;
 	}
 
-	App::main()->readServerHistory(_history, false);
+	App::main()->readServerHistory(_history);
 	fastShowAtEnd(_history);
 
 	uint64 randomId = rand_value<uint64>();
@@ -7084,7 +7121,7 @@ void HistoryWidget::sendExistingDocument(DocumentData *doc, const QString &capti
 void HistoryWidget::sendExistingPhoto(PhotoData *photo, const QString &caption) {
 	if (!_history || !photo || !canSendMessages(_peer)) return;
 
-	App::main()->readServerHistory(_history, false);
+	App::main()->readServerHistory(_history);
 	fastShowAtEnd(_history);
 
 	uint64 randomId = rand_value<uint64>();
diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h
index e747eb9410..8b2bd6ede2 100644
--- a/Telegram/SourceFiles/historywidget.h
+++ b/Telegram/SourceFiles/historywidget.h
@@ -498,7 +498,7 @@ public:
 	void historyLoaded();
 
 	void windowShown();
-	bool isActive() const;
+	bool doWeReadServerHistory() const;
 
 	void resizeEvent(QResizeEvent *e) override;
 	void keyPressEvent(QKeyEvent *e) override;
@@ -527,8 +527,9 @@ public:
 
 	void newUnreadMsg(History *history, HistoryItem *item);
 	void historyToDown(History *history);
-	void historyWasRead(bool force = true);
+	void historyWasRead(ReadServerHistoryChecks checks);
 	void historyCleared(History *history);
+	void unreadCountChanged(History *history);
 
 	QRect historyRect() const;
 
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 32af1c33ee..e553164674 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -253,18 +253,18 @@ void MainWidget::cancelForwarding() {
 	_history->cancelForwarding();
 }
 
-void MainWidget::finishForwarding(History *hist, bool silent) {
-	if (!hist) return;
+void MainWidget::finishForwarding(History *history, bool silent) {
+	if (!history) return;
 
 	if (!_toForward.isEmpty()) {
 		bool genClientSideMessage = (_toForward.size() < 2);
 		PeerData *forwardFrom = 0;
-		App::main()->readServerHistory(hist, false);
+		App::main()->readServerHistory(history);
 
 		MTPDmessage::Flags flags = 0;
 		MTPmessages_ForwardMessages::Flags sendFlags = 0;
-		bool channelPost = hist->peer->isChannel() && !hist->peer->isMegagroup();
-		bool showFromName = !channelPost || hist->peer->asChannel()->addsSignature();
+		bool channelPost = history->peer->isChannel() && !history->peer->isMegagroup();
+		bool showFromName = !channelPost || history->peer->asChannel()->addsSignature();
 		bool silentPost = channelPost && silent;
 		if (channelPost) {
 			flags |= MTPDmessage::Flag::f_views;
@@ -284,9 +284,9 @@ void MainWidget::finishForwarding(History *hist, bool silent) {
 		for (SelectedItemSet::const_iterator i = _toForward.cbegin(), e = _toForward.cend(); i != e; ++i) {
 			uint64 randomId = rand_value<uint64>();
 			if (genClientSideMessage) {
-				FullMsgId newId(peerToChannel(hist->peer->id), clientMsgId());
+				FullMsgId newId(peerToChannel(history->peer->id), clientMsgId());
 				HistoryMessage *msg = static_cast<HistoryMessage*>(_toForward.cbegin().value());
-				hist->addNewForwarded(newId.msg, flags, date(MTP_int(unixtime())), showFromName ? MTP::authedId() : 0, msg);
+				history->addNewForwarded(newId.msg, flags, date(MTP_int(unixtime())), showFromName ? MTP::authedId() : 0, msg);
 				if (HistoryMedia *media = msg->getMedia()) {
 					if (media->type() == MediaTypeSticker) {
 						App::main()->incrementSticker(media->getDocument());
@@ -296,7 +296,7 @@ void MainWidget::finishForwarding(History *hist, bool silent) {
 			}
 			if (forwardFrom != i.value()->history()->peer) {
 				if (forwardFrom) {
-					hist->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector<MTPint>(ids), MTP_vector<MTPlong>(randomIds), hist->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
+					history->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector<MTPint>(ids), MTP_vector<MTPlong>(randomIds), history->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, history->sendRequestId);
 					ids.resize(0);
 					randomIds.resize(0);
 				}
@@ -305,18 +305,18 @@ void MainWidget::finishForwarding(History *hist, bool silent) {
 			ids.push_back(MTP_int(i.value()->id));
 			randomIds.push_back(MTP_long(randomId));
 		}
-		hist->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector<MTPint>(ids), MTP_vector<MTPlong>(randomIds), hist->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
+		history->sendRequestId = MTP::send(MTPmessages_ForwardMessages(MTP_flags(sendFlags), forwardFrom->input, MTP_vector<MTPint>(ids), MTP_vector<MTPlong>(randomIds), history->peer->input), rpcDone(&MainWidget::sentUpdatesReceived), RPCFailHandlerPtr(), 0, 0, history->sendRequestId);
 
-		if (_history->peer() == hist->peer) {
+		if (_history->peer() == history->peer) {
 			_history->peerMessagesUpdated();
 		}
 
 		cancelForwarding();
 	}
 
-	historyToDown(hist);
+	historyToDown(history);
 	dialogsToUp();
-	_history->peerMessagesUpdated(hist->peer->id);
+	_history->peerMessagesUpdated(history->peer->id);
 }
 
 void MainWidget::webPageUpdated(WebPageData *data) {
@@ -675,7 +675,9 @@ void MainWidget::deleteHistoryAfterLeave(PeerData *peer, const MTPUpdates &updat
 	deleteConversation(peer);
 }
 
-void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result) {
+void MainWidget::deleteHistoryPart(DeleteHistoryRequest request, const MTPmessages_AffectedHistory &result) {
+	auto peer = request.peer;
+
 	const auto &d(result.c_messages_affectedHistory());
 	if (peer && peer->isChannel()) {
 		if (peer->asChannel()->ptsUpdated(d.vpts.v, d.vpts_count.v)) {
@@ -697,7 +699,11 @@ void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHis
 		return;
 	}
 
-	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
+	MTPmessages_DeleteHistory::Flags flags = 0;
+	if (request.justClearHistory) {
+		flags |= MTPmessages_DeleteHistory::Flag::f_just_clear;
+	}
+	MTP::send(MTPmessages_DeleteHistory(MTP_flags(flags), peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, request));
 }
 
 void MainWidget::deleteMessages(PeerData *peer, const QVector<MTPint> &ids) {
@@ -742,7 +748,9 @@ void MainWidget::deleteConversation(PeerData *peer, bool deleteHistory) {
 		peer->asChannel()->ptsWaitingForShortPoll(-1);
 	}
 	if (deleteHistory) {
-		MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
+		DeleteHistoryRequest request = { peer, false };
+		MTPmessages_DeleteHistory::Flags flags = 0;
+		MTP::send(MTPmessages_DeleteHistory(MTP_flags(flags), peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, request));
 	}
 }
 
@@ -794,7 +802,9 @@ void MainWidget::clearHistory(PeerData *peer) {
 		h->newLoaded = h->oldLoaded = true;
 	}
 	Ui::showPeerHistory(peer->id, ShowAtUnreadMsgId);
-	MTP::send(MTPmessages_DeleteHistory(peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, peer));
+	MTPmessages_DeleteHistory::Flags flags = MTPmessages_DeleteHistory::Flag::f_just_clear;
+	DeleteHistoryRequest request = { peer, true };
+	MTP::send(MTPmessages_DeleteHistory(MTP_flags(flags), peer->input, MTP_int(0)), rpcDone(&MainWidget::deleteHistoryPart, request));
 }
 
 void MainWidget::addParticipants(PeerData *chatOrChannel, const QVector<UserData*> &users) {
@@ -1045,7 +1055,7 @@ void MainWidget::sendMessage(const MessageToSend &message) {
 	auto history = message.history;
 	const auto &textWithTags = message.textWithTags;
 
-	readServerHistory(history, false);
+	readServerHistory(history);
 	_history->fastShowAtEnd(history);
 
 	if (!history || !_history->canSendMessages(history->peer)) {
@@ -1142,27 +1152,34 @@ void MainWidget::saveRecentHashtags(const QString &text) {
 	}
 }
 
-void MainWidget::readServerHistory(History *hist, bool force) {
-	if (!hist || (!force && !hist->unreadCount())) return;
+void MainWidget::readServerHistory(History *history, ReadServerHistoryChecks checks) {
+	if (!history) return;
+	if (checks == ReadServerHistoryChecks::OnlyIfUnread && !history->unreadCount()) return;
 
-	MsgId upTo = hist->inboxRead(0);
-	if (hist->isChannel() && !hist->peer->asChannel()->amIn()) {
-		return; // no read request for channels that I didn't koin
+	auto peer = history->peer;
+	MsgId upTo = history->inboxRead(0);
+	if (auto channel = peer->asChannel()) {
+		if (!channel->amIn()) {
+			return; // no read request for channels that I didn't koin
+		}
 	}
 
-	ReadRequests::const_iterator i = _readRequests.constFind(hist->peer);
-    if (i == _readRequests.cend()) {
-		sendReadRequest(hist->peer, upTo);
-	} else {
-		ReadRequestsPending::iterator i = _readRequestsPending.find(hist->peer);
+	if (_readRequests.contains(peer)) {
+		auto i = _readRequestsPending.find(peer);
 		if (i == _readRequestsPending.cend()) {
-			_readRequestsPending.insert(hist->peer, upTo);
+			_readRequestsPending.insert(peer, upTo);
 		} else if (i.value() < upTo) {
 			i.value() = upTo;
 		}
+	} else {
+		sendReadRequest(peer, upTo);
 	}
 }
 
+void MainWidget::unreadCountChanged(History *history) {
+	_history->unreadCountChanged(history);
+}
+
 uint64 MainWidget::animActiveTimeStart(const HistoryItem *msg) const {
 	return _history->animActiveTimeStart(msg);
 }
@@ -1385,17 +1402,17 @@ void MainWidget::overviewLoaded(History *history, const MTPmessages_Messages &re
 void MainWidget::sendReadRequest(PeerData *peer, MsgId upTo) {
 	if (!MTP::authedId()) return;
 	if (peer->isChannel()) {
-		_readRequests.insert(peer, qMakePair(MTP::send(MTPchannels_ReadHistory(peer->asChannel()->inputChannel, MTP_int(upTo)), rpcDone(&MainWidget::channelWasRead, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo));
+		_readRequests.insert(peer, qMakePair(MTP::send(MTPchannels_ReadHistory(peer->asChannel()->inputChannel, MTP_int(upTo)), rpcDone(&MainWidget::channelReadDone, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo));
 	} else {
-		_readRequests.insert(peer, qMakePair(MTP::send(MTPmessages_ReadHistory(peer->input, MTP_int(upTo)), rpcDone(&MainWidget::historyWasRead, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo));
+		_readRequests.insert(peer, qMakePair(MTP::send(MTPmessages_ReadHistory(peer->input, MTP_int(upTo)), rpcDone(&MainWidget::historyReadDone, peer), rpcFail(&MainWidget::readRequestFail, peer)), upTo));
 	}
 }
 
-void MainWidget::channelWasRead(PeerData *peer, const MTPBool &result) {
+void MainWidget::channelReadDone(PeerData *peer, const MTPBool &result) {
 	readRequestDone(peer);
 }
 
-void MainWidget::historyWasRead(PeerData *peer, const MTPmessages_AffectedMessages &result) {
+void MainWidget::historyReadDone(PeerData *peer, const MTPmessages_AffectedMessages &result) {
 	messagesAffected(peer, result);
 	readRequestDone(peer);
 }
@@ -2341,24 +2358,24 @@ void MainWidget::onActiveChannelUpdateFull() {
 	}
 }
 
-void MainWidget::historyToDown(History *hist) {
-	_history->historyToDown(hist);
+void MainWidget::historyToDown(History *history) {
+	_history->historyToDown(history);
 }
 
 void MainWidget::dialogsToUp() {
 	_dialogs->dialogsToUp();
 }
 
-void MainWidget::newUnreadMsg(History *hist, HistoryItem *item) {
-	_history->newUnreadMsg(hist, item);
+void MainWidget::newUnreadMsg(History *history, HistoryItem *item) {
+	_history->newUnreadMsg(history, item);
 }
 
-void MainWidget::historyWasRead() {
-	_history->historyWasRead(false);
+void MainWidget::markActiveHistoryAsRead() {
+	_history->historyWasRead(ReadServerHistoryChecks::OnlyIfUnread);
 }
 
-void MainWidget::historyCleared(History *hist) {
-	_history->historyCleared(hist);
+void MainWidget::historyCleared(History *history) {
+	_history->historyCleared(history);
 }
 
 void MainWidget::animShow(const QPixmap &bgAnimCache, bool back) {
@@ -3623,8 +3640,8 @@ bool MainWidget::isActive() const {
 	return !_isIdle && isVisible() && !_a_show.animating();
 }
 
-bool MainWidget::historyIsActive() const {
-	return isActive() && !_profile && !_overview && _history->isActive();
+bool MainWidget::doWeReadServerHistory() const {
+	return isActive() && !_profile && !_overview && _history->doWeReadServerHistory();
 }
 
 bool MainWidget::lastWasOnline() const {
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 564cfeb7e4..881071b306 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -199,7 +199,7 @@ public:
 	void historyToDown(History *hist);
 	void dialogsToUp();
 	void newUnreadMsg(History *history, HistoryItem *item);
-	void historyWasRead();
+	void markActiveHistoryAsRead();
 	void historyCleared(History *history);
 
 	void peerBefore(const PeerData *inPeer, MsgId inMsg, PeerData *&outPeer, MsgId &outMsg);
@@ -228,7 +228,7 @@ public:
 	void updateOnlineDisplayIn(int32 msecs);
 
 	bool isActive() const;
-	bool historyIsActive() const;
+	bool doWeReadServerHistory() const;
 	bool lastWasOnline() const;
 	uint64 lastSetOnline() const;
 
@@ -291,7 +291,8 @@ public:
 	void sendMessage(const MessageToSend &message);
 	void saveRecentHashtags(const QString &text);
 
-    void readServerHistory(History *history, bool force = true);
+    void readServerHistory(History *history, ReadServerHistoryChecks checks = ReadServerHistoryChecks::OnlyIfUnread);
+	void unreadCountChanged(History *history);
 
 	uint64 animActiveTimeStart(const HistoryItem *msg) const;
 	void stopAnimActive();
@@ -480,8 +481,8 @@ public slots:
 private:
 
 	void sendReadRequest(PeerData *peer, MsgId upTo);
-	void channelWasRead(PeerData *peer, const MTPBool &result);
-    void historyWasRead(PeerData *peer, const MTPmessages_AffectedMessages &result);
+	void channelReadDone(PeerData *peer, const MTPBool &result);
+    void historyReadDone(PeerData *peer, const MTPmessages_AffectedMessages &result);
 	bool readRequestFail(PeerData *peer, const RPCError &error);
 	void readRequestDone(PeerData *peer);
 
@@ -521,7 +522,11 @@ private:
 	void feedUpdateVector(const MTPVector<MTPUpdate> &updates, bool skipMessageIds = false);
 	void feedMessageIds(const MTPVector<MTPUpdate> &updates);
 
-	void deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHistory &result);
+	struct DeleteHistoryRequest {
+		PeerData *peer;
+		bool justClearHistory;
+	};
+	void deleteHistoryPart(DeleteHistoryRequest request, const MTPmessages_AffectedHistory &result);
 	struct DeleteAllFromUserParams {
 		ChannelData *channel;
 		UserData *from;
diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp
index de50efa2aa..c6cba8fc23 100644
--- a/Telegram/SourceFiles/mainwindow.cpp
+++ b/Telegram/SourceFiles/mainwindow.cpp
@@ -904,13 +904,13 @@ void MainWindow::hideConnecting() {
 	if (settings) settings->update();
 }
 
-bool MainWindow::historyIsActive() const {
-    return isActive(false) && main && main->historyIsActive() && (!settings || !settings->isVisible());
+bool MainWindow::doWeReadServerHistory() const {
+	return isActive(false) && main && (!settings || !settings->isVisible()) && main->doWeReadServerHistory();
 }
 
 void MainWindow::checkHistoryActivation() {
-	if (main && MTP::authedId() && historyIsActive()) {
-		main->historyWasRead();
+	if (main && MTP::authedId() && doWeReadServerHistory()) {
+		main->markActiveHistoryAsRead();
 	}
     QTimer::singleShot(1, this, SLOT(updateTrayMenu()));
 }
diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h
index 16d7d5d00e..ddac84e02f 100644
--- a/Telegram/SourceFiles/mainwindow.h
+++ b/Telegram/SourceFiles/mainwindow.h
@@ -185,7 +185,7 @@ public:
 	void showPhoto(PhotoData *photo, PeerData *item);
 	void showDocument(DocumentData *doc, HistoryItem *item);
 
-	bool historyIsActive() const;
+	bool doWeReadServerHistory() const;
 
 	void activate();
 
diff --git a/Telegram/SourceFiles/mtproto/generate.py b/Telegram/SourceFiles/mtproto/generate.py
index e93d8e5d32..d024f8036b 100644
--- a/Telegram/SourceFiles/mtproto/generate.py
+++ b/Telegram/SourceFiles/mtproto/generate.py
@@ -38,6 +38,7 @@ addChildParentFlags('MTPDreplyKeyboardHide', 'MTPDreplyKeyboardMarkup');
 addChildParentFlags('MTPDreplyKeyboardForceReply', 'MTPDreplyKeyboardMarkup');
 addChildParentFlags('MTPDinputPeerNotifySettings', 'MTPDpeerNotifySettings');
 addChildParentFlags('MTPDpeerNotifySettings', 'MTPDinputPeerNotifySettings');
+addChildParentFlags('MTPDchannelForbidden', 'MTPDchannel');
 
 # this is a map (key flags -> map (flag name -> flag bit))
 # each key flag of parentFlags should be a subset of the value flag here
diff --git a/Telegram/SourceFiles/mtproto/scheme.tl b/Telegram/SourceFiles/mtproto/scheme.tl
index 5845ac894a..0042053a2b 100644
--- a/Telegram/SourceFiles/mtproto/scheme.tl
+++ b/Telegram/SourceFiles/mtproto/scheme.tl
@@ -210,7 +210,7 @@ chatEmpty#9ba2d800 id:int = Chat;
 chat#d91cdd54 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true admins_enabled:flags.3?true admin:flags.4?true deactivated:flags.5?true id:int title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel = Chat;
 chatForbidden#7328bdb id:int title:string = Chat;
 channel#a14dca52 flags:# creator:flags.0?true kicked:flags.1?true left:flags.2?true editor:flags.3?true moderator:flags.4?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true democracy:flags.10?true signatures:flags.11?true min:flags.12?true id:int access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int version:int restriction_reason:flags.9?string = Chat;
-channelForbidden#2d85832c id:int access_hash:long title:string = Chat;
+channelForbidden#8537784f flags:# broadcast:flags.5?true megagroup:flags.8?true id:int access_hash:long title:string = Chat;
 
 chatFull#2e02a614 id:int participants:ChatParticipants chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> = ChatFull;
 channelFull#c3d5512f flags:# can_view_participants:flags.3?true can_set_username:flags.6?true id:int about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:ExportedChatInvite bot_info:Vector<BotInfo> migrated_from_chat_id:flags.4?int migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int = ChatFull;
@@ -250,6 +250,7 @@ messageActionChannelCreate#95d2ac92 title:string = MessageAction;
 messageActionChatMigrateTo#51bdb021 channel_id:int = MessageAction;
 messageActionChannelMigrateFrom#b055eaee title:string chat_id:int = MessageAction;
 messageActionPinMessage#94bd38ed = MessageAction;
+messageActionHistoryClear#9fbab604 = MessageAction;
 
 dialog#66ffba14 flags:# peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage = Dialog;
 
@@ -693,7 +694,7 @@ contacts.topPeersNotModified#de266ef5 = contacts.TopPeers;
 contacts.topPeers#70b772a8 categories:Vector<TopPeerCategoryPeers> chats:Vector<Chat> users:Vector<User> = contacts.TopPeers;
 
 draftMessageEmpty#ba4baec5 = DraftMessage;
-draftMessage#2a280746 flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> = DraftMessage;
+draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
 
 ---functions---
 
@@ -768,11 +769,11 @@ messages.getDialogs#6b47f94d offset_date:int offset_id:int offset_peer:InputPeer
 messages.getHistory#afa92846 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int = messages.Messages;
 messages.search#d4569248 flags:# peer:InputPeer q:string filter:MessagesFilter min_date:int max_date:int offset:int max_id:int limit:int = messages.Messages;
 messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages;
-messages.deleteHistory#b7c13bd9 peer:InputPeer max_id:int = messages.AffectedHistory;
+messages.deleteHistory#1c015b09 flags:# just_clear:flags.0?true peer:InputPeer max_id:int = messages.AffectedHistory;
 messages.deleteMessages#a5f18925 id:Vector<int> = messages.AffectedMessages;
 messages.receivedMessages#5a954c0 max_id:int = Vector<ReceivedNotifyMessage>;
 messages.setTyping#a3825e50 peer:InputPeer action:SendMessageAction = Bool;
-messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
+messages.sendMessage#fa88427a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true peer:InputPeer reply_to_msg_id:flags.0?int message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector<MessageEntity> = Updates;
 messages.sendMedia#c8f16791 flags:# silent:flags.5?true background:flags.6?true peer:InputPeer reply_to_msg_id:flags.0?int media:InputMedia random_id:long reply_markup:flags.2?ReplyMarkup = Updates;
 messages.forwardMessages#708e0195 flags:# silent:flags.5?true background:flags.6?true from_peer:InputPeer id:Vector<int> random_id:Vector<long> to_peer:InputPeer = Updates;
 messages.reportSpam#cf1592db peer:InputPeer = Bool;
diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.cpp b/Telegram/SourceFiles/mtproto/scheme_auto.cpp
index 2d076a6a17..ea6a0ae628 100644
--- a/Telegram/SourceFiles/mtproto/scheme_auto.cpp
+++ b/Telegram/SourceFiles/mtproto/scheme_auto.cpp
@@ -1179,6 +1179,8 @@ void _serialize_channel(MTPStringLogger &to, int32 stage, int32 lev, Types &type
 }
 
 void _serialize_channelForbidden(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	MTPDchannelForbidden::Flags flag(iflag);
+
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
 	} else {
@@ -1186,9 +1188,12 @@ void _serialize_channelForbidden(MTPStringLogger &to, int32 stage, int32 lev, Ty
 		to.add("\n").addSpaces(lev);
 	}
 	switch (stage) {
-	case 0: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 1: to.add("  access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 2: to.add("  title: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  broadcast: "); ++stages.back(); if (flag & MTPDchannelForbidden::Flag::f_broadcast) { to.add("YES [ BY BIT 5 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
+	case 2: to.add("  megagroup: "); ++stages.back(); if (flag & MTPDchannelForbidden::Flag::f_megagroup) { to.add("YES [ BY BIT 8 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 8 IN FIELD flags ]"); } break;
+	case 3: to.add("  id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 4: to.add("  access_hash: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 5: to.add("  title: "); ++stages.back(); types.push_back(mtpc_string+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;
 	}
 }
@@ -1634,6 +1639,10 @@ void _serialize_messageActionPinMessage(MTPStringLogger &to, int32 stage, int32
 	to.add("{ messageActionPinMessage }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
 }
 
+void _serialize_messageActionHistoryClear(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	to.add("{ messageActionHistoryClear }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
+}
+
 void _serialize_dialog(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
 	MTPDdialog::Flags flag(iflag);
 
@@ -5731,6 +5740,7 @@ void _serialize_draftMessage(MTPStringLogger &to, int32 stage, int32 lev, Types
 	case 2: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPDdraftMessage::Flag::f_reply_to_msg_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
 	case 3: to.add("  message: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
 	case 4: to.add("  entities: "); ++stages.back(); if (flag & MTPDdraftMessage::Flag::f_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;
+	case 5: to.add("  date: "); ++stages.back(); types.push_back(mtpc_int+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;
 	}
 }
@@ -7145,6 +7155,8 @@ void _serialize_channels_deleteMessages(MTPStringLogger &to, int32 stage, int32
 }
 
 void _serialize_messages_deleteHistory(MTPStringLogger &to, int32 stage, int32 lev, Types &types, Types &vtypes, StagesFlags &stages, StagesFlags &flags, const mtpPrime *start, const mtpPrime *end, int32 iflag) {
+	MTPmessages_deleteHistory::Flags flag(iflag);
+
 	if (stage) {
 		to.add(",\n").addSpaces(lev);
 	} else {
@@ -7152,8 +7164,10 @@ void _serialize_messages_deleteHistory(MTPStringLogger &to, int32 stage, int32 l
 		to.add("\n").addSpaces(lev);
 	}
 	switch (stage) {
-	case 0: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 1: to.add("  max_id: "); ++stages.back(); types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 0: to.add("  flags: "); ++stages.back(); if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; types.push_back(mtpc_flags); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 1: to.add("  just_clear: "); ++stages.back(); if (flag & MTPmessages_deleteHistory::Flag::f_just_clear) { to.add("YES [ BY BIT 0 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	case 2: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 3: to.add("  max_id: "); ++stages.back(); types.push_back(mtpc_int+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;
 	}
 }
@@ -7199,12 +7213,13 @@ void _serialize_messages_sendMessage(MTPStringLogger &to, int32 stage, int32 lev
 	case 1: to.add("  no_webpage: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_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("  silent: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_silent) { to.add("YES [ BY BIT 5 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 5 IN FIELD flags ]"); } break;
 	case 3: to.add("  background: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_background) { to.add("YES [ BY BIT 6 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 6 IN FIELD flags ]"); } break;
-	case 4: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 5: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_reply_to_msg_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
-	case 6: to.add("  message: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 7: to.add("  random_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
-	case 8: to.add("  reply_markup: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_reply_markup) { 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 9: to.add("  entities: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_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;
+	case 4: to.add("  clear_draft: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_clear_draft) { to.add("YES [ BY BIT 7 IN FIELD flags ]"); } else { to.add("[ SKIPPED BY BIT 7 IN FIELD flags ]"); } break;
+	case 5: to.add("  peer: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 6: to.add("  reply_to_msg_id: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_reply_to_msg_id) { types.push_back(mtpc_int+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); } else { to.add("[ SKIPPED BY BIT 0 IN FIELD flags ]"); } break;
+	case 7: to.add("  message: "); ++stages.back(); types.push_back(mtpc_string+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 8: to.add("  random_id: "); ++stages.back(); types.push_back(mtpc_long+0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
+	case 9: to.add("  reply_markup: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_reply_markup) { 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 10: to.add("  entities: "); ++stages.back(); if (flag & MTPmessages_sendMessage::Flag::f_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;
 	}
 }
@@ -8357,6 +8372,7 @@ namespace {
 		_serializers.insert(mtpc_messageActionChatMigrateTo, _serialize_messageActionChatMigrateTo);
 		_serializers.insert(mtpc_messageActionChannelMigrateFrom, _serialize_messageActionChannelMigrateFrom);
 		_serializers.insert(mtpc_messageActionPinMessage, _serialize_messageActionPinMessage);
+		_serializers.insert(mtpc_messageActionHistoryClear, _serialize_messageActionHistoryClear);
 		_serializers.insert(mtpc_dialog, _serialize_dialog);
 		_serializers.insert(mtpc_photoEmpty, _serialize_photoEmpty);
 		_serializers.insert(mtpc_photo, _serialize_photo);
diff --git a/Telegram/SourceFiles/mtproto/scheme_auto.h b/Telegram/SourceFiles/mtproto/scheme_auto.h
index 3a28c53e03..c1c974c50a 100644
--- a/Telegram/SourceFiles/mtproto/scheme_auto.h
+++ b/Telegram/SourceFiles/mtproto/scheme_auto.h
@@ -145,7 +145,7 @@ enum {
 	mtpc_chat = 0xd91cdd54,
 	mtpc_chatForbidden = 0x7328bdb,
 	mtpc_channel = 0xa14dca52,
-	mtpc_channelForbidden = 0x2d85832c,
+	mtpc_channelForbidden = 0x8537784f,
 	mtpc_chatFull = 0x2e02a614,
 	mtpc_channelFull = 0xc3d5512f,
 	mtpc_chatParticipant = 0xc8d7493e,
@@ -178,6 +178,7 @@ enum {
 	mtpc_messageActionChatMigrateTo = 0x51bdb021,
 	mtpc_messageActionChannelMigrateFrom = 0xb055eaee,
 	mtpc_messageActionPinMessage = 0x94bd38ed,
+	mtpc_messageActionHistoryClear = 0x9fbab604,
 	mtpc_dialog = 0x66ffba14,
 	mtpc_photoEmpty = 0x2331b22d,
 	mtpc_photo = 0xcded42fe,
@@ -499,7 +500,7 @@ enum {
 	mtpc_contacts_topPeersNotModified = 0xde266ef5,
 	mtpc_contacts_topPeers = 0x70b772a8,
 	mtpc_draftMessageEmpty = 0xba4baec5,
-	mtpc_draftMessage = 0x2a280746,
+	mtpc_draftMessage = 0xfd8e711f,
 	mtpc_invokeAfterMsg = 0xcb9f372d,
 	mtpc_invokeAfterMsgs = 0x3dc4b4f0,
 	mtpc_initConnection = 0x69796de9,
@@ -566,7 +567,7 @@ enum {
 	mtpc_messages_getHistory = 0xafa92846,
 	mtpc_messages_search = 0xd4569248,
 	mtpc_messages_readHistory = 0xe306d3a,
-	mtpc_messages_deleteHistory = 0xb7c13bd9,
+	mtpc_messages_deleteHistory = 0x1c015b09,
 	mtpc_messages_deleteMessages = 0xa5f18925,
 	mtpc_messages_receivedMessages = 0x5a954c0,
 	mtpc_messages_setTyping = 0xa3825e50,
@@ -10441,11 +10442,24 @@ public:
 
 class MTPDchannelForbidden : public mtpDataImpl<MTPDchannelForbidden> {
 public:
+	enum class Flag : int32 {
+		f_broadcast = (1 << 5),
+		f_megagroup = (1 << 8),
+
+		MAX_FIELD = (1 << 8),
+	};
+	Q_DECLARE_FLAGS(Flags, Flag);
+	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
+
+	bool is_broadcast() const { return vflags.v & Flag::f_broadcast; }
+	bool is_megagroup() const { return vflags.v & Flag::f_megagroup; }
+
 	MTPDchannelForbidden() {
 	}
-	MTPDchannelForbidden(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title) : vid(_id), vaccess_hash(_access_hash), vtitle(_title) {
+	MTPDchannelForbidden(const MTPflags<MTPDchannelForbidden::Flags> &_flags, MTPint _id, const MTPlong &_access_hash, const MTPstring &_title) : vflags(_flags), vid(_id), vaccess_hash(_access_hash), vtitle(_title) {
 	}
 
+	MTPflags<MTPDchannelForbidden::Flags> vflags;
 	MTPint vid;
 	MTPlong vaccess_hash;
 	MTPstring vtitle;
@@ -14388,13 +14402,14 @@ public:
 
 	MTPDdraftMessage() {
 	}
-	MTPDdraftMessage(const MTPflags<MTPDdraftMessage::Flags> &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities) : vflags(_flags), vreply_to_msg_id(_reply_to_msg_id), vmessage(_message), ventities(_entities) {
+	MTPDdraftMessage(const MTPflags<MTPDdraftMessage::Flags> &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities, MTPint _date) : vflags(_flags), vreply_to_msg_id(_reply_to_msg_id), vmessage(_message), ventities(_entities), vdate(_date) {
 	}
 
 	MTPflags<MTPDdraftMessage::Flags> vflags;
 	MTPint vreply_to_msg_id;
 	MTPstring vmessage;
 	MTPVector<MTPMessageEntity> ventities;
+	MTPint vdate;
 };
 
 // RPC methods
@@ -17553,6 +17568,17 @@ public:
 
 class MTPmessages_deleteHistory { // RPC method 'messages.deleteHistory'
 public:
+	enum class Flag : int32 {
+		f_just_clear = (1 << 0),
+
+		MAX_FIELD = (1 << 0),
+	};
+	Q_DECLARE_FLAGS(Flags, Flag);
+	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
+
+	bool is_just_clear() const { return vflags.v & Flag::f_just_clear; }
+
+	MTPflags<MTPmessages_deleteHistory::Flags> vflags;
 	MTPInputPeer vpeer;
 	MTPint vmax_id;
 
@@ -17561,26 +17587,30 @@ public:
 	MTPmessages_deleteHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteHistory) {
 		read(from, end, cons);
 	}
-	MTPmessages_deleteHistory(const MTPInputPeer &_peer, MTPint _max_id) : vpeer(_peer), vmax_id(_max_id) {
+	MTPmessages_deleteHistory(const MTPflags<MTPmessages_deleteHistory::Flags> &_flags, const MTPInputPeer &_peer, MTPint _max_id) : vflags(_flags), vpeer(_peer), vmax_id(_max_id) {
 	}
 
 	uint32 innerLength() const {
-		return vpeer.innerLength() + vmax_id.innerLength();
+		return vflags.innerLength() + vpeer.innerLength() + vmax_id.innerLength();
 	}
 	mtpTypeId type() const {
 		return mtpc_messages_deleteHistory;
 	}
 	void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_deleteHistory) {
+		vflags.read(from, end);
 		vpeer.read(from, end);
 		vmax_id.read(from, end);
 	}
 	void write(mtpBuffer &to) const {
+		vflags.write(to);
 		vpeer.write(to);
 		vmax_id.write(to);
 	}
 
 	typedef MTPmessages_AffectedHistory ResponseType;
 };
+Q_DECLARE_OPERATORS_FOR_FLAGS(MTPmessages_deleteHistory::Flags)
+
 class MTPmessages_DeleteHistory : public MTPBoxed<MTPmessages_deleteHistory> {
 public:
 	MTPmessages_DeleteHistory() {
@@ -17589,7 +17619,7 @@ public:
 	}
 	MTPmessages_DeleteHistory(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_deleteHistory>(from, end, cons) {
 	}
-	MTPmessages_DeleteHistory(const MTPInputPeer &_peer, MTPint _max_id) : MTPBoxed<MTPmessages_deleteHistory>(MTPmessages_deleteHistory(_peer, _max_id)) {
+	MTPmessages_DeleteHistory(const MTPflags<MTPmessages_deleteHistory::Flags> &_flags, const MTPInputPeer &_peer, MTPint _max_id) : MTPBoxed<MTPmessages_deleteHistory>(MTPmessages_deleteHistory(_flags, _peer, _max_id)) {
 	}
 };
 
@@ -17719,12 +17749,13 @@ public:
 		f_no_webpage = (1 << 1),
 		f_silent = (1 << 5),
 		f_background = (1 << 6),
+		f_clear_draft = (1 << 7),
 		f_reply_to_msg_id = (1 << 0),
 		f_reply_markup = (1 << 2),
 		f_entities = (1 << 3),
 
 
-		MAX_FIELD = (1 << 6),
+		MAX_FIELD = (1 << 7),
 	};
 	Q_DECLARE_FLAGS(Flags, Flag);
 	friend inline Flags operator~(Flag v) { return QFlag(~static_cast<int32>(v)); }
@@ -17732,6 +17763,7 @@ public:
 	bool is_no_webpage() const { return vflags.v & Flag::f_no_webpage; }
 	bool is_silent() const { return vflags.v & Flag::f_silent; }
 	bool is_background() const { return vflags.v & Flag::f_background; }
+	bool is_clear_draft() const { return vflags.v & Flag::f_clear_draft; }
 	bool has_reply_to_msg_id() const { return vflags.v & Flag::f_reply_to_msg_id; }
 	bool has_reply_markup() const { return vflags.v & Flag::f_reply_markup; }
 	bool has_entities() const { return vflags.v & Flag::f_entities; }
@@ -22490,8 +22522,8 @@ public:
 	inline static MTPchat new_channel(const MTPflags<MTPDchannel::Flags> &_flags, MTPint _id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_username, const MTPChatPhoto &_photo, MTPint _date, MTPint _version, const MTPstring &_restriction_reason) {
 		return MTPchat(new MTPDchannel(_flags, _id, _access_hash, _title, _username, _photo, _date, _version, _restriction_reason));
 	}
-	inline static MTPchat new_channelForbidden(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title) {
-		return MTPchat(new MTPDchannelForbidden(_id, _access_hash, _title));
+	inline static MTPchat new_channelForbidden(const MTPflags<MTPDchannelForbidden::Flags> &_flags, MTPint _id, const MTPlong &_access_hash, const MTPstring &_title) {
+		return MTPchat(new MTPDchannelForbidden(_flags, _id, _access_hash, _title));
 	}
 	inline static MTPchatFull new_chatFull(MTPint _id, const MTPChatParticipants &_participants, const MTPPhoto &_chat_photo, const MTPPeerNotifySettings &_notify_settings, const MTPExportedChatInvite &_exported_invite, const MTPVector<MTPBotInfo> &_bot_info) {
 		return MTPchatFull(new MTPDchatFull(_id, _participants, _chat_photo, _notify_settings, _exported_invite, _bot_info));
@@ -22589,6 +22621,9 @@ public:
 	inline static MTPmessageAction new_messageActionPinMessage() {
 		return MTPmessageAction(mtpc_messageActionPinMessage);
 	}
+	inline static MTPmessageAction new_messageActionHistoryClear() {
+		return MTPmessageAction(mtpc_messageActionHistoryClear);
+	}
 	inline static MTPdialog new_dialog(const MTPflags<MTPDdialog::Flags> &_flags, const MTPPeer &_peer, MTPint _top_message, MTPint _read_inbox_max_id, MTPint _read_outbox_max_id, MTPint _unread_count, const MTPPeerNotifySettings &_notify_settings, MTPint _pts, const MTPDraftMessage &_draft) {
 		return MTPdialog(new MTPDdialog(_flags, _peer, _top_message, _read_inbox_max_id, _read_outbox_max_id, _unread_count, _notify_settings, _pts, _draft));
 	}
@@ -23552,8 +23587,8 @@ public:
 	inline static MTPdraftMessage new_draftMessageEmpty() {
 		return MTPdraftMessage(mtpc_draftMessageEmpty);
 	}
-	inline static MTPdraftMessage new_draftMessage(const MTPflags<MTPDdraftMessage::Flags> &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities) {
-		return MTPdraftMessage(new MTPDdraftMessage(_flags, _reply_to_msg_id, _message, _entities));
+	inline static MTPdraftMessage new_draftMessage(const MTPflags<MTPDdraftMessage::Flags> &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities, MTPint _date) {
+		return MTPdraftMessage(new MTPDdraftMessage(_flags, _reply_to_msg_id, _message, _entities, _date));
 	}
 	};
 
@@ -25852,7 +25887,7 @@ inline uint32 MTPchat::innerLength() const {
 		}
 		case mtpc_channelForbidden: {
 			const MTPDchannelForbidden &v(c_channelForbidden());
-			return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vtitle.innerLength();
+			return v.vflags.innerLength() + v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vtitle.innerLength();
 		}
 	}
 	return 0;
@@ -25903,6 +25938,7 @@ inline void MTPchat::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId
 		case mtpc_channelForbidden: _type = cons; {
 			if (!data) setData(new MTPDchannelForbidden());
 			MTPDchannelForbidden &v(_channelForbidden());
+			v.vflags.read(from, end);
 			v.vid.read(from, end);
 			v.vaccess_hash.read(from, end);
 			v.vtitle.read(from, end);
@@ -25946,6 +25982,7 @@ inline void MTPchat::write(mtpBuffer &to) const {
 		} break;
 		case mtpc_channelForbidden: {
 			const MTPDchannelForbidden &v(c_channelForbidden());
+			v.vflags.write(to);
 			v.vid.write(to);
 			v.vaccess_hash.write(to);
 			v.vtitle.write(to);
@@ -25986,8 +26023,9 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDchannel::Flags)
 inline MTPchat MTP_channel(const MTPflags<MTPDchannel::Flags> &_flags, MTPint _id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_username, const MTPChatPhoto &_photo, MTPint _date, MTPint _version, const MTPstring &_restriction_reason) {
 	return MTP::internal::TypeCreator::new_channel(_flags, _id, _access_hash, _title, _username, _photo, _date, _version, _restriction_reason);
 }
-inline MTPchat MTP_channelForbidden(MTPint _id, const MTPlong &_access_hash, const MTPstring &_title) {
-	return MTP::internal::TypeCreator::new_channelForbidden(_id, _access_hash, _title);
+Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDchannelForbidden::Flags)
+inline MTPchat MTP_channelForbidden(const MTPflags<MTPDchannelForbidden::Flags> &_flags, MTPint _id, const MTPlong &_access_hash, const MTPstring &_title) {
+	return MTP::internal::TypeCreator::new_channelForbidden(_flags, _id, _access_hash, _title);
 }
 
 inline uint32 MTPchatFull::innerLength() const {
@@ -26694,6 +26732,7 @@ inline void MTPmessageAction::read(const mtpPrime *&from, const mtpPrime *end, m
 			v.vchat_id.read(from, end);
 		} break;
 		case mtpc_messageActionPinMessage: _type = cons; break;
+		case mtpc_messageActionHistoryClear: _type = cons; break;
 		default: throw mtpErrorUnexpected(cons, "MTPmessageAction");
 	}
 }
@@ -26753,6 +26792,7 @@ inline MTPmessageAction::MTPmessageAction(mtpTypeId type) : mtpDataOwner(0), _ty
 		case mtpc_messageActionChatMigrateTo: setData(new MTPDmessageActionChatMigrateTo()); break;
 		case mtpc_messageActionChannelMigrateFrom: setData(new MTPDmessageActionChannelMigrateFrom()); break;
 		case mtpc_messageActionPinMessage: break;
+		case mtpc_messageActionHistoryClear: break;
 		default: throw mtpErrorBadTypeId(type, "MTPmessageAction");
 	}
 }
@@ -26810,6 +26850,9 @@ inline MTPmessageAction MTP_messageActionChannelMigrateFrom(const MTPstring &_ti
 inline MTPmessageAction MTP_messageActionPinMessage() {
 	return MTP::internal::TypeCreator::new_messageActionPinMessage();
 }
+inline MTPmessageAction MTP_messageActionHistoryClear() {
+	return MTP::internal::TypeCreator::new_messageActionHistoryClear();
+}
 
 inline MTPdialog::MTPdialog() : mtpDataOwner(new MTPDdialog()) {
 }
@@ -34814,7 +34857,7 @@ inline uint32 MTPdraftMessage::innerLength() const {
 	switch (_type) {
 		case mtpc_draftMessage: {
 			const MTPDdraftMessage &v(c_draftMessage());
-			return v.vflags.innerLength() + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + v.vmessage.innerLength() + (v.has_entities() ? v.ventities.innerLength() : 0);
+			return v.vflags.innerLength() + (v.has_reply_to_msg_id() ? v.vreply_to_msg_id.innerLength() : 0) + v.vmessage.innerLength() + (v.has_entities() ? v.ventities.innerLength() : 0) + v.vdate.innerLength();
 		}
 	}
 	return 0;
@@ -34834,6 +34877,7 @@ inline void MTPdraftMessage::read(const mtpPrime *&from, const mtpPrime *end, mt
 			if (v.has_reply_to_msg_id()) { v.vreply_to_msg_id.read(from, end); } else { v.vreply_to_msg_id = MTPint(); }
 			v.vmessage.read(from, end);
 			if (v.has_entities()) { v.ventities.read(from, end); } else { v.ventities = MTPVector<MTPMessageEntity>(); }
+			v.vdate.read(from, end);
 		} break;
 		default: throw mtpErrorUnexpected(cons, "MTPdraftMessage");
 	}
@@ -34846,6 +34890,7 @@ inline void MTPdraftMessage::write(mtpBuffer &to) const {
 			if (v.has_reply_to_msg_id()) v.vreply_to_msg_id.write(to);
 			v.vmessage.write(to);
 			if (v.has_entities()) v.ventities.write(to);
+			v.vdate.write(to);
 		} break;
 	}
 }
@@ -34862,8 +34907,8 @@ inline MTPdraftMessage MTP_draftMessageEmpty() {
 	return MTP::internal::TypeCreator::new_draftMessageEmpty();
 }
 Q_DECLARE_OPERATORS_FOR_FLAGS(MTPDdraftMessage::Flags)
-inline MTPdraftMessage MTP_draftMessage(const MTPflags<MTPDdraftMessage::Flags> &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities) {
-	return MTP::internal::TypeCreator::new_draftMessage(_flags, _reply_to_msg_id, _message, _entities);
+inline MTPdraftMessage MTP_draftMessage(const MTPflags<MTPDdraftMessage::Flags> &_flags, MTPint _reply_to_msg_id, const MTPstring &_message, const MTPVector<MTPMessageEntity> &_entities, MTPint _date) {
+	return MTP::internal::TypeCreator::new_draftMessage(_flags, _reply_to_msg_id, _message, _entities, _date);
 }
 inline MTPDmessage::Flags mtpCastFlags(MTPDmessageService::Flags flags) { return MTPDmessage::Flags(QFlag(flags)); }
 inline MTPDmessage::Flags mtpCastFlags(MTPflags<MTPDmessageService::Flags> flags) { return mtpCastFlags(flags.v); }
@@ -34881,6 +34926,8 @@ inline MTPDpeerNotifySettings::Flags mtpCastFlags(MTPDinputPeerNotifySettings::F
 inline MTPDpeerNotifySettings::Flags mtpCastFlags(MTPflags<MTPDinputPeerNotifySettings::Flags> flags) { return mtpCastFlags(flags.v); }
 inline MTPDinputPeerNotifySettings::Flags mtpCastFlags(MTPDpeerNotifySettings::Flags flags) { return MTPDinputPeerNotifySettings::Flags(QFlag(flags)); }
 inline MTPDinputPeerNotifySettings::Flags mtpCastFlags(MTPflags<MTPDpeerNotifySettings::Flags> flags) { return mtpCastFlags(flags.v); }
+inline MTPDchannel::Flags mtpCastFlags(MTPDchannelForbidden::Flags flags) { return MTPDchannel::Flags(QFlag(flags)); }
+inline MTPDchannel::Flags mtpCastFlags(MTPflags<MTPDchannelForbidden::Flags> flags) { return mtpCastFlags(flags.v); }
 
 // 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/ui/buttons/history_down_button.cpp b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp
index 8d1135757e..fd0c5d8974 100644
--- a/Telegram/SourceFiles/ui/buttons/history_down_button.cpp
+++ b/Telegram/SourceFiles/ui/buttons/history_down_button.cpp
@@ -22,6 +22,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
 #include "ui/buttons/history_down_button.h"
 
 #include "styles/style_history.h"
+#include "dialogs/dialogs_layout.h"
 
 namespace Ui {
 
@@ -29,16 +30,25 @@ HistoryDownButton::HistoryDownButton(QWidget *parent) : Button(parent)
 , a_arrowOpacity(st::btnAttachEmoji.opacity, st::btnAttachEmoji.opacity)
 , _a_arrowOver(animation(this, &HistoryDownButton::step_arrowOver)) {
 	setCursor(style::cur_pointer);
-	resize(st::historyToDown.width(), st::historyToDown.height());
+	resize(st::historyToDown.width(), st::historyToDownPaddingTop + st::historyToDown.height());
 
 	connect(this, SIGNAL(stateChanged(int,ButtonStateChangeSource)), this, SLOT(onStateChange(int,ButtonStateChangeSource)));
 }
 
 void HistoryDownButton::paintEvent(QPaintEvent *e) {
 	Painter p(this);
-	st::historyToDown.paint(p, QPoint(0, 0), width());
+	st::historyToDown.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
 	p.setOpacity(a_arrowOpacity.current());
-	st::historyToDownArrow.paint(p, QPoint(0, 0), width());
+	st::historyToDownArrow.paint(p, QPoint(0, st::historyToDownPaddingTop), width());
+	if (_unreadCount > 0) {
+		p.setOpacity(1);
+		bool active = false, muted = false;
+		auto unreadString = QString::number(_unreadCount);
+		if (unreadString.size() > 4) {
+			unreadString = qsl("..") + unreadString.mid(unreadString.size() - 4);
+		}
+		Dialogs::Layout::paintUnreadCount(p, unreadString, width(), 0, style::al_center, active, muted, nullptr);
+	}
 }
 
 void HistoryDownButton::onStateChange(int oldState, ButtonStateChangeSource source) {
@@ -53,6 +63,11 @@ void HistoryDownButton::onStateChange(int oldState, ButtonStateChangeSource sour
 	}
 }
 
+void HistoryDownButton::setUnreadCount(int unreadCount) {
+	_unreadCount = unreadCount;
+	update();
+}
+
 void HistoryDownButton::step_arrowOver(float64 ms, bool timer) {
 	float64 dt = ms / st::btnAttachEmoji.duration;
 	if (dt >= 1) {
diff --git a/Telegram/SourceFiles/ui/buttons/history_down_button.h b/Telegram/SourceFiles/ui/buttons/history_down_button.h
index c472439ab9..849e14d4fa 100644
--- a/Telegram/SourceFiles/ui/buttons/history_down_button.h
+++ b/Telegram/SourceFiles/ui/buttons/history_down_button.h
@@ -30,6 +30,11 @@ class HistoryDownButton : public Button {
 public:
 	HistoryDownButton(QWidget *parent);
 
+	void setUnreadCount(int unreadCount);
+	int unreadCount() const {
+		return _unreadCount;
+	}
+
 protected:
 	void paintEvent(QPaintEvent *e) override;
 
@@ -42,6 +47,8 @@ private:
 	anim::fvalue a_arrowOpacity;
 	Animation _a_arrowOver;
 
+	int _unreadCount = 0;
+
 };
 
 } // namespace Ui