From d18164bc518e49986cf848b4db97acde0b036950 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Wed, 19 Apr 2017 12:44:07 +0300
Subject: [PATCH] Add Calls::Instance. Add libtgvoip as a dependency.

Also move all submodules to Telegram/ThirdParty.
---
 .gitmodules                                   |  13 +-
 Telegram/SourceFiles/auth_session.cpp         |   2 +
 Telegram/SourceFiles/auth_session.h           |   9 +
 Telegram/SourceFiles/base/weak_unique_ptr.h   |  12 +
 Telegram/SourceFiles/calls/calls_instance.cpp | 248 ++++++++++++++++++
 Telegram/SourceFiles/calls/calls_instance.h   |  68 +++++
 Telegram/SourceFiles/mainwidget.cpp           |   3 +-
 Telegram/ThirdParty/GSL                       |   1 +
 Telegram/ThirdParty/libtgvoip                 |   1 +
 Telegram/ThirdParty/variant                   |   1 +
 Telegram/gyp/Telegram.gyp                     |  10 +-
 Telegram/gyp/common.gypi                      |   2 +-
 Telegram/gyp/official.py                      |  36 ---
 Telegram/gyp/qt.gypi                          |   2 +-
 Telegram/gyp/refresh.bat                      |  10 +-
 Telegram/gyp/refresh.sh                       |  12 +-
 Telegram/gyp/settings_win.gypi                |  38 +--
 Telegram/gyp/telegram_sources.txt             |   2 +
 third_party/GSL                               |   1 -
 third_party/variant                           |   1 -
 20 files changed, 399 insertions(+), 73 deletions(-)
 create mode 100644 Telegram/SourceFiles/calls/calls_instance.cpp
 create mode 100644 Telegram/SourceFiles/calls/calls_instance.h
 create mode 160000 Telegram/ThirdParty/GSL
 create mode 160000 Telegram/ThirdParty/libtgvoip
 create mode 160000 Telegram/ThirdParty/variant
 delete mode 100644 Telegram/gyp/official.py
 delete mode 160000 third_party/GSL
 delete mode 160000 third_party/variant

diff --git a/.gitmodules b/.gitmodules
index 570f29fe2..874ea8efc 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,9 @@
-[submodule "third_party/GSL"]
-	path = third_party/GSL
-	url = https://github.com/Microsoft/GSL.git
-[submodule "third_party/variant"]
-	path = third_party/variant
+[submodule "Telegram/ThirdParty/libtgvoip"]
+	path = Telegram/ThirdParty/libtgvoip
+	url = https://github.com/telegramdesktop/libtgvoip
+[submodule "Telegram/ThirdParty/variant"]
+	path = Telegram/ThirdParty/variant
 	url = https://github.com/mapbox/variant
+[submodule "Telegram/ThirdParty/GSL"]
+	path = Telegram/ThirdParty/GSL
+	url = https://github.com/Microsoft/GSL.git
diff --git a/Telegram/SourceFiles/auth_session.cpp b/Telegram/SourceFiles/auth_session.cpp
index 1c8852b76..66372fbf4 100644
--- a/Telegram/SourceFiles/auth_session.cpp
+++ b/Telegram/SourceFiles/auth_session.cpp
@@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "storage/localstorage.h"
 #include "window/notifications_manager.h"
 #include "platform/platform_specific.h"
+#include "calls/calls_instance.h"
 
 namespace {
 
@@ -92,6 +93,7 @@ AuthSession::AuthSession(UserId userId)
 : _userId(userId)
 , _autoLockTimer([this] { checkAutoLock(); })
 , _api(std::make_unique<ApiWrap>())
+, _calls(std::make_unique<Calls::Instance>())
 , _downloader(std::make_unique<Storage::Downloader>())
 , _notifications(std::make_unique<Window::Notifications::System>(this)) {
 	Expects(_userId != 0);
diff --git a/Telegram/SourceFiles/auth_session.h b/Telegram/SourceFiles/auth_session.h
index e8636d7e8..dda8b7164 100644
--- a/Telegram/SourceFiles/auth_session.h
+++ b/Telegram/SourceFiles/auth_session.h
@@ -32,6 +32,10 @@ class System;
 } // namespace Notifications
 } // namespace Window
 
+namespace Calls {
+class Instance;
+} // namespace Calls
+
 class ApiWrap;
 
 enum class EmojiPanelTab {
@@ -144,6 +148,10 @@ public:
 		return *_api;
 	}
 
+	Calls::Instance &calls() {
+		return *_calls;
+	}
+
 	void checkAutoLock();
 	void checkAutoLockIn(TimeMs time);
 
@@ -158,6 +166,7 @@ private:
 	base::Timer _autoLockTimer;
 
 	const std::unique_ptr<ApiWrap> _api;
+	const std::unique_ptr<Calls::Instance> _calls;
 	const std::unique_ptr<Storage::Downloader> _downloader;
 	const std::unique_ptr<Window::Notifications::System> _notifications;
 
diff --git a/Telegram/SourceFiles/base/weak_unique_ptr.h b/Telegram/SourceFiles/base/weak_unique_ptr.h
index b29a9be8f..ce0b7b8ce 100644
--- a/Telegram/SourceFiles/base/weak_unique_ptr.h
+++ b/Telegram/SourceFiles/base/weak_unique_ptr.h
@@ -86,3 +86,15 @@ private:
 };
 
 } // namespace base
+
+#ifdef QT_VERSION
+template <typename Lambda>
+inline void InvokeQueued(base::enable_weak_from_this *context, Lambda &&lambda) {
+	QObject proxy;
+	QObject::connect(&proxy, &QObject::destroyed, QCoreApplication::instance(), [guard = base::weak_unique_ptr<base::enable_weak_from_this>(context), lambda = std::forward<Lambda>(lambda)] {
+		if (guard) {
+			lambda();
+		}
+	}, Qt::QueuedConnection);
+}
+#endif // QT_VERSION
diff --git a/Telegram/SourceFiles/calls/calls_instance.cpp b/Telegram/SourceFiles/calls/calls_instance.cpp
new file mode 100644
index 000000000..679f54101
--- /dev/null
+++ b/Telegram/SourceFiles/calls/calls_instance.cpp
@@ -0,0 +1,248 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop version of Telegram messaging app, see https://telegram.org
+
+Telegram Desktop is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+It is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program with the OpenSSL library.
+
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
+*/
+#include "calls/calls_instance.h"
+
+#include "mtproto/connection.h"
+#include "auth_session.h"
+
+#include <openssl/bn.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+
+#ifdef slots
+#undef slots
+#define NEED_TO_RESTORE_SLOTS
+#endif // slots
+
+#include <VoIPController.h>
+#include <VoIPServerConfig.h>
+
+#ifdef NEED_TO_RESTORE_SLOTS
+#define slots Q_SLOTS
+#undef NEED_TO_RESTORE_SLOTS
+#endif // NEED_TO_RESTORE_SLOTS
+
+namespace Calls {
+namespace {
+
+constexpr auto kMinLayer = 65;
+constexpr auto kMaxLayer = 65; // MTP::CurrentLayer?
+
+using tgvoip::Endpoint;
+
+void ConvertEndpoint(std::vector<tgvoip::Endpoint> &ep, const MTPDphoneConnection &mtc) {
+	if (mtc.vpeer_tag.v.length() != 16)
+		return;
+	auto ipv4 = tgvoip::IPv4Address(std::string(mtc.vip.v.constData(), mtc.vip.v.size()));
+	auto ipv6 = tgvoip::IPv6Address(std::string(mtc.vipv6.v.constData(), mtc.vipv6.v.size()));
+	ep.push_back(Endpoint((int64_t)mtc.vid.v, (uint16_t)mtc.vport.v, ipv4, ipv6, EP_TYPE_UDP_RELAY, (unsigned char*)mtc.vpeer_tag.v.data()));
+}
+
+} // namespace
+
+Instance::Instance() = default;
+
+void Instance::startOutgoingCall(gsl::not_null<UserData*> user) {
+	if (_controller) {
+		return; // Already in a call.
+	}
+
+	_controller = std::make_unique<tgvoip::VoIPController>();
+	request(MTPmessages_GetDhConfig(MTP_int(_dhConfigVersion), MTP_int(256))).done([this, user](const MTPmessages_DhConfig &result) {
+		auto random = QByteArray();
+		switch (result.type()) {
+		case mtpc_messages_dhConfig: {
+			auto &config = result.c_messages_dhConfig();
+			if (!MTP::IsPrimeAndGood(config.vp.v, config.vg.v)) {
+				LOG(("API Error: bad p/g received in dhConfig."));
+				callFailed();
+				return;
+			}
+			_dhConfigG = config.vg.v;
+			_dhConfigP = config.vp.v;
+			random = qba(config.vrandom);
+		} break;
+
+		case mtpc_messages_dhConfigNotModified: {
+			auto &config = result.c_messages_dhConfigNotModified();
+			random = qba(config.vrandom);
+			if (!_dhConfigG || _dhConfigP.isEmpty()) {
+				LOG(("API Error: dhConfigNotModified on zero version."));
+				callFailed();
+				return;
+			}
+		} break;
+
+		default: Unexpected("Type in messages.getDhConfig");
+		}
+		if (random.size() != kSaltSize) {
+			LOG(("API Error: dhConfig random bytes wrong size: %1").arg(random.size()));
+			callFailed();
+			return;
+		}
+
+		auto randomBytes = reinterpret_cast<const unsigned char*>(random.constData());
+		RAND_bytes(_salt.data(), kSaltSize);
+		for (auto i = 0; i != kSaltSize; i++) {
+			_salt[i] ^= randomBytes[i];
+		}
+		BN_CTX* ctx = BN_CTX_new();
+		BN_CTX_init(ctx);
+		BIGNUM i_g_a;
+		BN_init(&i_g_a);
+		BN_set_word(&i_g_a, _dhConfigG);
+		BIGNUM tmp;
+		BN_init(&tmp);
+		BIGNUM saltBN;
+		BN_init(&saltBN);
+		BN_bin2bn(_salt.data(), kSaltSize, &saltBN);
+		BIGNUM pbytesBN;
+		BN_init(&pbytesBN);
+		BN_bin2bn(reinterpret_cast<const unsigned char*>(_dhConfigP.constData()), _dhConfigP.size(), &pbytesBN);
+		BN_mod_exp(&tmp, &i_g_a, &saltBN, &pbytesBN, ctx);
+		auto g_a_length = BN_num_bytes(&tmp);
+		_g_a = QByteArray(g_a_length, Qt::Uninitialized);
+		BN_bn2bin(&tmp, reinterpret_cast<unsigned char*>(_g_a.data()));
+		constexpr auto kMaxGASize = 256;
+		if (g_a_length > kMaxGASize) {
+			_g_a = _g_a.mid(1, kMaxGASize);
+		}
+		BN_CTX_free(ctx);
+
+		auto randomID = rand_value<int32>();
+		QByteArray g_a_hash;
+		g_a_hash.resize(SHA256_DIGEST_LENGTH);
+		SHA256(reinterpret_cast<const unsigned char*>(_g_a.constData()), _g_a.size(), reinterpret_cast<unsigned char*>(g_a_hash.data()));
+
+		request(MTPphone_RequestCall(user->inputUser, MTP_int(randomID), MTP_bytes(g_a_hash), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
+			Expects(result.type() == mtpc_phone_phoneCall);
+			auto &call = result.c_phone_phoneCall();
+			App::feedUsers(call.vusers);
+			if (call.vphone_call.type() != mtpc_phoneCallWaiting) {
+				LOG(("API Error: Expected phoneCallWaiting in response to phone.requestCall()"));
+				callFailed();
+				return;
+			}
+			auto &phoneCall = call.vphone_call.c_phoneCallWaiting();
+			_callId = phoneCall.vid.v;
+			_accessHash = phoneCall.vaccess_hash.v;
+		}).fail([this](const RPCError &error) {
+			callFailed();
+		}).send();
+	}).fail([this](const RPCError &error) {
+		callFailed();
+	}).send();
+}
+
+void Instance::handleUpdate(const MTPDupdatePhoneCall& update) {
+	// TODO check call id
+	switch (update.vphone_call.type()) {
+	case mtpc_phoneCallAccepted: {
+		// state changed STATE_EXCHANGING_KEYS
+		auto &call = update.vphone_call.c_phoneCallAccepted();
+		// TODO check isGoodGaAndGb
+
+		BN_CTX *ctx = BN_CTX_new();
+		BN_CTX_init(ctx);
+		BIGNUM p;
+		BIGNUM i_authKey;
+		BIGNUM res;
+		BIGNUM salt;
+		BN_init(&p);
+		BN_init(&i_authKey);
+		BN_init(&res);
+		BN_init(&salt);
+		BN_bin2bn(reinterpret_cast<const unsigned char*>(_dhConfigP.constData()), _dhConfigP.size(), &p);
+		BN_bin2bn((const unsigned char*)call.vg_b.v.constData(), call.vg_b.v.length(), &i_authKey);
+		BN_bin2bn(_salt.data(), kSaltSize, &salt);
+
+		BN_mod_exp(&res, &i_authKey, &salt, &p, ctx);
+		BN_CTX_free(ctx);
+		auto realAuthKeyLength = BN_num_bytes(&res);
+		auto realAuthKeyBytes = QByteArray(realAuthKeyLength, Qt::Uninitialized);
+		BN_bn2bin(&res, reinterpret_cast<unsigned char*>(realAuthKeyBytes.data()));
+
+		if (realAuthKeyLength > kAuthKeySize) {
+			memcpy(_authKey.data(), realAuthKeyBytes.constData() + (realAuthKeyLength - kAuthKeySize), kAuthKeySize);
+		} else if (realAuthKeyLength < kAuthKeySize) {
+			memset(_authKey.data(), 0, kAuthKeySize - realAuthKeyLength);
+			memcpy(_authKey.data() + (kAuthKeySize - realAuthKeyLength), realAuthKeyBytes.constData(), realAuthKeyLength);
+		} else {
+			memcpy(_authKey.data(), realAuthKeyBytes.constData(), kAuthKeySize);
+		}
+
+		unsigned char authKeyHash[SHA_DIGEST_LENGTH];
+		SHA1(_authKey.data(), _authKey.size(), authKeyHash);
+
+		_keyFingerprint = ((uint64)authKeyHash[19] << 56)
+			| ((uint64)authKeyHash[18] << 48)
+			| ((uint64)authKeyHash[17] << 40)
+			| ((uint64)authKeyHash[16] << 32)
+			| ((uint64)authKeyHash[15] << 24)
+			| ((uint64)authKeyHash[14] << 16)
+			| ((uint64)authKeyHash[13] << 8)
+			| ((uint64)authKeyHash[12]);
+
+		request(MTPphone_ConfirmCall(MTP_inputPhoneCall(MTP_long(_callId), MTP_long(_accessHash)), MTP_bytes(_g_a), MTP_long(_keyFingerprint), MTP_phoneCallProtocol(MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p | MTPDphoneCallProtocol::Flag::f_udp_reflector), MTP_int(kMinLayer), MTP_int(kMaxLayer)))).done([this](const MTPphone_PhoneCall &result) {
+			auto &call = result.c_phone_phoneCall().vphone_call.c_phoneCall();
+
+			std::vector<Endpoint> endpoints;
+			ConvertEndpoint(endpoints, call.vconnection.c_phoneConnection());
+			for (int i = 0; i < call.valternative_connections.v.length(); i++) {
+				ConvertEndpoint(endpoints, call.valternative_connections.v[i].c_phoneConnection());
+			}
+			_controller->SetRemoteEndpoints(endpoints, true);
+
+			initiateActualCall();
+		}).fail([this](const RPCError &error) {
+			callFailed();
+		}).send();
+	} break;
+	}
+}
+
+void Instance::callFailed() {
+	InvokeQueued(this, [this] {
+		_controller.reset();
+	});
+}
+
+void Instance::initiateActualCall() {
+	voip_config_t config;
+	config.data_saving = DATA_SAVING_NEVER;
+	config.enableAEC = true;
+	config.enableNS = true;
+	config.enableAGC = true;
+	config.init_timeout = 30;
+	config.recv_timeout = 10;
+	_controller->SetConfig(&config);
+	_controller->SetEncryptionKey(reinterpret_cast<char*>(_authKey.data()), true);
+	_controller->Start();
+	_controller->Connect();
+}
+
+Instance::~Instance() = default;
+
+Instance &Current() {
+	return AuthSession::Current().calls();
+}
+
+} // namespace Calls
diff --git a/Telegram/SourceFiles/calls/calls_instance.h b/Telegram/SourceFiles/calls/calls_instance.h
new file mode 100644
index 000000000..50f1cd40e
--- /dev/null
+++ b/Telegram/SourceFiles/calls/calls_instance.h
@@ -0,0 +1,68 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop version of Telegram messaging app, see https://telegram.org
+
+Telegram Desktop is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+It is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program with the OpenSSL library.
+
+Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
+Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
+*/
+#pragma once
+
+#include "mtproto/sender.h"
+#include "base/weak_unique_ptr.h"
+
+class AuthSession;
+
+namespace tgvoip {
+class VoIPController;
+} // namespace tgvoip
+
+namespace Calls {
+
+class Instance : public base::enable_weak_from_this, private MTP::Sender {
+public:
+	Instance();
+
+	void startOutgoingCall(gsl::not_null<UserData*> user);
+
+	void handleUpdate(const MTPDupdatePhoneCall &update);
+
+	~Instance();
+
+private:
+	void initiateActualCall();
+	void callFailed();
+
+	static constexpr auto kSaltSize = 256;
+	static constexpr auto kAuthKeySize = 256;
+
+	int32 _dhConfigVersion = 0;
+	int32 _dhConfigG = 0;
+	QByteArray _dhConfigP;
+
+	QByteArray _g_a;
+	std::array<unsigned char, kSaltSize> _salt;
+	std::array<unsigned char, kAuthKeySize> _authKey;
+	uint64 _callId = 0;
+	uint64 _accessHash = 0;
+	uint64 _keyFingerprint = 0;
+
+	std::unique_ptr<tgvoip::VoIPController> _controller;
+
+};
+
+Instance &Current();
+
+} // namespace Calls
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index ce9223b35..e189ef656 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -67,6 +67,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 #include "auth_session.h"
 #include "window/notifications_manager.h"
 #include "window/window_controller.h"
+#include "calls/calls_instance.h"
 
 StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
 , _memento(std::move(memento)) {
@@ -4854,7 +4855,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
 	} break;
 
 	case mtpc_updatePhoneCall: {
-		auto &d = update.c_updatePhoneCall();
+		Calls::Current().handleUpdate(update.c_updatePhoneCall());
 	} break;
 
 	case mtpc_updateUserBlocked: {
diff --git a/Telegram/ThirdParty/GSL b/Telegram/ThirdParty/GSL
new file mode 160000
index 000000000..c5851a816
--- /dev/null
+++ b/Telegram/ThirdParty/GSL
@@ -0,0 +1 @@
+Subproject commit c5851a8161938798c5594a66420cb814fea92711
diff --git a/Telegram/ThirdParty/libtgvoip b/Telegram/ThirdParty/libtgvoip
new file mode 160000
index 000000000..ccf715b62
--- /dev/null
+++ b/Telegram/ThirdParty/libtgvoip
@@ -0,0 +1 @@
+Subproject commit ccf715b626246990bf57068102bc04014f4ac385
diff --git a/Telegram/ThirdParty/variant b/Telegram/ThirdParty/variant
new file mode 160000
index 000000000..550ac2f15
--- /dev/null
+++ b/Telegram/ThirdParty/variant
@@ -0,0 +1 @@
+Subproject commit 550ac2f159ca883d360c196149b466955c77a573
diff --git a/Telegram/gyp/Telegram.gyp b/Telegram/gyp/Telegram.gyp
index 5b7ead4df..cee607fe8 100644
--- a/Telegram/gyp/Telegram.gyp
+++ b/Telegram/gyp/Telegram.gyp
@@ -30,10 +30,9 @@
       'libs_loc': '<(libs_loc)',
       'src_loc': '../SourceFiles',
       'res_loc': '../Resources',
-      'submodules_loc': '../../third_party',
-      'third_party_loc': '../ThirdParty',
-      'minizip_loc': '<(third_party_loc)/minizip',
-      'sp_media_key_tap_loc': '<(third_party_loc)/SPMediaKeyTap',
+      'submodules_loc': '../ThirdParty',
+      'minizip_loc': '<(submodules_loc)/minizip',
+      'sp_media_key_tap_loc': '<(submodules_loc)/SPMediaKeyTap',
       'style_files': [
         '<(res_loc)/colors.palette',
         '<(res_loc)/basic.style',
@@ -79,10 +78,12 @@
       'codegen.gyp:codegen_numbers',
       'codegen.gyp:codegen_style',
       'utils.gyp:Updater',
+      '../ThirdParty/libtgvoip/libtgvoip.gyp:libtgvoip',
     ],
 
     'defines': [
       'AL_LIBTYPE_STATIC',
+      'TGVOIP_USE_CXX11_LIB',
       '<!@(python -c "for s in \'<(build_defines)\'.split(\',\'): print(s)")',
     ],
 
@@ -95,6 +96,7 @@
       '<(libs_loc)/zlib-1.2.8',
       '<(libs_loc)/ffmpeg',
       '<(libs_loc)/openal-soft/include',
+      '<(libs_loc)/opus/include',
       '<(minizip_loc)',
       '<(sp_media_key_tap_loc)',
       '<(submodules_loc)/GSL/include',
diff --git a/Telegram/gyp/common.gypi b/Telegram/gyp/common.gypi
index ca73a899c..9d9e67a37 100644
--- a/Telegram/gyp/common.gypi
+++ b/Telegram/gyp/common.gypi
@@ -59,7 +59,7 @@
       'build_mac%': '<(build_mac)',
       'build_linux%': '<(build_linux)',
 
-      'official_build_target%': '<!(python <(DEPTH)/official.py --read-target)',
+      'official_build_target%': '',
     },
     'build_os%': '<(build_os)',
     'build_win%': '<(build_win)',
diff --git a/Telegram/gyp/official.py b/Telegram/gyp/official.py
deleted file mode 100644
index c91df04f2..000000000
--- a/Telegram/gyp/official.py
+++ /dev/null
@@ -1,36 +0,0 @@
-'''
-This file is part of Telegram Desktop,
-the official desktop version of Telegram messaging app, see https://telegram.org
-
-Telegram Desktop is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-It is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-In addition, as a special exception, the copyright holders give permission
-to link the code of portions of this program with the OpenSSL library.
-
-Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
-Copyright (c) 2014 John Preston, https://desktop.telegram.org
-'''
-import sys
-import os
-import re
-
-my_path = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/')
-
-if len(sys.argv) > 1 and sys.argv[1] == '--read-target':
-  target_path = my_path + '/../build/target'
-  if os.path.isfile(target_path):
-    with open(target_path) as f:
-      for line in f:
-        cleanline = re.sub(r'^\s*|\s*$', '', line);
-        if cleanline != '':
-          print(cleanline);
-else:
-  print('This is a helper script, it should not be called directly.')
diff --git a/Telegram/gyp/qt.gypi b/Telegram/gyp/qt.gypi
index c12e450b0..81c13a182 100644
--- a/Telegram/gyp/qt.gypi
+++ b/Telegram/gyp/qt.gypi
@@ -130,7 +130,7 @@
     'qt_version%': '<(qt_version)',
     'conditions': [
       [ 'build_win', {
-        'qt_loc': '../../../Libraries/qt<(qt_version_loc)/qtbase',
+        'qt_loc': '<(DEPTH)/../../../Libraries/qt<(qt_version_loc)/qtbase',
       }, {
         'qt_loc': '<(qt_loc_unix)',
       }],
diff --git a/Telegram/gyp/refresh.bat b/Telegram/gyp/refresh.bat
index 78caadc88..4f29651c7 100644
--- a/Telegram/gyp/refresh.bat
+++ b/Telegram/gyp/refresh.bat
@@ -6,6 +6,12 @@ set "FullExecPath=%cd%"
 set "Silence=>nul"
 if "%1" == "-v" set "Silence="
 
+if exist "%FullScriptPath%..\build\target" (
+  FOR /F "tokens=1* delims= " %%i in (%FullScriptPath%..\build\target) do set "BuildTarget=%%i"
+) else (
+  set "BuildTarget="
+)
+
 rem strangely linking of Release Telegram build complains about the absence of lib.pdb
 if exist "%FullScriptPath%..\..\..\Libraries\openssl\tmp32\lib.pdb" (
   if not exist "%FullScriptPath%..\..\..\Libraries\openssl\Release\lib\lib.pdb" (
@@ -22,9 +28,9 @@ if not "%TDESKTOP_BUILD_DEFINES%" == "" (
 set GYP_MSVS_VERSION=2015
 
 cd "%FullScriptPath%"
-call gyp --depth=. --generator-output=../.. -Goutput_dir=out !BUILD_DEFINES! Telegram.gyp --format=ninja
+call gyp --depth=. --generator-output=../.. -Goutput_dir=out !BUILD_DEFINES! -Dofficial_build_target=%BuildTarget% Telegram.gyp --format=ninja
 if %errorlevel% neq 0 goto error
-call gyp --depth=. --generator-output=../.. -Goutput_dir=out !BUILD_DEFINES! Telegram.gyp --format=msvs-ninja
+call gyp --depth=. --generator-output=../.. -Goutput_dir=out !BUILD_DEFINES! -Dofficial_build_target=%BuildTarget% Telegram.gyp --format=msvs-ninja
 if %errorlevel% neq 0 goto error
 cd ../..
 
diff --git a/Telegram/gyp/refresh.sh b/Telegram/gyp/refresh.sh
index 87f16da88..cd96456c9 100755
--- a/Telegram/gyp/refresh.sh
+++ b/Telegram/gyp/refresh.sh
@@ -5,11 +5,19 @@ pushd `dirname $0` > /dev/null
 FullScriptPath=`pwd`
 popd > /dev/null
 
+if [ -f "$FullScriptPath/../build/target" ]; then
+  while IFS='' read -r line || [[ -n "$line" ]]; do
+    BuildTarget="$line"
+  done < "$FullScriptPath/../build/target"
+else
+  BuildTarget=""
+fi
+
 MySystem=`uname -s`
 cd $FullScriptPath
 
 if [ "$MySystem" == "Linux" ]; then
-  ../../../Libraries/gyp/gyp --depth=. --generator-output=../.. -Goutput_dir=out Telegram.gyp --format=cmake
+  ../../../Libraries/gyp/gyp --depth=. --generator-output=../.. -Goutput_dir=out -Dofficial_build_target=$BuildTarget Telegram.gyp --format=cmake
   cd ../../out/Debug
   ../../../Libraries/cmake-3.6.2/bin/cmake .
   cd ../Release
@@ -20,7 +28,7 @@ else
   #gyp --depth=. --generator-output=../.. -Goutput_dir=out Telegram.gyp --format=xcode-ninja
   #gyp --depth=. --generator-output=../.. -Goutput_dir=out Telegram.gyp --format=xcode
   # use patched gyp with Xcode project generator
-  ../../../Libraries/gyp/gyp --depth=. --generator-output=../.. -Goutput_dir=out Telegram.gyp -Gxcode_upgrade_check_project_version=830 --format=xcode
+  ../../../Libraries/gyp/gyp --depth=. --generator-output=../.. -Goutput_dir=out -Gxcode_upgrade_check_project_version=830 -Dofficial_build_target=$BuildTarget Telegram.gyp --format=xcode
 fi
 
 cd ../..
diff --git a/Telegram/gyp/settings_win.gypi b/Telegram/gyp/settings_win.gypi
index 2bcb0797e..521a850ce 100644
--- a/Telegram/gyp/settings_win.gypi
+++ b/Telegram/gyp/settings_win.gypi
@@ -55,25 +55,25 @@
         '$(ProjectName)',
       ],
       'libraries': [
-        'winmm',
-        'imm32',
-        'ws2_32',
-        'kernel32',
-        'user32',
-        'gdi32',
-        'winspool',
-        'comdlg32',
-        'advapi32',
-        'shell32',
-        'ole32',
-        'oleaut32',
-        'uuid',
-        'odbc32',
-        'odbccp32',
-        'Shlwapi',
-        'Iphlpapi',
-        'Gdiplus',
-        'Strmiids',
+        '-lwinmm',
+        '-limm32',
+        '-lws2_32',
+        '-lkernel32',
+        '-luser32',
+        '-lgdi32',
+        '-lwinspool',
+        '-lcomdlg32',
+        '-ladvapi32',
+        '-lshell32',
+        '-lole32',
+        '-loleaut32',
+        '-luuid',
+        '-lodbc32',
+        '-lodbccp32',
+        '-lShlwapi',
+        '-lIphlpapi',
+        '-lGdiplus',
+        '-lStrmiids',
       ],
 
       'configurations': {
diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt
index a08b77b7d..c52b38268 100644
--- a/Telegram/gyp/telegram_sources.txt
+++ b/Telegram/gyp/telegram_sources.txt
@@ -79,6 +79,8 @@
 <(src_loc)/boxes/stickers_box.h
 <(src_loc)/boxes/username_box.cpp
 <(src_loc)/boxes/username_box.h
+<(src_loc)/calls/calls_instance.cpp
+<(src_loc)/calls/calls_instance.h
 <(src_loc)/chat_helpers/bot_keyboard.cpp
 <(src_loc)/chat_helpers/bot_keyboard.h
 <(src_loc)/chat_helpers/emoji_list_widget.cpp
diff --git a/third_party/GSL b/third_party/GSL
deleted file mode 160000
index f9c47dd63..000000000
--- a/third_party/GSL
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit f9c47dd63fe25cc216294fbe7e2fbe4f9a302ca3
diff --git a/third_party/variant b/third_party/variant
deleted file mode 160000
index 916139a2e..000000000
--- a/third_party/variant
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 916139a2e51e125816efce6e19d428385601273f