summaryrefslogtreecommitdiff
path: root/protocols/Telegram/tdlib/td/example
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2018-04-27 21:33:17 +0300
committeraunsane <aunsane@gmail.com>2018-04-27 21:33:17 +0300
commite1ec72eab6d00b3ba38e5932bc88920f103b6e4a (patch)
tree999de2725a83e30fbbf6576200525d4ef0c5fe38 /protocols/Telegram/tdlib/td/example
parentb9ce1d4d98525490ca1a38e2d9fd4f3369adb3e0 (diff)
Telegram: initial commit
- tdlib moved to telegram dir
Diffstat (limited to 'protocols/Telegram/tdlib/td/example')
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/.gitignore1
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt13
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/README.md24
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/td_example.cpp308
-rw-r--r--protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp33
-rw-r--r--protocols/Telegram/tdlib/td/example/csharp/.gitignore5
-rw-r--r--protocols/Telegram/tdlib/td/example/csharp/README.md32
-rw-r--r--protocols/Telegram/tdlib/td/example/csharp/TdExample.cs270
-rw-r--r--protocols/Telegram/tdlib/td/example/csharp/TdExample.csproj85
-rw-r--r--protocols/Telegram/tdlib/td/example/go/main.go26
-rw-r--r--protocols/Telegram/tdlib/td/example/ios/README.md41
-rw-r--r--protocols/Telegram/tdlib/td/example/ios/build-openssl.sh22
-rw-r--r--protocols/Telegram/tdlib/td/example/ios/build.sh74
-rw-r--r--protocols/Telegram/tdlib/td/example/java/.gitignore5
-rw-r--r--protocols/Telegram/tdlib/td/example/java/CMakeLists.txt68
-rw-r--r--protocols/Telegram/tdlib/td/example/java/README.md39
-rw-r--r--protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java285
-rw-r--r--protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java75
-rw-r--r--protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java533
-rw-r--r--protocols/Telegram/tdlib/td/example/java/td_jni.cpp158
-rw-r--r--protocols/Telegram/tdlib/td/example/python/README.md11
-rw-r--r--protocols/Telegram/tdlib/td/example/python/tdjson_example.py106
-rw-r--r--protocols/Telegram/tdlib/td/example/ruby/Gemfile3
-rw-r--r--protocols/Telegram/tdlib/td/example/ruby/Gemfile.lock17
-rw-r--r--protocols/Telegram/tdlib/td/example/ruby/example.rb61
-rw-r--r--protocols/Telegram/tdlib/td/example/swift/.gitignore3
-rw-r--r--protocols/Telegram/tdlib/td/example/swift/README.md15
-rw-r--r--protocols/Telegram/tdlib/td/example/swift/src/main.swift178
-rw-r--r--protocols/Telegram/tdlib/td/example/swift/src/td-Bridging-Header.h15
-rw-r--r--protocols/Telegram/tdlib/td/example/swift/td.xcodeproj/project.pbxproj310
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/LICENSE_1_0.txt23
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/README.md28
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/SDKManifest.xml12
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/[Content_Types].xml14
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/.gitignore5
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/App.xaml7
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/App.xaml.cs104
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/ApplicationInsights.config3
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/LockScreenLogo.scale-200.pngbin0 -> 1430 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/SplashScreen.scale-200.pngbin0 -> 7700 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square150x150Logo.scale-200.pngbin0 -> 2937 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.scale-200.pngbin0 -> 1647 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.targetsize-24_altform-unplated.pngbin0 -> 1255 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/StoreLogo.pngbin0 -> 1451 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Assets/Wide310x150Logo.scale-200.pngbin0 -> 3204 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml29
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml.cs171
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Package.appxmanifest28
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Properties/AssemblyInfo.cs29
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/Properties/Default.rd.xml31
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/TdApp.csproj151
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/TdApp_TemporaryKey.pfxbin0 -> 2456 bytes
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/app/project.json19
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/build.ps1142
-rw-r--r--protocols/Telegram/tdlib/td/example/uwp/extension.vsixmanifest17
55 files changed, 3629 insertions, 0 deletions
diff --git a/protocols/Telegram/tdlib/td/example/cpp/.gitignore b/protocols/Telegram/tdlib/td/example/cpp/.gitignore
new file mode 100644
index 0000000000..336dc7d458
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/.gitignore
@@ -0,0 +1 @@
+td/
diff --git a/protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt b/protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt
new file mode 100644
index 0000000000..3e7794d4fa
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+project(TdExample VERSION 1.0 LANGUAGES CXX)
+
+find_package(Td 1.2.0 REQUIRED)
+
+add_executable(tdjson_example tdjson_example.cpp)
+target_link_libraries(tdjson_example PRIVATE Td::TdJson)
+set_property(TARGET tdjson_example PROPERTY CXX_STANDARD 11)
+
+add_executable(td_example td_example.cpp)
+target_link_libraries(td_example PRIVATE Td::TdStatic)
+set_property(TARGET td_example PROPERTY CXX_STANDARD 14)
diff --git a/protocols/Telegram/tdlib/td/example/cpp/README.md b/protocols/Telegram/tdlib/td/example/cpp/README.md
new file mode 100644
index 0000000000..9e5de531ba
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/README.md
@@ -0,0 +1,24 @@
+# TDLib cpp basic usage examples
+
+TDLib should be prebuilt and installed to local subdirectory `td/`:
+```
+cd <path to TDLib sources>
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../example/cpp/td ..
+cmake --build . --target install
+```
+Also see [building](https://github.com/tdlib/td#building) for additional details on TDLib building.
+
+Then you can build the examples:
+```
+cd <path to TDLib sources>/example/cpp
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DTd_DIR=<full path to TDLib sources>/example/cpp/td/lib/cmake/Td ..
+cmake --build .
+```
+
+Documentation for all available classes and methods can be found at https://core.telegram.org/tdlib/docs.
+
+To run `tdjson_example` you may need to manually copy a `tdjson` shared library from `td/bin` to a directory containing built binaries.
diff --git a/protocols/Telegram/tdlib/td/example/cpp/td_example.cpp b/protocols/Telegram/tdlib/td/example/cpp/td_example.cpp
new file mode 100644
index 0000000000..1efbf465b9
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/td_example.cpp
@@ -0,0 +1,308 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <td/telegram/Client.h>
+#include <td/telegram/Log.h>
+#include <td/telegram/td_api.h>
+#include <td/telegram/td_api.hpp>
+
+#include <cstdint>
+#include <functional>
+#include <iostream>
+#include <limits>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+// Simple single-threaded example of TDLib usage.
+// Real world programs should use separate thread for the user input.
+// Example includes user authentication, receiving updates, getting chat list and sending text messages.
+
+// overloaded
+namespace detail {
+template <class... Fs>
+struct overload;
+
+template <class F>
+struct overload<F> : public F {
+ explicit overload(F f) : F(f) {
+ }
+};
+template <class F, class... Fs>
+struct overload<F, Fs...>
+ : public overload<F>
+ , overload<Fs...> {
+ overload(F f, Fs... fs) : overload<F>(f), overload<Fs...>(fs...) {
+ }
+ using overload<F>::operator();
+ using overload<Fs...>::operator();
+};
+} // namespace detail
+
+template <class... F>
+auto overloaded(F... f) {
+ return detail::overload<F...>(f...);
+}
+
+namespace td_api = td::td_api;
+
+class TdExample {
+ public:
+ TdExample() {
+ td::Log::set_verbosity_level(1);
+ client_ = std::make_unique<td::Client>();
+ }
+
+ void loop() {
+ while (true) {
+ if (need_restart_) {
+ restart();
+ } else if (!are_authorized_) {
+ process_response(client_->receive(10));
+ } else {
+ std::cerr << "Enter action [q] quit [u] check for updates and request results [c] show chats [m <id> <text>] "
+ "send message [l] logout: "
+ << std::endl;
+ std::string line;
+ std::getline(std::cin, line);
+ std::istringstream ss(line);
+ std::string action;
+ if (!(ss >> action)) {
+ continue;
+ }
+ if (action == "q") {
+ return;
+ }
+ if (action == "u") {
+ std::cerr << "Checking for updates..." << std::endl;
+ while (true) {
+ auto response = client_->receive(0);
+ if (response.object) {
+ process_response(std::move(response));
+ } else {
+ break;
+ }
+ }
+ } else if (action == "l") {
+ std::cerr << "Logging out..." << std::endl;
+ send_query(td_api::make_object<td_api::logOut>(), {});
+ } else if (action == "m") {
+ std::int64_t chat_id;
+ ss >> chat_id;
+ ss.get();
+ std::string text;
+ std::getline(ss, text);
+
+ std::cerr << "Sending message to chat " << chat_id << "..." << std::endl;
+ auto send_message = td_api::make_object<td_api::sendMessage>();
+ send_message->chat_id_ = chat_id;
+ auto message_content = td_api::make_object<td_api::inputMessageText>();
+ message_content->text_ = td_api::make_object<td_api::formattedText>();
+ message_content->text_->text_ = std::move(text);
+ send_message->input_message_content_ = std::move(message_content);
+
+ send_query(std::move(send_message), {});
+ } else if (action == "c") {
+ std::cerr << "Loading chat list..." << std::endl;
+ send_query(td_api::make_object<td_api::getChats>(std::numeric_limits<std::int64_t>::max(), 0, 20),
+ [this](Object object) {
+ if (object->get_id() == td_api::error::ID) {
+ return;
+ }
+ auto chats = td::move_tl_object_as<td_api::chats>(object);
+ for (auto chat_id : chats->chat_ids_) {
+ std::cerr << "[id:" << chat_id << "] [title:" << chat_title_[chat_id] << "]" << std::endl;
+ }
+ });
+ }
+ }
+ }
+ }
+
+ private:
+ using Object = td_api::object_ptr<td_api::Object>;
+ std::unique_ptr<td::Client> client_;
+
+ td_api::object_ptr<td_api::AuthorizationState> authorization_state_;
+ bool are_authorized_{false};
+ bool need_restart_{false};
+ std::uint64_t current_query_id_{0};
+ std::uint64_t authentication_query_id_{0};
+
+ std::map<std::uint64_t, std::function<void(Object)>> handlers_;
+
+ std::map<std::int32_t, td_api::object_ptr<td_api::user>> users_;
+
+ std::map<std::int64_t, std::string> chat_title_;
+
+ void restart() {
+ client_.reset();
+ *this = TdExample();
+ }
+
+ void send_query(td_api::object_ptr<td_api::Function> f, std::function<void(Object)> handler) {
+ auto query_id = next_query_id();
+ if (handler) {
+ handlers_.emplace(query_id, std::move(handler));
+ }
+ client_->send({query_id, std::move(f)});
+ }
+
+ void process_response(td::Client::Response response) {
+ if (!response.object) {
+ return;
+ }
+ //std::cerr << response.id << " " << to_string(response.object) << std::endl;
+ if (response.id == 0) {
+ return process_update(std::move(response.object));
+ }
+ auto it = handlers_.find(response.id);
+ if (it != handlers_.end()) {
+ it->second(std::move(response.object));
+ }
+ }
+
+ std::string get_user_name(std::int32_t user_id) {
+ auto it = users_.find(user_id);
+ if (it == users_.end()) {
+ return "unknown user";
+ }
+ return it->second->first_name_ + " " + it->second->last_name_;
+ }
+
+ void process_update(td_api::object_ptr<td_api::Object> update) {
+ td_api::downcast_call(
+ *update, overloaded(
+ [this](td_api::updateAuthorizationState &update_authorization_state) {
+ authorization_state_ = std::move(update_authorization_state.authorization_state_);
+ on_authorization_state_update();
+ },
+ [this](td_api::updateNewChat &update_new_chat) {
+ chat_title_[update_new_chat.chat_->id_] = update_new_chat.chat_->title_;
+ },
+ [this](td_api::updateChatTitle &update_chat_title) {
+ chat_title_[update_chat_title.chat_id_] = update_chat_title.title_;
+ },
+ [this](td_api::updateUser &update_user) {
+ auto user_id = update_user.user_->id_;
+ users_[user_id] = std::move(update_user.user_);
+ },
+ [this](td_api::updateNewMessage &update_new_message) {
+ auto chat_id = update_new_message.message_->chat_id_;
+ auto sender_user_name = get_user_name(update_new_message.message_->sender_user_id_);
+ std::string text;
+ if (update_new_message.message_->content_->get_id() == td_api::messageText::ID) {
+ text = static_cast<td_api::messageText &>(*update_new_message.message_->content_).text_->text_;
+ }
+ std::cerr << "Got message: [chat_id:" << chat_id << "] [from:" << sender_user_name << "] ["
+ << text << "]" << std::endl;
+ },
+ [](auto &update) {}));
+ }
+
+ auto create_authentication_query_handler() {
+ return [this, id = authentication_query_id_](Object object) {
+ if (id == authentication_query_id_) {
+ check_authentication_error(std::move(object));
+ }
+ };
+ }
+
+ void on_authorization_state_update() {
+ authentication_query_id_++;
+ td_api::downcast_call(
+ *authorization_state_,
+ overloaded(
+ [this](td_api::authorizationStateReady &) {
+ are_authorized_ = true;
+ std::cerr << "Got authorization" << std::endl;
+ },
+ [this](td_api::authorizationStateLoggingOut &) {
+ are_authorized_ = false;
+ std::cerr << "Logging out" << std::endl;
+ },
+ [this](td_api::authorizationStateClosing &) { std::cerr << "Closing" << std::endl; },
+ [this](td_api::authorizationStateClosed &) {
+ are_authorized_ = false;
+ need_restart_ = true;
+ std::cerr << "Terminated" << std::endl;
+ },
+ [this](td_api::authorizationStateWaitCode &wait_code) {
+ std::string first_name;
+ std::string last_name;
+ if (!wait_code.is_registered_) {
+ std::cerr << "Enter your first name: ";
+ std::cin >> first_name;
+ std::cerr << "Enter your last name: ";
+ std::cin >> last_name;
+ }
+ std::cerr << "Enter authentication code: ";
+ std::string code;
+ std::cin >> code;
+ send_query(td_api::make_object<td_api::checkAuthenticationCode>(code, first_name, last_name),
+ create_authentication_query_handler());
+ },
+ [this](td_api::authorizationStateWaitPassword &) {
+ std::cerr << "Enter authentication password: ";
+ std::string password;
+ std::cin >> password;
+ send_query(td_api::make_object<td_api::checkAuthenticationPassword>(password),
+ create_authentication_query_handler());
+ },
+ [this](td_api::authorizationStateWaitPhoneNumber &) {
+ std::cerr << "Enter phone number: ";
+ std::string phone_number;
+ std::cin >> phone_number;
+ send_query(td_api::make_object<td_api::setAuthenticationPhoneNumber>(
+ phone_number, false /*allow_flash_calls*/, false /*is_current_phone_number*/),
+ create_authentication_query_handler());
+ },
+ [this](td_api::authorizationStateWaitEncryptionKey &) {
+ std::cerr << "Enter encryption key or DESTROY: ";
+ std::string key;
+ std::getline(std::cin, key);
+ if (key == "DESTROY") {
+ send_query(td_api::make_object<td_api::destroy>(), create_authentication_query_handler());
+ } else {
+ send_query(td_api::make_object<td_api::checkDatabaseEncryptionKey>(std::move(key)),
+ create_authentication_query_handler());
+ }
+ },
+ [this](td_api::authorizationStateWaitTdlibParameters &) {
+ auto parameters = td_api::make_object<td_api::tdlibParameters>();
+ parameters->database_directory_ = "tdlib";
+ parameters->use_message_database_ = true;
+ parameters->use_secret_chats_ = true;
+ parameters->api_id_ = 94575;
+ parameters->api_hash_ = "a3406de8d171bb422bb6ddf3bbd800e2";
+ parameters->system_language_code_ = "en";
+ parameters->device_model_ = "Desktop";
+ parameters->system_version_ = "Unknown";
+ parameters->application_version_ = "1.0";
+ parameters->enable_storage_optimizer_ = true;
+ send_query(td_api::make_object<td_api::setTdlibParameters>(std::move(parameters)),
+ create_authentication_query_handler());
+ }));
+ }
+
+ void check_authentication_error(Object object) {
+ if (object->get_id() == td_api::error::ID) {
+ auto error = td::move_tl_object_as<td_api::error>(object);
+ std::cerr << "Error: " << to_string(error);
+ on_authorization_state_update();
+ }
+ }
+
+ std::uint64_t next_query_id() {
+ return ++current_query_id_;
+ }
+};
+
+int main() {
+ TdExample example;
+ example.loop();
+}
diff --git a/protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp b/protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp
new file mode 100644
index 0000000000..6787b37f86
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/cpp/tdjson_example.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <iostream>
+#include <td/telegram/td_json_client.h>
+
+// Basic example of TDLib JSON interface usage.
+// Native interface should be preferred instead in C++, so here is only an example of
+// the main event cycle, which should be essentially the same for all languages.
+
+int main() {
+ void *client = td_json_client_create();
+ // somehow share the client with other threads, which will be able to send requests via td_json_client_send
+
+ const double WAIT_TIMEOUT = 10.0; // seconds
+ while (true) {
+ const char *result = td_json_client_receive(client, WAIT_TIMEOUT);
+ if (result != nullptr) {
+ // parse the result as JSON object and process it as an incoming update or an answer to a previously sent request
+
+ // if (result is UpdateAuthorizationState with authorizationStateClosed) {
+ // break;
+ // }
+
+ std::cout << result << std::endl;
+ }
+ }
+
+ td_json_client_destroy(client);
+}
diff --git a/protocols/Telegram/tdlib/td/example/csharp/.gitignore b/protocols/Telegram/tdlib/td/example/csharp/.gitignore
new file mode 100644
index 0000000000..5266ecccc9
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/csharp/.gitignore
@@ -0,0 +1,5 @@
+.vs/
+bin/
+obj/
+project.lock.json
+TdExample.csproj.user
diff --git a/protocols/Telegram/tdlib/td/example/csharp/README.md b/protocols/Telegram/tdlib/td/example/csharp/README.md
new file mode 100644
index 0000000000..2faa15e12e
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/csharp/README.md
@@ -0,0 +1,32 @@
+# TDLib C# example
+
+This is an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C#.
+
+## Building TDLib
+
+* Download and install Microsoft Visual Studio 2015 or later.
+* Download and install [CMake](https://cmake.org/download/).
+* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
+* Install `zlib` and `openssl` for using `vcpkg`:
+```
+C:\src\vcpkg> .\vcpkg.exe install openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
+```
+* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable.
+* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable.
+* Build `TDLib` with CMake enabling `.NET` support and specifying correct path to `vcpkg` toolchain file:
+```
+cd <path to TDLib sources>/example/csharp
+mkdir build
+cd build
+cmake -DTD_ENABLE_DOTNET=ON -DCMAKE_TOOLCHAIN_FILE=C:\src\vcpkg\scripts\buildsystems\vcpkg.cmake ../../..
+cmake --build . --config Release
+cmake --build . --config Debug
+```
+
+## Example of usage
+
+After `TDLib` is built you can open and run TdExample project.
+It contains a simple console C# application with implementation of authorization and message sending.
+Just open it with Visual Studio 2015 or 2017 and run.
+
+Also see TdExample.csproj for example of including TDLib in C# project with all native shared library dependencies.
diff --git a/protocols/Telegram/tdlib/td/example/csharp/TdExample.cs b/protocols/Telegram/tdlib/td/example/csharp/TdExample.cs
new file mode 100644
index 0000000000..be98e1a758
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/csharp/TdExample.cs
@@ -0,0 +1,270 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using Td = Telegram.Td;
+using TdApi = Telegram.Td.Api;
+
+using System;
+using System.Threading;
+
+namespace TdExample
+{
+ /// <summary>
+ /// Example class for TDLib usage from C#.
+ /// </summary>
+ class Example
+ {
+ private static Td.Client _client = null;
+ private readonly static Td.ClientResultHandler _defaultHandler = new DefaultHandler();
+
+ private static TdApi.AuthorizationState _authorizationState = null;
+ private static volatile bool _haveAuthorization = false;
+ private static volatile bool _quiting = false;
+
+ private static volatile AutoResetEvent _gotAuthorization = new AutoResetEvent(false);
+
+ private static readonly string _newLine = Environment.NewLine;
+ private static readonly string _commandsLine = "Enter command (gc <chatId> - GetChat, me - GetMe, sm <chatId> <message> - SendMessage, lo - LogOut, q - Quit): ";
+ private static volatile string _currentPrompt = null;
+
+ private static Td.Client CreateTdClient()
+ {
+ Td.Client result = Td.Client.Create(new UpdatesHandler());
+ new Thread(() =>
+ {
+ Thread.CurrentThread.IsBackground = true;
+ result.Run();
+ }).Start();
+ return result;
+ }
+
+ private static void Print(string str)
+ {
+ if (_currentPrompt != null)
+ {
+ Console.WriteLine();
+ }
+ Console.WriteLine(str);
+ if (_currentPrompt != null)
+ {
+ Console.Write(_currentPrompt);
+ }
+ }
+
+ private static string ReadLine(string str)
+ {
+ Console.Write(str);
+ _currentPrompt = str;
+ var result = Console.ReadLine();
+ _currentPrompt = null;
+ return result;
+ }
+
+ private static void OnAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState)
+ {
+ if (authorizationState != null)
+ {
+ _authorizationState = authorizationState;
+ }
+ if (_authorizationState is TdApi.AuthorizationStateWaitTdlibParameters)
+ {
+ TdApi.TdlibParameters parameters = new TdApi.TdlibParameters();
+ parameters.DatabaseDirectory = "tdlib";
+ parameters.UseMessageDatabase = true;
+ parameters.UseSecretChats = true;
+ parameters.ApiId = 94575;
+ parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
+ parameters.SystemLanguageCode = "en";
+ parameters.DeviceModel = "Desktop";
+ parameters.SystemVersion = "Unknown";
+ parameters.ApplicationVersion = "1.0";
+ parameters.EnableStorageOptimizer = true;
+
+ _client.Send(new TdApi.SetTdlibParameters(parameters), new AuthorizationRequestHandler());
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateWaitEncryptionKey)
+ {
+ _client.Send(new TdApi.CheckDatabaseEncryptionKey(), new AuthorizationRequestHandler());
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateWaitPhoneNumber)
+ {
+ string phoneNumber = ReadLine("Please enter phone number: ");
+ _client.Send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, false, false), new AuthorizationRequestHandler());
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateWaitCode)
+ {
+ string code = ReadLine("Please enter authentication code: ");
+ _client.Send(new TdApi.CheckAuthenticationCode(code, "", ""), new AuthorizationRequestHandler());
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateWaitPassword)
+ {
+ string password = ReadLine("Please enter password: ");
+ _client.Send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler());
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateReady)
+ {
+ _haveAuthorization = true;
+ _gotAuthorization.Set();
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateLoggingOut)
+ {
+ _haveAuthorization = false;
+ Print("Logging out");
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateClosing)
+ {
+ _haveAuthorization = false;
+ Print("Closing");
+ }
+ else if (_authorizationState is TdApi.AuthorizationStateClosed)
+ {
+ Print("Closed");
+ if (!_quiting)
+ {
+ _client = CreateTdClient(); // recreate _client after previous has closed
+ }
+ }
+ else
+ {
+ Print("Unsupported authorization state:" + _newLine + _authorizationState);
+ }
+ }
+
+ private static long GetChatId(string arg)
+ {
+ long chatId = 0;
+ try
+ {
+ chatId = Convert.ToInt64(arg);
+ }
+ catch (FormatException)
+ {
+ }
+ catch (OverflowException)
+ {
+ }
+ return chatId;
+ }
+
+ private static void GetCommand()
+ {
+ string command = ReadLine(_commandsLine);
+ string[] commands = command.Split(new char[] { ' ' }, 2);
+ try
+ {
+ switch (commands[0])
+ {
+ case "gc":
+ _client.Send(new TdApi.GetChat(GetChatId(commands[1])), _defaultHandler);
+ break;
+ case "me":
+ _client.Send(new TdApi.GetMe(), _defaultHandler);
+ break;
+ case "sm":
+ string[] args = commands[1].Split(new char[] { ' ' }, 2);
+ sendMessage(GetChatId(args[0]), args[1]);
+ break;
+ case "lo":
+ _haveAuthorization = false;
+ _client.Send(new TdApi.LogOut(), _defaultHandler);
+ break;
+ case "q":
+ _quiting = true;
+ _haveAuthorization = false;
+ _client.Send(new TdApi.Close(), _defaultHandler);
+ break;
+ default:
+ Print("Unsupported command: " + command);
+ break;
+ }
+ }
+ catch (IndexOutOfRangeException)
+ {
+ Print("Not enough arguments");
+ }
+ }
+
+ private static void sendMessage(long chatId, string message)
+ {
+ // initialize reply markup just for testing
+ TdApi.InlineKeyboardButton[] row = { new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl()) };
+ TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][] { row, row, row });
+
+ TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true);
+ _client.Send(new TdApi.SendMessage(chatId, 0, false, false, replyMarkup, content), _defaultHandler);
+ }
+
+ static void Main()
+ {
+ // disable TDLib log
+ Td.Log.SetVerbosityLevel(0);
+ if (!Td.Log.SetFilePath("tdlib.log"))
+ {
+ throw new System.IO.IOException("Write access to the current directory is required");
+ }
+
+ // create Td.Client
+ _client = CreateTdClient();
+
+ // test Client.Execute
+ _defaultHandler.OnResult(_client.Execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test")));
+
+ // main loop
+ while (!_quiting)
+ {
+ // await authorization
+ _gotAuthorization.Reset();
+ _gotAuthorization.WaitOne();
+
+ _client.Send(new TdApi.GetChats(Int64.MaxValue, 0, 100), _defaultHandler); // preload chat list
+ while (_haveAuthorization)
+ {
+ GetCommand();
+ }
+ }
+ }
+
+ private class DefaultHandler : Td.ClientResultHandler
+ {
+ void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
+ {
+ Print(@object.ToString());
+ }
+ }
+
+ private class UpdatesHandler : Td.ClientResultHandler
+ {
+ void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
+ {
+ if (@object is TdApi.UpdateAuthorizationState)
+ {
+ OnAuthorizationStateUpdated((@object as TdApi.UpdateAuthorizationState).AuthorizationState);
+ }
+ else
+ {
+ // Print("Unsupported update: " + @object);
+ }
+ }
+ }
+
+ private class AuthorizationRequestHandler : Td.ClientResultHandler
+ {
+ void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
+ {
+ if (@object is TdApi.Error)
+ {
+ Print("Receive an error:" + _newLine + @object);
+ OnAuthorizationStateUpdated(null); // repeat last action
+ }
+ else
+ {
+ // result is already received through UpdateAuthorizationState, nothing to do
+ }
+ }
+ }
+ }
+}
diff --git a/protocols/Telegram/tdlib/td/example/csharp/TdExample.csproj b/protocols/Telegram/tdlib/td/example/csharp/TdExample.csproj
new file mode 100644
index 0000000000..ea2ad56532
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/csharp/TdExample.csproj
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProjectGuid>{3F9A93EA-DC26-4F8B-ACE0-131B33B00CA7}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <NoStandardLibraries>false</NoStandardLibraries>
+ <AssemblyName>ConsoleApplication</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup>
+ <RootNamespace>TdExample</RootNamespace>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="Telegram.Td, Version=0.0.0.0, Culture=neutral, processorArchitecture=AMD64">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath Condition=" '$(Configuration)' == 'Debug' ">build\Debug\Telegram.Td.dll</HintPath>
+ <HintPath Condition=" '$(Configuration)' == 'Release' ">build\Release\Telegram.Td.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="TdExample.cs" />
+ </ItemGroup>
+ <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+ <Content Include="build\Debug\LIBEAY32.dll">
+ <Link>LIBEAY32.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="build\Debug\SSLEAY32.dll">
+ <Link>SSLEAY32.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="build\Debug\zlibd1.dll">
+ <Link>zlibd1.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <ItemGroup Condition=" '$(Configuration)' == 'Release' ">
+ <Content Include="build\Release\LIBEAY32.dll">
+ <Link>LIBEAY32.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="build\Release\SSLEAY32.dll">
+ <Link>SSLEAY32.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="build\Release\zlib1.dll">
+ <Link>zlib1.dll</Link>
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSHARP.Targets" />
+ <ProjectExtensions>
+ <VisualStudio AllowExistingFolder="true" />
+ </ProjectExtensions>
+</Project> \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/go/main.go b/protocols/Telegram/tdlib/td/example/go/main.go
new file mode 100644
index 0000000000..430e067019
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/go/main.go
@@ -0,0 +1,26 @@
+package main
+
+// #cgo LDFLAGS: -ltdjson
+// #include <td/telegram/td_json_client.h>
+import "C"
+import (
+ "log"
+ "unsafe"
+)
+
+func td_send(client unsafe.Pointer, query *C.char) {
+ C.td_json_client_send(client, query)
+}
+
+func td_receive(client unsafe.Pointer) string {
+ return C.GoString(C.td_json_client_receive(client, 1.0))
+}
+
+func main() {
+ var client unsafe.Pointer
+ client = C.td_json_client_create()
+
+ query := C.CString(`{"@type": "getAuthorizationState"}`)
+ td_send(client, query)
+ log.Println(td_receive(client))
+}
diff --git a/protocols/Telegram/tdlib/td/example/ios/README.md b/protocols/Telegram/tdlib/td/example/ios/README.md
new file mode 100644
index 0000000000..25a1e68fcc
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/ios/README.md
@@ -0,0 +1,41 @@
+# Build for iOS
+
+Below are instructions for building TDLib for iOS, watchOS, tvOS, and also macOS.
+
+If you need only a macOS build, take a look at our build instructions for [macOS](https://github.com/tdlib/td#macos).
+
+For example of usage take a look at our [Swift example](https://github.com/tdlib/td/tree/master/example/swift).
+
+To compile `TDLib` you will need to:
+* Install the latest Xcode command line tools.
+* Install other build dependencies, for example, using [Homebrew](https://brew.sh):
+```
+brew install gperf cmake
+```
+* If you don't want to build `TDLib` for macOS, you can pregenerate required source code files using CMake prepare_cross_compiling target:
+```
+cd <path to TDLib sources>
+mkdir native-build
+cd native-build
+cmake ..
+cmake --build . --target prepare_cross_compiling
+```
+* Build OpenSSL for iOS, watchOS, tvOS and macOS:
+```
+cd <path to TDLib sources>/example/ios
+./build-openssl.sh
+```
+Here we use scripts from [Python Apple support](https://github.com/pybee/Python-Apple-support), but any other OpenSSL builds should work too.
+Built libraries should be stored in `third_party/openssl/<platform>`, because the next script will rely on this location.
+* Build TDLib for iOS, watchOS, tvOS and macOS:
+```
+cd <path to TDLib sources>/example/ios
+./build.sh
+```
+This may take a while, because TDLib will be built about 10 times.
+Resulting library for iOS will work on any architecture (arv7, armv7s, arm64) and even on a simulator.
+We use [CMake/iOS.cmake](https://github.com/tdlib/td/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too.
+
+Built libraries will be store in `tdjson` directory.
+
+Documentation for all available classes and methods can be found at https://core.telegram.org/tdlib/docs.
diff --git a/protocols/Telegram/tdlib/td/example/ios/build-openssl.sh b/protocols/Telegram/tdlib/td/example/ios/build-openssl.sh
new file mode 100644
index 0000000000..2ad9dbcfee
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/ios/build-openssl.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+git clone https://github.com/pybee/Python-Apple-support
+cd Python-Apple-support
+git checkout 2.7
+cd ..
+
+#TODO: change openssl version
+platforms="macOS iOS watchOS tvOS"
+for platform in $platforms;
+do
+ echo $platform
+ cd Python-Apple-support
+ #NB: -j will fail
+ make OpenSSL-$platform
+ cd ..
+ rm -rf third_party/openssl/$platform
+ mkdir -p third_party/openssl/$platform/lib
+ cp ./Python-Apple-support/build/$platform/libcrypto.a third_party/openssl/$platform/lib/
+ cp ./Python-Apple-support/build/$platform/libssl.a third_party/openssl/$platform/lib/
+ cp -r ./Python-Apple-support/build/$platform/Support/OpenSSL/Headers/ third_party/openssl/$platform/include
+done
diff --git a/protocols/Telegram/tdlib/td/example/ios/build.sh b/protocols/Telegram/tdlib/td/example/ios/build.sh
new file mode 100644
index 0000000000..9970008a1c
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/ios/build.sh
@@ -0,0 +1,74 @@
+#/bin/sh
+td_path=$(realpath ../..)
+
+rm -rf build
+mkdir -p build
+cd build
+
+platforms="macOS iOS watchOS tvOS"
+for platform in $platforms;
+do
+ echo "Platform = ${platform} Simulator = ${simulator}"
+ openssl_path=$(realpath ../third_party/openssl/${platform})
+ echo "OpenSSL path = ${openssl_path}"
+ openssl_crypto_library="${openssl_path}/lib/libcrypto.a"
+ openssl_ssl_library="${openssl_path}/lib/libssl.a"
+ options="$options -DOPENSSL_FOUND=1"
+ options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}"
+ #options="$options -DOPENSSL_SSL_LIBRARY=${openssl_ssl_library}"
+ options="$options -DOPENSSL_INCLUDE_DIR=${openssl_path}/include"
+ options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library};${openssl_ssl_library}"
+ options="$options -DCMAKE_BUILD_TYPE=Release"
+ if [[ $platform = "macOS" ]]; then
+ build="build-${platform}"
+ install="install-${platform}"
+ rm -rf $build
+ mkdir -p $build
+ mkdir -p $install
+ cd $build
+ cmake $td_path $options -DCMAKE_INSTALL_PREFIX=../${install}
+ make -j3 install || exit
+ cd ..
+ mkdir -p $platform
+ cp $build/libtdjson.dylib $platform/libtdjson.dylib
+ install_name_tool -id @rpath/libtdjson.dylib $platform/libtdjson.dylib
+ else
+ simulators="0 1"
+ for simulator in $simulators;
+ do
+ build="build-${platform}"
+ install="install-${platform}"
+ if [[ $simulator = "1" ]]; then
+ build="${build}-simulator"
+ install="${install}-simulator"
+ ios_platform="SIMULATOR"
+ else
+ ios_platform="OS"
+ fi
+ if [[ $platform = "watchOS" ]]; then
+ ios_platform="WATCH${ios_platform}"
+ fi
+ if [[ $platform = "tvOS" ]]; then
+ ios_platform="TV${ios_platform}"
+ fi
+ echo $ios_platform
+ rm -rf $build
+ mkdir -p $build
+ mkdir -p $install
+ cd $build
+ cmake $td_path $options -DIOS_PLATFORM=${ios_platform} -DCMAKE_TOOLCHAIN_FILE=${td_path}/CMake/iOS.cmake -DCMAKE_INSTALL_PREFIX=../${install}
+ make -j3 install || exit
+ cd ..
+ done
+ lib="install-${platform}/lib/libtdjson.dylib"
+ lib_simulator="install-${platform}-simulator/lib/libtdjson.dylib"
+ mkdir -p $platform
+ lipo -create $lib $lib_simulator -o $platform/libtdjson.dylib
+ install_name_tool -id @rpath/libtdjson.dylib $platform/libtdjson.dylib
+ fi
+
+ mkdir -p ../tdjson/$platform/include
+ rsync --recursive ${install}/include/ ../tdjson/${platform}/include/
+ mkdir -p ../tdjson/$platform/lib
+ cp $platform/libtdjson.dylib ../tdjson/$platform/lib/
+done
diff --git a/protocols/Telegram/tdlib/td/example/java/.gitignore b/protocols/Telegram/tdlib/td/example/java/.gitignore
new file mode 100644
index 0000000000..8f846b80d9
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/.gitignore
@@ -0,0 +1,5 @@
+**/*build/
+bin/
+docs/
+org/drinkless/tdlib/TdApi.java
+td/
diff --git a/protocols/Telegram/tdlib/td/example/java/CMakeLists.txt b/protocols/Telegram/tdlib/td/example/java/CMakeLists.txt
new file mode 100644
index 0000000000..e8313a68b7
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/CMakeLists.txt
@@ -0,0 +1,68 @@
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+project(TdJavaExample VERSION 1.0 LANGUAGES CXX)
+
+find_package(Td REQUIRED)
+
+if (NOT JNI_FOUND)
+ find_package(JNI REQUIRED)
+endif()
+message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}")
+
+if (NOT Java_FOUND)
+ find_package(Java 1.6 REQUIRED)
+endif()
+message(STATUS "Found Java: ${Java_JAVAC_EXECUTABLE} ${Java_JAVADOC_EXECUTABLE}")
+
+# Generating TdApi.java
+find_program(PHP_EXECUTABLE php)
+
+set(TD_API_JAVA_PACKAGE "org/drinkless/tdlib")
+set(TD_API_JAVA_PATH ${CMAKE_CURRENT_SOURCE_DIR})
+set(TD_API_TLO_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tlo)
+set(TD_API_TL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/scheme/td_api.tl)
+set(JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td/generate/JavadocTlDocumentationGenerator.php)
+set(GENERATE_JAVA_API_CMD ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api TdApi ${TD_API_TLO_PATH} ${TD_API_JAVA_PATH} ${TD_API_JAVA_PACKAGE})
+if (PHP_EXECUTABLE)
+ set(GENERATE_JAVA_API_CMD ${GENERATE_JAVA_API_CMD} && ${PHP_EXECUTABLE} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH} ${TD_API_TL_PATH} ${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}/TdApi.java)
+endif()
+
+add_custom_target(td_generate_java_api
+ COMMAND ${GENERATE_JAVA_API_CMD}
+ COMMENT "Generating Java TDLib API source files"
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/td/bin/td_generate_java_api ${TD_API_TLO_PATH} ${TD_API_TL_PATH} ${JAVADOC_TL_DOCUMENTATION_GENERATOR_PATH}
+)
+
+set(JAVA_SOURCE_PATH "${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}")
+get_filename_component(JAVA_OUTPUT_DIRECTORY ${CMAKE_INSTALL_PREFIX}/bin REALPATH BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+file(MAKE_DIRECTORY ${JAVA_OUTPUT_DIRECTORY})
+add_custom_target(build_java
+ COMMAND ${Java_JAVAC_EXECUTABLE} -d ${JAVA_OUTPUT_DIRECTORY} ${JAVA_SOURCE_PATH}/example/Example.java ${JAVA_SOURCE_PATH}/Client.java ${JAVA_SOURCE_PATH}/Log.java ${JAVA_SOURCE_PATH}/TdApi.java
+ COMMENT "Building Java code"
+ DEPENDS td_generate_java_api
+)
+
+set(JAVA_SOURCE_PATH "${TD_API_JAVA_PATH}/${TD_API_JAVA_PACKAGE}")
+add_custom_target(generate_javadoc
+ COMMAND ${Java_JAVADOC_EXECUTABLE} -d ${JAVA_OUTPUT_DIRECTORY}/../docs org.drinkless.tdlib
+ WORKING_DIRECTORY ${TD_API_JAVA_PATH}
+ COMMENT "Generating Javadoc documentation"
+ DEPENDS td_generate_java_api
+)
+
+# Building shared library
+add_library(tdjni SHARED
+ td_jni.cpp
+)
+target_include_directories(tdjni PRIVATE ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
+target_link_libraries(tdjni PRIVATE Td::TdStatic ${JAVA_JVM_LIBRARY})
+target_compile_definitions(tdjni PRIVATE PACKAGE_NAME="${TD_API_JAVA_PACKAGE}")
+
+set_property(TARGET tdjni PROPERTY CXX_STANDARD 14)
+
+add_dependencies(tdjni td_generate_java_api build_java generate_javadoc)
+
+install(TARGETS tdjni
+ LIBRARY DESTINATION bin
+ RUNTIME DESTINATION bin
+)
diff --git a/protocols/Telegram/tdlib/td/example/java/README.md b/protocols/Telegram/tdlib/td/example/java/README.md
new file mode 100644
index 0000000000..c2b5c43171
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/README.md
@@ -0,0 +1,39 @@
+# TDLib Java example
+
+To run this example, you will need installed JDK >= 1.6.
+For Javadoc documentation generation PHP is needed.
+
+TDLib should be prebuilt for using with Java and installed to local subdirectory `td/` as follows:
+```
+cd <path to TDLib sources>
+mkdir jnibuild
+cd jnibuild
+cmake -DCMAKE_BUILD_TYPE=Release -DTD_ENABLE_JNI=ON -DCMAKE_INSTALL_PREFIX:PATH=../example/java/td ..
+cmake --build . --target install
+```
+If you want to compile TDLib for 64-bit Java on Windows using MSVC, you will also need to add `-A x64` option to CMake.
+
+In Windows, use Vcpkg toolchain file by adding parameter -DCMAKE_TOOLCHAIN_FILE=<VCPKG_DIR>/scripts/buildsystems/vcpkg.cmake
+
+Then you can build this example:
+```
+cd <path to TDLib sources>/example/java
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DTd_DIR=<full path to TDLib sources>/example/java/td/lib/cmake/Td -DCMAKE_INSTALL_PREFIX:PATH=.. ..
+cmake --build . --target install
+```
+
+Compiled TDLib shared library and Java example after that will be placed in bin/ and Javadoc documentation in `docs/`.
+
+Now you can run Java example:
+```
+cd <path to TDLib sources>/example/java/bin
+java '-Djava.library.path=.' org/drinkless/tdlib/example/Example
+```
+
+If you get "Could NOT find JNI ..." error from CMake, you need to specify to CMake path to the installed JDK, for example, "-DJAVA_HOME=/usr/lib/jvm/java-8-oracle/".
+
+If you get java.lang.UnsatisfiedLinkError with "Can't find dependent libraries", you may also need to copy some dependent shared libraries to `bin/`.
+
+In case you compiled the example as 32-bit version, you may need to give -d32 parameter to Java.
diff --git a/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java
new file mode 100644
index 0000000000..efb38e9c5a
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Client.java
@@ -0,0 +1,285 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+package org.drinkless.tdlib;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Main class for interaction with the TDLib.
+ */
+public final class Client implements Runnable {
+ /**
+ * Interface for handler for results of queries to TDLib and incoming updates from TDLib.
+ */
+ public interface ResultHandler {
+ /**
+ * Callback called on result of query to TDLib or incoming update from TDLib.
+ *
+ * @param object Result of query or update of type TdApi.Update about new events.
+ */
+ void onResult(TdApi.Object object);
+ }
+
+ /**
+ * Interface for handler of exceptions thrown while invoking ResultHandler.
+ * By default, all such exceptions are ignored.
+ * All exceptions thrown from ExceptionHandler are ignored.
+ */
+ public interface ExceptionHandler {
+ /**
+ * Callback called on exceptions thrown while invoking ResultHandler.
+ *
+ * @param e Exception thrown by ResultHandler.
+ */
+ void onException(Throwable e);
+ }
+
+ /**
+ * Sends a request to the TDLib.
+ *
+ * @param query Object representing a query to the TDLib.
+ * @param resultHandler Result handler with onResult method which will be called with result
+ * of the query or with TdApi.Error as parameter. If it is null, nothing
+ * will be called.
+ * @param exceptionHandler Exception handler with onException method which will be called on
+ * exception thrown from resultHandler. If it is null, then
+ * defaultExceptionHandler will be called.
+ * @throws NullPointerException if query is null.
+ */
+ public void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
+ if (query == null) {
+ throw new NullPointerException("query is null");
+ }
+
+ readLock.lock();
+ try {
+ if (isClientDestroyed) {
+ if (resultHandler != null) {
+ handleResult(new TdApi.Error(500, "Client is closed"), resultHandler, exceptionHandler);
+ }
+ return;
+ }
+
+ long queryId = currentQueryId.incrementAndGet();
+ handlers.put(queryId, new Handler(resultHandler, exceptionHandler));
+ nativeClientSend(nativeClientId, queryId, query);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ /**
+ * Sends a request to the TDLib with an empty ExceptionHandler.
+ *
+ * @param query Object representing a query to the TDLib.
+ * @param resultHandler Result handler with onResult method which will be called with result
+ * of the query or with TdApi.Error as parameter. If it is null, then
+ * defaultExceptionHandler will be called.
+ * @throws NullPointerException if query is null.
+ */
+ public void send(TdApi.Function query, ResultHandler resultHandler) {
+ send(query, resultHandler, null);
+ }
+
+ /**
+ * Synchronously executes a TDLib request. Only a few marked accordingly requests can be executed synchronously.
+ *
+ * @param query Object representing a query to the TDLib.
+ * @return request result.
+ * @throws NullPointerException if query is null.
+ */
+ public static TdApi.Object execute(TdApi.Function query) {
+ if (query == null) {
+ throw new NullPointerException("query is null");
+ }
+ return nativeClientExecute(query);
+ }
+
+ /**
+ * Replaces handler for incoming updates from the TDLib.
+ *
+ * @param updatesHandler Handler with onResult method which will be called for every incoming
+ * update from the TDLib.
+ * @param exceptionHandler Exception handler with onException method which will be called on
+ * exception thrown from updatesHandler, if it is null, defaultExceptionHandler will be invoked.
+ */
+ public void setUpdatesHandler(ResultHandler updatesHandler, ExceptionHandler exceptionHandler) {
+ handlers.put(0L, new Handler(updatesHandler, exceptionHandler));
+ }
+
+ /**
+ * Replaces handler for incoming updates from the TDLib. Sets empty ExceptionHandler.
+ *
+ * @param updatesHandler Handler with onResult method which will be called for every incoming
+ * update from the TDLib.
+ */
+ public void setUpdatesHandler(ResultHandler updatesHandler) {
+ setUpdatesHandler(updatesHandler, null);
+ }
+
+ /**
+ * Replaces default exception handler to be invoked on exceptions thrown from updatesHandler and all other ResultHandler.
+ *
+ * @param defaultExceptionHandler Default exception handler. If null Exceptions are ignored.
+ */
+ public void setDefaultExceptionHandler(Client.ExceptionHandler defaultExceptionHandler) {
+ this.defaultExceptionHandler = defaultExceptionHandler;
+ }
+
+ /**
+ * Overridden method from Runnable, do not call it directly.
+ */
+ @Override
+ public void run() {
+ while (!stopFlag) {
+ receiveQueries(300.0 /*seconds*/);
+ }
+ }
+
+ /**
+ * Creates new Client.
+ *
+ * @param updatesHandler Handler for incoming updates.
+ * @param updatesExceptionHandler Handler for exceptions thrown from updatesHandler. If it is null, exceptions will be iggnored.
+ * @param defaultExceptionHandler Default handler for exceptions thrown from all ResultHandler. If it is null, exceptions will be iggnored.
+ * @return created Client
+ */
+ public static Client create(ResultHandler updatesHandler, ExceptionHandler updatesExceptionHandler, ExceptionHandler defaultExceptionHandler) {
+ Client client = new Client(updatesHandler, updatesExceptionHandler, defaultExceptionHandler);
+ new Thread(client, "TDLib thread").start();
+ return client;
+ }
+
+ /**
+ * Closes Client.
+ */
+ public void close() {
+ writeLock.lock();
+ try {
+ if (isClientDestroyed) {
+ return;
+ }
+ if (!stopFlag) {
+ send(new TdApi.Close(), null);
+ }
+ isClientDestroyed = true;
+ while (!stopFlag) {
+ Thread.yield();
+ }
+ while (handlers.size() != 1) {
+ receiveQueries(300.0);
+ }
+ destroyNativeClient(nativeClientId);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
+ private final Lock readLock = readWriteLock.readLock();
+ private final Lock writeLock = readWriteLock.writeLock();
+
+ private volatile boolean stopFlag = false;
+ private volatile boolean isClientDestroyed = false;
+ private final long nativeClientId;
+
+ private final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<Long, Handler>();
+ private final AtomicLong currentQueryId = new AtomicLong();
+
+ private volatile ExceptionHandler defaultExceptionHandler = null;
+
+ private static final int MAX_EVENTS = 1000;
+ private final long[] eventIds = new long[MAX_EVENTS];
+ private final TdApi.Object[] events = new TdApi.Object[MAX_EVENTS];
+
+ private static class Handler {
+ final ResultHandler resultHandler;
+ final ExceptionHandler exceptionHandler;
+
+ Handler(ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
+ this.resultHandler = resultHandler;
+ this.exceptionHandler = exceptionHandler;
+ }
+ }
+
+ private Client(ResultHandler updatesHandler, ExceptionHandler updateExceptionHandler, ExceptionHandler defaultExceptionHandler) {
+ nativeClientId = createNativeClient();
+ handlers.put(0L, new Handler(updatesHandler, updateExceptionHandler));
+ this.defaultExceptionHandler = defaultExceptionHandler;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void processResult(long id, TdApi.Object object) {
+ if (object instanceof TdApi.UpdateAuthorizationState) {
+ if (((TdApi.UpdateAuthorizationState) object).authorizationState instanceof TdApi.AuthorizationStateClosed) {
+ stopFlag = true;
+ }
+ }
+ Handler handler;
+ if (id == 0) {
+ // update handler stays forever
+ handler = handlers.get(id);
+ } else {
+ handler = handlers.remove(id);
+ }
+ if (handler == null) {
+ return;
+ }
+
+ handleResult(object, handler.resultHandler, handler.exceptionHandler);
+ }
+
+ private void handleResult(TdApi.Object object, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
+ if (resultHandler == null) {
+ return;
+ }
+
+ try {
+ resultHandler.onResult(object);
+ } catch (Throwable cause) {
+ if (exceptionHandler == null) {
+ exceptionHandler = defaultExceptionHandler;
+ }
+ if (exceptionHandler != null) {
+ try {
+ exceptionHandler.onException(cause);
+ } catch (Throwable ignored) {
+ }
+ }
+ }
+ }
+
+ private void receiveQueries(double timeout) {
+ int resultN = nativeClientReceive(nativeClientId, eventIds, events, timeout);
+ for (int i = 0; i < resultN; i++) {
+ processResult(eventIds[i], events[i]);
+ events[i] = null;
+ }
+ }
+
+ private static native long createNativeClient();
+
+ private static native void nativeClientSend(long nativeClientId, long eventId, TdApi.Function function);
+
+ private static native int nativeClientReceive(long nativeClientId, long[] eventIds, TdApi.Object[] events, double timeout);
+
+ private static native TdApi.Object nativeClientExecute(TdApi.Function function);
+
+ private static native void destroyNativeClient(long nativeClientId);
+}
diff --git a/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java
new file mode 100644
index 0000000000..c81ffbeeb7
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/Log.java
@@ -0,0 +1,75 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+package org.drinkless.tdlib;
+
+/**
+ * Class for managing internal TDLib logging.
+ */
+public final class Log {
+ /**
+ * Changes TDLib log verbosity.
+ *
+ * @param verbosityLevel New value of log verbosity level. Must be non-negative.
+ * Value 0 corresponds to fatal errors,
+ * value 1 corresponds to java.util.logging.Level.SEVERE,
+ * value 2 corresponds to java.util.logging.Level.WARNING,
+ * value 3 corresponds to java.util.logging.Level.INFO,
+ * value 4 corresponds to java.util.logging.Level.FINE,
+ * value 5 corresponds to java.util.logging.Level.FINER,
+ * value greater than 5 can be used to enable even more logging.
+ * Default value of the log verbosity level is 5.
+ */
+ public static native void setVerbosityLevel(int verbosityLevel);
+
+ /**
+ * Sets file path for writing TDLib internal log. By default TDLib writes logs to the System.err.
+ * Use this method to write the log to a file instead.
+ *
+ * @param filePath Path to a file for writing TDLib internal log. Use an empty path to
+ * switch back to logging to the System.err.
+ * @return whether opening the log file succeeded.
+ */
+ public static native boolean setFilePath(String filePath);
+
+ /**
+ * Changes maximum size of TDLib log file.
+ *
+ * @param maxFileSize Maximum size of the file to where the internal TDLib log is written
+ * before the file will be auto-rotated. Must be positive. Defaults to 10 MB.
+ */
+ public static native void setMaxFileSize(long maxFileSize);
+
+ /**
+ * This function is called from the JNI when a fatal error happens to provide a better error message.
+ * The function does not return.
+ *
+ * @param errorMessage Error message.
+ */
+ private static void onFatalError(String errorMessage) {
+ class ThrowError implements Runnable {
+ private ThrowError(String errorMessage) {
+ this.errorMessage = errorMessage;
+ }
+
+ @Override
+ public void run() {
+ throw new RuntimeException("TDLib fatal error: " + errorMessage);
+ }
+
+ private final String errorMessage;
+ }
+
+ new Thread(new ThrowError(errorMessage), "TDLib fatal error thread").start();
+ while (true) {
+ try {
+ Thread.sleep(1000); // milliseconds
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+}
diff --git a/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java
new file mode 100644
index 0000000000..831de88f1d
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/org/drinkless/tdlib/example/Example.java
@@ -0,0 +1,533 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+package org.drinkless.tdlib.example;
+
+import org.drinkless.tdlib.Client;
+import org.drinkless.tdlib.Log;
+import org.drinkless.tdlib.TdApi;
+
+import java.io.IOError;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.NavigableSet;
+import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Example class for TDLib usage from Java.
+ */
+public final class Example {
+ private static Client client = null;
+
+ private static TdApi.AuthorizationState authorizationState = null;
+ private static volatile boolean haveAuthorization = false;
+ private static volatile boolean quiting = false;
+
+ private static final Client.ResultHandler defaultHandler = new DefaultHandler();
+
+ private static final Lock authorizationLock = new ReentrantLock();
+ private static final Condition gotAuthorization = authorizationLock.newCondition();
+
+ private static final ConcurrentMap<Integer, TdApi.User> users = new ConcurrentHashMap<Integer, TdApi.User>();
+ private static final ConcurrentMap<Integer, TdApi.BasicGroup> basicGroups = new ConcurrentHashMap<Integer, TdApi.BasicGroup>();
+ private static final ConcurrentMap<Integer, TdApi.Supergroup> supergroups = new ConcurrentHashMap<Integer, TdApi.Supergroup>();
+ private static final ConcurrentMap<Integer, TdApi.SecretChat> secretChats = new ConcurrentHashMap<Integer, TdApi.SecretChat>();
+
+ private static final ConcurrentMap<Long, TdApi.Chat> chats = new ConcurrentHashMap<Long, TdApi.Chat>();
+ private static final NavigableSet<OrderedChat> chatList = new TreeSet<OrderedChat>();
+ private static boolean haveFullChatList = false;
+
+ private static final ConcurrentMap<Integer, TdApi.UserFullInfo> usersFullInfo = new ConcurrentHashMap<Integer, TdApi.UserFullInfo>();
+ private static final ConcurrentMap<Integer, TdApi.BasicGroupFullInfo> basicGroupsFullInfo = new ConcurrentHashMap<Integer, TdApi.BasicGroupFullInfo>();
+ private static final ConcurrentMap<Integer, TdApi.SupergroupFullInfo> supergroupsFullInfo = new ConcurrentHashMap<Integer, TdApi.SupergroupFullInfo>();
+
+ private static final String newLine = System.getProperty("line.separator");
+ private static final String commandsLine = "Enter command (gcs - GetChats, gc <chatId> - GetChat, me - GetMe, sm <chatId> <message> - SendMessage, lo - LogOut, q - Quit): ";
+ private static volatile String currentPrompt = null;
+
+ static {
+ System.loadLibrary("tdjni");
+ }
+
+ private static void print(String str) {
+ if (currentPrompt != null) {
+ System.out.println("");
+ }
+ System.out.println(str);
+ if (currentPrompt != null) {
+ System.out.print(currentPrompt);
+ }
+ }
+
+ private static void setChatOrder(TdApi.Chat chat, long order) {
+ synchronized (chatList) {
+ if (chat.order != 0) {
+ boolean isRemoved = chatList.remove(new OrderedChat(chat.order, chat.id));
+ assert isRemoved;
+ }
+
+ chat.order = order;
+
+ if (chat.order != 0) {
+ boolean isAdded = chatList.add(new OrderedChat(chat.order, chat.id));
+ assert isAdded;
+ }
+ }
+ }
+
+ private static void onAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState) {
+ if (authorizationState != null) {
+ Example.authorizationState = authorizationState;
+ }
+ switch (Example.authorizationState.getConstructor()) {
+ case TdApi.AuthorizationStateWaitTdlibParameters.CONSTRUCTOR:
+ TdApi.TdlibParameters parameters = new TdApi.TdlibParameters();
+ parameters.databaseDirectory = "tdlib";
+ parameters.useMessageDatabase = true;
+ parameters.useSecretChats = true;
+ parameters.apiId = 94575;
+ parameters.apiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
+ parameters.systemLanguageCode = "en";
+ parameters.deviceModel = "Desktop";
+ parameters.systemVersion = "Unknown";
+ parameters.applicationVersion = "1.0";
+ parameters.enableStorageOptimizer = true;
+
+ client.send(new TdApi.SetTdlibParameters(parameters), new AuthorizationRequestHandler());
+ break;
+ case TdApi.AuthorizationStateWaitEncryptionKey.CONSTRUCTOR:
+ client.send(new TdApi.CheckDatabaseEncryptionKey(), new AuthorizationRequestHandler());
+ break;
+ case TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR: {
+ String phoneNumber = promptString("Please enter phone number: ");
+ client.send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, false, false), new AuthorizationRequestHandler());
+ break;
+ }
+ case TdApi.AuthorizationStateWaitCode.CONSTRUCTOR: {
+ String code = promptString("Please enter authentication code: ");
+ client.send(new TdApi.CheckAuthenticationCode(code, "", ""), new AuthorizationRequestHandler());
+ break;
+ }
+ case TdApi.AuthorizationStateWaitPassword.CONSTRUCTOR: {
+ String password = promptString("Please enter password: ");
+ client.send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler());
+ break;
+ }
+ case TdApi.AuthorizationStateReady.CONSTRUCTOR:
+ haveAuthorization = true;
+ authorizationLock.lock();
+ try {
+ gotAuthorization.signal();
+ } finally {
+ authorizationLock.unlock();
+ }
+ break;
+ case TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR:
+ haveAuthorization = false;
+ print("Logging out");
+ break;
+ case TdApi.AuthorizationStateClosing.CONSTRUCTOR:
+ haveAuthorization = false;
+ print("Closing");
+ break;
+ case TdApi.AuthorizationStateClosed.CONSTRUCTOR:
+ print("Closed");
+ if (!quiting) {
+ client = Client.create(new UpdatesHandler(), null, null); // recreate client after previous has closed
+ }
+ break;
+ default:
+ System.err.println("Unsupported authorization state:" + newLine + Example.authorizationState);
+ }
+ }
+
+ private static int toInt(String arg) {
+ int result = 0;
+ try {
+ result = Integer.parseInt(arg);
+ } catch (NumberFormatException ignored) {
+ }
+ return result;
+ }
+
+ private static long getChatId(String arg) {
+ long chatId = 0;
+ try {
+ chatId = Long.parseLong(arg);
+ } catch (NumberFormatException ignored) {
+ }
+ return chatId;
+ }
+
+ private static String promptString(String prompt) {
+ System.out.print(prompt);
+ currentPrompt = prompt;
+ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+ String str = "";
+ try {
+ str = reader.readLine();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ currentPrompt = null;
+ return str;
+ }
+
+ private static void getCommand() {
+ String command = promptString(commandsLine);
+ String[] commands = command.split(" ", 2);
+ try {
+ switch (commands[0]) {
+ case "gcs": {
+ int limit = 20;
+ if (commands.length > 1) {
+ limit = toInt(commands[1]);
+ }
+ getChatList(limit);
+ break;
+ }
+ case "gc":
+ client.send(new TdApi.GetChat(getChatId(commands[1])), defaultHandler);
+ break;
+ case "me":
+ client.send(new TdApi.GetMe(), defaultHandler);
+ break;
+ case "sm": {
+ String[] args = commands[1].split(" ", 2);
+ sendMessage(getChatId(args[0]), args[1]);
+ break;
+ }
+ case "lo":
+ haveAuthorization = false;
+ client.send(new TdApi.LogOut(), defaultHandler);
+ break;
+ case "q":
+ quiting = true;
+ haveAuthorization = false;
+ client.send(new TdApi.Close(), defaultHandler);
+ break;
+ default:
+ System.err.println("Unsupported command: " + command);
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ print("Not enough arguments");
+ }
+ }
+
+ private static void getChatList(final int limit) {
+ synchronized (chatList) {
+ if (!haveFullChatList && limit > chatList.size()) {
+ // have enough chats in the chat list or chat list is too small
+ long offsetOrder = Long.MAX_VALUE;
+ long offsetChatId = 0;
+ if (!chatList.isEmpty()) {
+ OrderedChat last = chatList.last();
+ offsetOrder = last.order;
+ offsetChatId = last.chatId;
+ }
+ client.send(new TdApi.GetChats(offsetOrder, offsetChatId, limit - chatList.size()), new Client.ResultHandler() {
+ @Override
+ public void onResult(TdApi.Object object) {
+ switch (object.getConstructor()) {
+ case TdApi.Error.CONSTRUCTOR:
+ System.err.println("Receive an error for GetChats:" + newLine + object);
+ break;
+ case TdApi.Chats.CONSTRUCTOR:
+ long[] chatIds = ((TdApi.Chats) object).chatIds;
+ if (chatIds.length == 0) {
+ synchronized (chatList) {
+ haveFullChatList = true;
+ }
+ }
+ // chats had already been received through updates, let's retry request
+ getChatList(limit);
+ break;
+ default:
+ System.err.println("Receive wrong response from TDLib:" + newLine + object);
+ }
+ }
+ });
+ return;
+ }
+
+ // have enough chats in the chat list to answer request
+ java.util.Iterator<OrderedChat> iter = chatList.iterator();
+ System.out.println();
+ System.out.println("First " + limit + " chat(s) out of " + chatList.size() + " known chat(s):");
+ for (int i = 0; i < limit; i++) {
+ long chatId = iter.next().chatId;
+ TdApi.Chat chat = chats.get(chatId);
+ synchronized (chat) {
+ System.out.println(chatId + ": " + chat.title);
+ }
+ }
+ print("");
+ }
+ }
+
+ private static void sendMessage(long chatId, String message) {
+ // initialize reply markup just for testing
+ TdApi.InlineKeyboardButton[] row = {new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl())};
+ TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][]{row, row, row});
+
+ TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true);
+ client.send(new TdApi.SendMessage(chatId, 0, false, false, replyMarkup, content), defaultHandler);
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+ // disable TDLib log
+ Log.setVerbosityLevel(0);
+ if (!Log.setFilePath("tdlib.log")) {
+ throw new IOError(new IOException("Write access to the current directory is required"));
+ }
+
+ // create client
+ client = Client.create(new UpdatesHandler(), null, null);
+
+ // test Client.execute
+ defaultHandler.onResult(Client.execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test")));
+
+ // main loop
+ while (!quiting) {
+ // await authorization
+ authorizationLock.lock();
+ try {
+ while (!haveAuthorization) {
+ gotAuthorization.await();
+ }
+ } finally {
+ authorizationLock.unlock();
+ }
+
+ while (haveAuthorization) {
+ getCommand();
+ }
+ }
+ }
+
+ private static class OrderedChat implements Comparable<OrderedChat> {
+ final long order;
+ final long chatId;
+
+ OrderedChat(long order, long chatId) {
+ this.order = order;
+ this.chatId = chatId;
+ }
+
+ @Override
+ public int compareTo(OrderedChat o) {
+ if (this.order != o.order) {
+ return o.order < this.order ? -1 : 1;
+ }
+ if (this.chatId != o.chatId) {
+ return o.chatId < this.chatId ? -1 : 1;
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ OrderedChat o = (OrderedChat) obj;
+ return this.order == o.order && this.chatId == o.chatId;
+ }
+ }
+
+ private static class DefaultHandler implements Client.ResultHandler {
+ @Override
+ public void onResult(TdApi.Object object) {
+ print(object.toString());
+ }
+ }
+
+ private static class UpdatesHandler implements Client.ResultHandler {
+ @Override
+ public void onResult(TdApi.Object object) {
+ switch (object.getConstructor()) {
+ case TdApi.UpdateAuthorizationState.CONSTRUCTOR:
+ onAuthorizationStateUpdated(((TdApi.UpdateAuthorizationState) object).authorizationState);
+ break;
+
+ case TdApi.UpdateUser.CONSTRUCTOR:
+ TdApi.UpdateUser updateUser = (TdApi.UpdateUser) object;
+ users.put(updateUser.user.id, updateUser.user);
+ break;
+ case TdApi.UpdateUserStatus.CONSTRUCTOR: {
+ TdApi.UpdateUserStatus updateUserStatus = (TdApi.UpdateUserStatus) object;
+ TdApi.User user = users.get(updateUserStatus.userId);
+ synchronized (user) {
+ user.status = updateUserStatus.status;
+ }
+ break;
+ }
+ case TdApi.UpdateBasicGroup.CONSTRUCTOR:
+ TdApi.UpdateBasicGroup updateBasicGroup = (TdApi.UpdateBasicGroup) object;
+ basicGroups.put(updateBasicGroup.basicGroup.id, updateBasicGroup.basicGroup);
+ break;
+ case TdApi.UpdateSupergroup.CONSTRUCTOR:
+ TdApi.UpdateSupergroup updateSupergroup = (TdApi.UpdateSupergroup) object;
+ supergroups.put(updateSupergroup.supergroup.id, updateSupergroup.supergroup);
+ break;
+ case TdApi.UpdateSecretChat.CONSTRUCTOR:
+ TdApi.UpdateSecretChat updateSecretChat = (TdApi.UpdateSecretChat) object;
+ secretChats.put(updateSecretChat.secretChat.id, updateSecretChat.secretChat);
+ break;
+
+ case TdApi.UpdateNewChat.CONSTRUCTOR: {
+ TdApi.UpdateNewChat updateNewChat = (TdApi.UpdateNewChat) object;
+ TdApi.Chat chat = updateNewChat.chat;
+ synchronized (chat) {
+ chats.put(chat.id, chat);
+
+ long order = chat.order;
+ chat.order = 0;
+ setChatOrder(chat, order);
+ }
+ break;
+ }
+ case TdApi.UpdateChatTitle.CONSTRUCTOR: {
+ TdApi.UpdateChatTitle updateChat = (TdApi.UpdateChatTitle) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.title = updateChat.title;
+ }
+ break;
+ }
+ case TdApi.UpdateChatPhoto.CONSTRUCTOR: {
+ TdApi.UpdateChatPhoto updateChat = (TdApi.UpdateChatPhoto) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.photo = updateChat.photo;
+ }
+ break;
+ }
+ case TdApi.UpdateChatLastMessage.CONSTRUCTOR: {
+ TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.lastMessage = updateChat.lastMessage;
+ setChatOrder(chat, updateChat.order);
+ }
+ break;
+ }
+ case TdApi.UpdateChatOrder.CONSTRUCTOR: {
+ TdApi.UpdateChatOrder updateChat = (TdApi.UpdateChatOrder) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ setChatOrder(chat, updateChat.order);
+ }
+ break;
+ }
+ case TdApi.UpdateChatIsPinned.CONSTRUCTOR: {
+ TdApi.UpdateChatIsPinned updateChat = (TdApi.UpdateChatIsPinned) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.isPinned = updateChat.isPinned;
+ setChatOrder(chat, updateChat.order);
+ }
+ break;
+ }
+ case TdApi.UpdateChatReadInbox.CONSTRUCTOR: {
+ TdApi.UpdateChatReadInbox updateChat = (TdApi.UpdateChatReadInbox) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.lastReadInboxMessageId = updateChat.lastReadInboxMessageId;
+ chat.unreadCount = updateChat.unreadCount;
+ }
+ break;
+ }
+ case TdApi.UpdateChatReadOutbox.CONSTRUCTOR: {
+ TdApi.UpdateChatReadOutbox updateChat = (TdApi.UpdateChatReadOutbox) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.lastReadOutboxMessageId = updateChat.lastReadOutboxMessageId;
+ }
+ break;
+ }
+ case TdApi.UpdateChatUnreadMentionCount.CONSTRUCTOR: {
+ TdApi.UpdateChatUnreadMentionCount updateChat = (TdApi.UpdateChatUnreadMentionCount) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.unreadMentionCount = updateChat.unreadMentionCount;
+ }
+ break;
+ }
+ case TdApi.UpdateMessageMentionRead.CONSTRUCTOR: {
+ TdApi.UpdateMessageMentionRead updateChat = (TdApi.UpdateMessageMentionRead) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.unreadMentionCount = updateChat.unreadMentionCount;
+ }
+ break;
+ }
+ case TdApi.UpdateChatReplyMarkup.CONSTRUCTOR: {
+ TdApi.UpdateChatReplyMarkup updateChat = (TdApi.UpdateChatReplyMarkup) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.replyMarkupMessageId = updateChat.replyMarkupMessageId;
+ }
+ break;
+ }
+ case TdApi.UpdateChatDraftMessage.CONSTRUCTOR: {
+ TdApi.UpdateChatDraftMessage updateChat = (TdApi.UpdateChatDraftMessage) object;
+ TdApi.Chat chat = chats.get(updateChat.chatId);
+ synchronized (chat) {
+ chat.draftMessage = updateChat.draftMessage;
+ setChatOrder(chat, updateChat.order);
+ }
+ break;
+ }
+ case TdApi.UpdateNotificationSettings.CONSTRUCTOR: {
+ TdApi.UpdateNotificationSettings update = (TdApi.UpdateNotificationSettings) object;
+ if (update.scope instanceof TdApi.NotificationSettingsScopeChat) {
+ TdApi.Chat chat = chats.get(((TdApi.NotificationSettingsScopeChat) update.scope).chatId);
+ synchronized (chat) {
+ chat.notificationSettings = update.notificationSettings;
+ }
+ }
+ break;
+ }
+
+ case TdApi.UpdateUserFullInfo.CONSTRUCTOR:
+ TdApi.UpdateUserFullInfo updateUserFullInfo = (TdApi.UpdateUserFullInfo) object;
+ usersFullInfo.put(updateUserFullInfo.userId, updateUserFullInfo.userFullInfo);
+ break;
+ case TdApi.UpdateBasicGroupFullInfo.CONSTRUCTOR:
+ TdApi.UpdateBasicGroupFullInfo updateBasicGroupFullInfo = (TdApi.UpdateBasicGroupFullInfo) object;
+ basicGroupsFullInfo.put(updateBasicGroupFullInfo.basicGroupId, updateBasicGroupFullInfo.basicGroupFullInfo);
+ break;
+ case TdApi.UpdateSupergroupFullInfo.CONSTRUCTOR:
+ TdApi.UpdateSupergroupFullInfo updateSupergroupFullInfo = (TdApi.UpdateSupergroupFullInfo) object;
+ supergroupsFullInfo.put(updateSupergroupFullInfo.supergroupId, updateSupergroupFullInfo.supergroupFullInfo);
+ break;
+ default:
+ // print("Unsupported update:" + newLine + object);
+ }
+ }
+ }
+
+ private static class AuthorizationRequestHandler implements Client.ResultHandler {
+ @Override
+ public void onResult(TdApi.Object object) {
+ switch (object.getConstructor()) {
+ case TdApi.Error.CONSTRUCTOR:
+ System.err.println("Receive an error:" + newLine + object);
+ onAuthorizationStateUpdated(null); // repeat last action
+ break;
+ case TdApi.Ok.CONSTRUCTOR:
+ // result is already received through UpdateAuthorizationState, nothing to do
+ break;
+ default:
+ System.err.println("Receive wrong response from TDLib:" + newLine + object);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/java/td_jni.cpp b/protocols/Telegram/tdlib/td/example/java/td_jni.cpp
new file mode 100644
index 0000000000..b9ba74a402
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/java/td_jni.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+#include <td/telegram/Client.h>
+#include <td/telegram/Log.h>
+#include <td/telegram/td_api.h>
+
+#include <td/tl/tl_jni_object.h>
+
+#include <cstdint>
+#include <cstdlib>
+#include <string>
+#include <utility>
+
+namespace td_jni {
+
+static td::td_api::object_ptr<td::td_api::Function> fetch_function(JNIEnv *env, jobject function) {
+ td::jni::reset_parse_error();
+ auto result = td::td_api::Function::fetch(env, function);
+ if (td::jni::have_parse_error()) {
+ std::abort();
+ }
+ return result;
+}
+
+static td::Client *get_client(jlong client_id) {
+ return reinterpret_cast<td::Client *>(static_cast<std::uintptr_t>(client_id));
+}
+
+static jlong Client_createNativeClient(JNIEnv *env, jclass clazz) {
+ return static_cast<jlong>(reinterpret_cast<std::uintptr_t>(new td::Client()));
+}
+
+static void Client_nativeClientSend(JNIEnv *env, jclass clazz, jlong client_id, jlong id, jobject function) {
+ get_client(client_id)->send({static_cast<std::uint64_t>(id), fetch_function(env, function)});
+}
+
+static jint Client_nativeClientReceive(JNIEnv *env, jclass clazz, jlong client_id, jlongArray ids, jobjectArray events,
+ jdouble timeout) {
+ auto client = get_client(client_id);
+ jsize events_size = env->GetArrayLength(ids); // ids and events size must be of equal size
+ jsize result_size = 0;
+
+ auto response = client->receive(timeout);
+ while (response.object && result_size < events_size) {
+ jlong result_id = static_cast<jlong>(response.id);
+ env->SetLongArrayRegion(ids, result_size, 1, &result_id);
+
+ jobject object;
+ response.object->store(env, object);
+ env->SetObjectArrayElement(events, result_size, object);
+ env->DeleteLocalRef(object);
+
+ result_size++;
+ response = client->receive(0);
+ }
+ return result_size;
+}
+
+static jobject Client_nativeClientExecute(JNIEnv *env, jclass clazz, jobject function) {
+ jobject result;
+ td::Client::execute({0, fetch_function(env, function)}).object->store(env, result);
+ return result;
+}
+
+static void Client_destroyNativeClient(JNIEnv *env, jclass clazz, jlong client_id) {
+ delete get_client(client_id);
+}
+
+static void Log_setVerbosityLevel(JNIEnv *env, jclass clazz, jint new_log_verbosity_level) {
+ td::Log::set_verbosity_level(static_cast<int>(new_log_verbosity_level));
+}
+
+static jboolean Log_setFilePath(JNIEnv *env, jclass clazz, jstring file_path) {
+ return td::Log::set_file_path(td::jni::from_jstring(env, file_path)) ? JNI_TRUE : JNI_FALSE;
+}
+
+static void Log_setMaxFileSize(JNIEnv *env, jclass clazz, jlong max_file_size) {
+ td::Log::set_max_file_size(max_file_size);
+}
+
+static jstring Object_toString(JNIEnv *env, jobject object) {
+ return td::jni::to_jstring(env, to_string(td::td_api::Object::fetch(env, object)));
+}
+
+static jstring Function_toString(JNIEnv *env, jobject object) {
+ return td::jni::to_jstring(env, to_string(td::td_api::Function::fetch(env, object)));
+}
+
+static constexpr jint JAVA_VERSION = JNI_VERSION_1_6;
+static JavaVM *java_vm;
+static jclass log_class;
+
+static void on_fatal_error(const char *error_message) {
+ auto env = td::jni::get_jni_env(java_vm, JAVA_VERSION);
+ jmethodID on_fatal_error_method = env->GetStaticMethodID(log_class, "onFatalError", "(Ljava/lang/String;)V");
+ if (env && on_fatal_error_method) {
+ jstring error_str = td::jni::to_jstring(env.get(), error_message);
+ env->CallStaticVoidMethod(log_class, on_fatal_error_method, error_str);
+ if (error_str) {
+ env->DeleteLocalRef(error_str);
+ }
+ }
+}
+
+static jint register_native(JavaVM *vm) {
+ JNIEnv *env;
+ if (vm->GetEnv(reinterpret_cast<void **>(&env), JAVA_VERSION) != JNI_OK) {
+ return -1;
+ }
+
+ java_vm = vm;
+
+ auto register_method = [env](jclass clazz, std::string name, std::string signature, auto function_ptr) {
+ td::jni::register_native_method(env, clazz, std::move(name), std::move(signature),
+ reinterpret_cast<void *>(function_ptr));
+ };
+
+ auto client_class = td::jni::get_jclass(env, PACKAGE_NAME "/Client");
+ log_class = td::jni::get_jclass(env, PACKAGE_NAME "/Log");
+ auto object_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi$Object");
+ auto function_class = td::jni::get_jclass(env, PACKAGE_NAME "/TdApi$Function");
+
+#define TD_OBJECT "L" PACKAGE_NAME "/TdApi$Object;"
+#define TD_FUNCTION "L" PACKAGE_NAME "/TdApi$Function;"
+ register_method(client_class, "createNativeClient", "()J", Client_createNativeClient);
+ register_method(client_class, "nativeClientSend", "(JJ" TD_FUNCTION ")V", Client_nativeClientSend);
+ register_method(client_class, "nativeClientReceive", "(J[J[" TD_OBJECT "D)I", Client_nativeClientReceive);
+ register_method(client_class, "nativeClientExecute", "(" TD_FUNCTION ")" TD_OBJECT, Client_nativeClientExecute);
+ register_method(client_class, "destroyNativeClient", "(J)V", Client_destroyNativeClient);
+
+ register_method(log_class, "setVerbosityLevel", "(I)V", Log_setVerbosityLevel);
+ register_method(log_class, "setFilePath", "(Ljava/lang/String;)Z", Log_setFilePath);
+ register_method(log_class, "setMaxFileSize", "(J)V", Log_setMaxFileSize);
+
+ register_method(object_class, "toString", "()Ljava/lang/String;", Object_toString);
+
+ register_method(function_class, "toString", "()Ljava/lang/String;", Function_toString);
+#undef TD_FUNCTION
+#undef TD_OBJECT
+
+ td::jni::init_vars(env, PACKAGE_NAME);
+ td::td_api::Object::init_jni_vars(env, PACKAGE_NAME);
+ td::td_api::Function::init_jni_vars(env, PACKAGE_NAME);
+ td::Log::set_fatal_error_callback(on_fatal_error);
+
+ return JAVA_VERSION;
+}
+
+} // namespace td_jni
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
+ static jint jni_version = td_jni::register_native(vm); // call_once
+ return jni_version;
+}
diff --git a/protocols/Telegram/tdlib/td/example/python/README.md b/protocols/Telegram/tdlib/td/example/python/README.md
new file mode 100644
index 0000000000..c4a4ad3768
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/python/README.md
@@ -0,0 +1,11 @@
+# TDLib Python example
+
+To run this example you need to [build](https://github.com/tdlib/td#building) TDLib and copy built tdjson shared library to this directory.
+
+Then you can run the example:
+```
+python tdjson_example.py
+```
+
+Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html),
+[td_log](https://core.telegram.org/tdlib/docs/td__log_8h.html) and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation.
diff --git a/protocols/Telegram/tdlib/td/example/python/tdjson_example.py b/protocols/Telegram/tdlib/td/example/python/tdjson_example.py
new file mode 100644
index 0000000000..d7b2e86fbb
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/python/tdjson_example.py
@@ -0,0 +1,106 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+from ctypes.util import find_library
+from ctypes import *
+import json
+import sys
+
+# load shared library
+tdjson_path = find_library("tdjson") or "tdjson.dll"
+if tdjson_path is None:
+ print('can\'t find tdjson library')
+ quit()
+tdjson = CDLL(tdjson_path)
+
+# load TDLib functions from shared library
+td_json_client_create = tdjson.td_json_client_create
+td_json_client_create.restype = c_void_p
+td_json_client_create.argtypes = []
+
+td_json_client_receive = tdjson.td_json_client_receive
+td_json_client_receive.restype = c_char_p
+td_json_client_receive.argtypes = [c_void_p, c_double]
+
+td_json_client_send = tdjson.td_json_client_send
+td_json_client_send.restype = None
+td_json_client_send.argtypes = [c_void_p, c_char_p]
+
+td_json_client_execute = tdjson.td_json_client_execute
+td_json_client_execute.restype = c_char_p
+td_json_client_execute.argtypes = [c_void_p, c_char_p]
+
+td_json_client_destroy = tdjson.td_json_client_destroy
+td_json_client_destroy.restype = None
+td_json_client_destroy.argtypes = [c_void_p]
+
+td_set_log_file_path = tdjson.td_set_log_file_path
+td_set_log_file_path.restype = c_int
+td_set_log_file_path.argtypes = [c_char_p]
+
+td_set_log_max_file_size = tdjson.td_set_log_max_file_size
+td_set_log_max_file_size.restype = None
+td_set_log_max_file_size.argtypes = [c_longlong]
+
+td_set_log_verbosity_level = tdjson.td_set_log_verbosity_level
+td_set_log_verbosity_level.restype = None
+td_set_log_verbosity_level.argtypes = [c_int]
+
+fatal_error_callback_type = CFUNCTYPE(None, c_char_p)
+
+td_set_log_fatal_error_callback = tdjson.td_set_log_fatal_error_callback
+td_set_log_fatal_error_callback.restype = None
+td_set_log_fatal_error_callback.argtypes = [fatal_error_callback_type]
+
+# initialize TDLib log with desired parameters
+def on_fatal_error_callback(error_message):
+ print('TDLib fatal error: ', error_message)
+
+td_set_log_verbosity_level(2)
+c_on_fatal_error_callback = fatal_error_callback_type(on_fatal_error_callback)
+td_set_log_fatal_error_callback(c_on_fatal_error_callback)
+
+# create client
+client = td_json_client_create()
+
+# simple wrappers for client usage
+def td_send(query):
+ query = json.dumps(query).encode('utf-8')
+ td_json_client_send(client, query)
+
+def td_receive():
+ result = td_json_client_receive(client, 1.0)
+ if result:
+ result = json.loads(result.decode('utf-8'))
+ return result
+
+def td_execute(query):
+ query = json.dumps(query).encode('utf-8')
+ result = td_json_client_execute(client, query)
+ if result:
+ result = json.loads(result.decode('utf-8'))
+ return result
+
+# testing TDLib execute method
+print(td_execute({'@type': 'getTextEntities', 'text': '@telegram /test_command https://telegram.org telegram.me', '@extra': ['5', 7.0]}))
+
+# testing TDLib send method
+td_send({'@type': 'getAuthorizationState', '@extra': 1.01234})
+
+# main events cycle
+while True:
+ event = td_receive()
+ if event:
+ # if client is closed, we need to destroy it and create new client
+ if event['@type'] is 'updateAuthorizationState' and event['authorization_state']['@type'] is 'authorizationStateClosed':
+ break
+
+ # handle an incoming update or an answer to a previously sent request
+ print(event)
+ sys.stdout.flush()
+
+# destroy client when it is closed and isn't needed anymore
+td_json_client_destroy(client)
diff --git a/protocols/Telegram/tdlib/td/example/ruby/Gemfile b/protocols/Telegram/tdlib/td/example/ruby/Gemfile
new file mode 100644
index 0000000000..3a38ffc0a3
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/ruby/Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+
+gem 'tdlib-ruby'
diff --git a/protocols/Telegram/tdlib/td/example/ruby/Gemfile.lock b/protocols/Telegram/tdlib/td/example/ruby/Gemfile.lock
new file mode 100644
index 0000000000..22954eddfb
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/ruby/Gemfile.lock
@@ -0,0 +1,17 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ concurrent-ruby (1.0.5)
+ dry-configurable (0.7.0)
+ concurrent-ruby (~> 1.0)
+ tdlib-ruby (0.2.0)
+ dry-configurable (~> 0.7)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ tdlib-ruby
+
+BUNDLED WITH
+ 1.16.1
diff --git a/protocols/Telegram/tdlib/td/example/ruby/example.rb b/protocols/Telegram/tdlib/td/example/ruby/example.rb
new file mode 100644
index 0000000000..4b29dfd53a
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/ruby/example.rb
@@ -0,0 +1,61 @@
+require 'tdlib-ruby'
+
+TD.configure do |config|
+ config.lib_path = 'path/to/dir_containing_lobtdjson'
+
+ # You should obtain your own api_id and api_hash from https://my.telegram.org/apps
+ config.client.api_id = 12345
+ config.client.api_hash = '1234567890abcdefghigklmnopqrstuv'
+end
+
+TD::Api.set_log_verbosity_level(1)
+
+client = TD::Client.new
+
+begin
+ state = nil
+
+ client.on('updateAuthorizationState') do |update|
+ next unless update.dig('authorization_state', '@type') == 'authorizationStateWaitPhoneNumber'
+ state = :wait_phone
+ end
+
+ client.on('updateAuthorizationState') do |update|
+ next unless update.dig('authorization_state', '@type') == 'authorizationStateWaitCode'
+ state = :wait_code
+ end
+
+ client.on('updateAuthorizationState') do |update|
+ next unless update.dig('authorization_state', '@type') == 'authorizationStateReady'
+ state = :ready
+ end
+
+ loop do
+ case state
+ when :wait_phone
+ p 'Please, enter your phone number:'
+ phone = STDIN.gets.strip
+ params = {
+ '@type' => 'setAuthenticationPhoneNumber',
+ 'phone_number' => phone
+ }
+ client.broadcast_and_receive(params)
+ when :wait_code
+ p 'Please, enter code from SMS:'
+ code = STDIN.gets.strip
+ params = {
+ '@type' => 'checkAuthenticationCode',
+ 'code' => code
+ }
+ client.broadcast_and_receive(params)
+ when :ready
+ @me = client.broadcast_and_receive('@type' => 'getMe')
+ break
+ end
+ end
+
+ensure
+ client.close
+end
+
+p @me
diff --git a/protocols/Telegram/tdlib/td/example/swift/.gitignore b/protocols/Telegram/tdlib/td/example/swift/.gitignore
new file mode 100644
index 0000000000..4737be5996
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/swift/.gitignore
@@ -0,0 +1,3 @@
+xcuserdata/
+*workspace/
+td/
diff --git a/protocols/Telegram/tdlib/td/example/swift/README.md b/protocols/Telegram/tdlib/td/example/swift/README.md
new file mode 100644
index 0000000000..6a333df766
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/swift/README.md
@@ -0,0 +1,15 @@
+# TDLib swift MacOS example
+
+TDLib should be prebuilt and installed to local subdirectory `td/`:
+```
+cd <path to TDLib sources>
+mkdir build
+cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=../example/swift/td ..
+cmake --build . --target install
+```
+
+Then you can open and build the example with the latest Xcode.
+
+Description of all available classes and methods can be found at [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html),
+[td_log](https://core.telegram.org/tdlib/docs/td__log_8h.html) and [td_api](https://core.telegram.org/tdlib/docs/td__api_8h.html) documentation.
diff --git a/protocols/Telegram/tdlib/td/example/swift/src/main.swift b/protocols/Telegram/tdlib/td/example/swift/src/main.swift
new file mode 100644
index 0000000000..ac81c632b8
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/swift/src/main.swift
@@ -0,0 +1,178 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+import Foundation
+
+// TDLib Client Swift binding
+class TdClient {
+ typealias Client = UnsafeMutableRawPointer
+ var client = td_json_client_create()!
+ let tdlibMainLoop = DispatchQueue(label: "TDLib")
+ let tdlibQueryQueue = DispatchQueue(label: "TDLibQuery")
+ var queryF = Dictionary<Int64, (Dictionary<String,Any>)->()>()
+ var updateF: ((Dictionary<String,Any>)->())?
+ var queryId: Int64 = 0
+
+ func queryAsync(query: [String: Any], f: ((Dictionary<String,Any>)->())? = nil) {
+ tdlibQueryQueue.async {
+ var newQuery = query
+
+ if f != nil {
+ let nextQueryId = self.queryId + 1
+ newQuery["@extra"] = nextQueryId
+ self.queryF[nextQueryId] = f
+ self.queryId = nextQueryId
+ }
+ td_json_client_send(self.client, to_json(newQuery))
+ }
+ }
+
+ func querySync(query: [String: Any]) -> Dictionary<String,Any> {
+ let semaphore = DispatchSemaphore(value:0)
+ var result = Dictionary<String,Any>()
+ queryAsync(query: query) {
+ result = $0
+ semaphore.signal()
+ }
+ semaphore.wait()
+ return result
+ }
+
+ init() {
+ }
+
+ deinit {
+ td_json_client_destroy(client)
+ }
+
+ func run(updateHandler: @escaping (Dictionary<String,Any>)->()) {
+ updateF = updateHandler
+ tdlibMainLoop.async { [weak self] in
+ while (true) {
+ if let s = self {
+ if let res = td_json_client_receive(s.client, 10) {
+ let event = String(cString: res)
+ s.queryResultAsync(event)
+ }
+ } else {
+ break
+ }
+ }
+ }
+ }
+
+ private func queryResultAsync(_ result: String) {
+ tdlibQueryQueue.async {
+ let json = try? JSONSerialization.jsonObject(with: result.data(using: .utf8)!, options:[])
+ if let dictionary = json as? [String:Any] {
+ if let extra = dictionary["@extra"] as? Int64 {
+ let index = self.queryF.index(forKey: extra)!
+ self.queryF[index].value(dictionary)
+ self.queryF.remove(at: index)
+ } else {
+ self.updateF!(dictionary)
+ }
+ }
+ }
+ }
+}
+
+func to_json(_ obj: Any) -> String {
+ do {
+ let obj = try JSONSerialization.data(withJSONObject: obj)
+ return String(data: obj, encoding: .utf8)!
+ } catch {
+ return ""
+ }
+}
+
+
+// An example of usage
+td_set_log_verbosity_level(1);
+
+var client = TdClient()
+
+func myReadLine() -> String {
+ while (true) {
+ if let line = readLine() {
+ return line
+ }
+ }
+}
+
+func updateAuthorizationState(authorizationState: Dictionary<String, Any>) {
+ switch(authorizationState["@type"] as! String) {
+ case "authorizationStateWaitTdlibParameters":
+ client.queryAsync(query:[
+ "@type":"setTdlibParameters",
+ "parameters":[
+ "database_directory":"tdlib",
+ "use_message_database":true,
+ "use_secret_chats":true,
+ "api_id":94575,
+ "api_hash":"a3406de8d171bb422bb6ddf3bbd800e2",
+ "system_language_code":"en",
+ "device_model":"Desktop",
+ "system_version":"Unknown",
+ "application_version":"1.0",
+ "enable_storage_optimizer":true
+ ]
+ ]);
+
+ case "authorizationStateWaitEncryptionKey":
+ client.queryAsync(query: ["@type":"checkDatabaseEncryptionKey", "key":"cucumber"])
+
+ case "authorizationStateWaitPhoneNumber":
+ print("Enter your phone: ")
+ let phone = myReadLine()
+ client.queryAsync(query:["@type":"setAuthenticationPhoneNumber", "phone_number":phone], f:checkAuthenticationError)
+
+ case "authorizationStateWaitCode":
+ var first_name: String = ""
+ var last_name: String = ""
+ var code: String = ""
+ if let is_registered = authorizationState["is_registered"] as? Bool, is_registered {
+ } else {
+ print("Enter your first name: ")
+ first_name = myReadLine()
+ print("Enter your last name: ")
+ last_name = myReadLine()
+ }
+ print("Enter (SMS) code: ")
+ code = myReadLine()
+ client.queryAsync(query:["@type":"checkAuthenticationCode", "code":code, "first_name":first_name, "last_name":last_name], f:checkAuthenticationError)
+
+ case "authorizationStateWaitPassword":
+ print("Enter password: ")
+ let password = myReadLine()
+ client.queryAsync(query:["@type":"checkAuthenticationPassword", "password":password], f:checkAuthenticationError)
+
+ case "authorizationStateReady":
+ ()
+
+ default:
+ assert(false, "TODO: Unknown authorization state");
+ }
+}
+
+func checkAuthenticationError(error: Dictionary<String, Any>) {
+ if (error["@type"] as! String == "error") {
+ client.queryAsync(query:["@type":"getAuthorizationState"], f:updateAuthorizationState)
+ }
+}
+
+client.run {
+ let update = $0
+ print(update)
+ if update["@type"] as! String == "updateAuthorizationState" {
+ updateAuthorizationState(authorizationState: update["authorization_state"] as! Dictionary<String, Any>)
+ }
+}
+
+while true {
+ sleep(1)
+}
diff --git a/protocols/Telegram/tdlib/td/example/swift/src/td-Bridging-Header.h b/protocols/Telegram/tdlib/td/example/swift/src/td-Bridging-Header.h
new file mode 100644
index 0000000000..434ab2e4a4
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/swift/src/td-Bridging-Header.h
@@ -0,0 +1,15 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+#include "td/telegram/td_json_client.h"
+#include "td/telegram/td_log.h"
diff --git a/protocols/Telegram/tdlib/td/example/swift/td.xcodeproj/project.pbxproj b/protocols/Telegram/tdlib/td/example/swift/td.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000..7b774c421c
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/swift/td.xcodeproj/project.pbxproj
@@ -0,0 +1,310 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1F65E3A42031BF6A00F79763 /* libtdjson.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F65E3A32031BF6A00F79763 /* libtdjson.dylib */; };
+ 1F65E3A92031C0F000F79763 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F65E3A82031C0F000F79763 /* main.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 1FCE2CEF1EC5E1B50061661A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1F65E3A32031BF6A00F79763 /* libtdjson.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtdjson.dylib; path = td/lib/libtdjson.dylib; sourceTree = "<group>"; };
+ 1F65E3A82031C0F000F79763 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = main.swift; path = src/main.swift; sourceTree = SOURCE_ROOT; };
+ 1F65E3AA2031C14300F79763 /* td-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "td-Bridging-Header.h"; path = "src/td-Bridging-Header.h"; sourceTree = SOURCE_ROOT; };
+ 1FCE2CF11EC5E1B50061661A /* td */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = td; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 1FCE2CEE1EC5E1B50061661A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1F65E3A42031BF6A00F79763 /* libtdjson.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 1FCE2CE81EC5E1B50061661A = {
+ isa = PBXGroup;
+ children = (
+ 1FCE2CF31EC5E1B50061661A /* src */,
+ 1FCE2CF21EC5E1B50061661A /* Products */,
+ 1FCE2CFB1EC5E1EE0061661A /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 1FCE2CF21EC5E1B50061661A /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 1FCE2CF11EC5E1B50061661A /* td */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 1FCE2CF31EC5E1B50061661A /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 1F65E3AA2031C14300F79763 /* td-Bridging-Header.h */,
+ 1F65E3A82031C0F000F79763 /* main.swift */,
+ );
+ name = src;
+ path = td;
+ sourceTree = "<group>";
+ };
+ 1FCE2CFB1EC5E1EE0061661A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1F65E3A32031BF6A00F79763 /* libtdjson.dylib */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 1FCE2CF01EC5E1B50061661A /* td */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1FCE2CF81EC5E1B50061661A /* Build configuration list for PBXNativeTarget "td" */;
+ buildPhases = (
+ 1FCE2CED1EC5E1B50061661A /* Sources */,
+ 1FCE2CEE1EC5E1B50061661A /* Frameworks */,
+ 1FCE2CEF1EC5E1B50061661A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = td;
+ productName = td;
+ productReference = 1FCE2CF11EC5E1B50061661A /* td */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 1FCE2CE91EC5E1B50061661A /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0830;
+ LastUpgradeCheck = 0920;
+ ORGANIZATIONNAME = "Arseny Smirnov ";
+ TargetAttributes = {
+ 1FCE2CF01EC5E1B50061661A = {
+ CreatedOnToolsVersion = 8.3.2;
+ LastSwiftMigration = 0920;
+ ProvisioningStyle = Automatic;
+ };
+ };
+ };
+ buildConfigurationList = 1FCE2CEC1EC5E1B50061661A /* Build configuration list for PBXProject "td" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 1FCE2CE81EC5E1B50061661A;
+ productRefGroup = 1FCE2CF21EC5E1B50061661A /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 1FCE2CF01EC5E1B50061661A /* td */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 1FCE2CED1EC5E1B50061661A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1F65E3A92031C0F000F79763 /* main.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1FCE2CF61EC5E1B50061661A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.12;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ };
+ name = Debug;
+ };
+ 1FCE2CF71EC5E1B50061661A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.12;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = macosx;
+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ };
+ name = Release;
+ };
+ 1FCE2CF91EC5E1B50061661A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(PROJECT_DIR)/lib";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/td/lib",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "src/td-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ USER_HEADER_SEARCH_PATHS = td/include/;
+ };
+ name = Debug;
+ };
+ 1FCE2CFA1EC5E1B50061661A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(PROJECT_DIR)/lib";
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(PROJECT_DIR)/td/lib",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OBJC_BRIDGING_HEADER = "src/td-Bridging-Header.h";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ USER_HEADER_SEARCH_PATHS = td/include/;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1FCE2CEC1EC5E1B50061661A /* Build configuration list for PBXProject "td" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1FCE2CF61EC5E1B50061661A /* Debug */,
+ 1FCE2CF71EC5E1B50061661A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1FCE2CF81EC5E1B50061661A /* Build configuration list for PBXNativeTarget "td" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1FCE2CF91EC5E1B50061661A /* Debug */,
+ 1FCE2CFA1EC5E1B50061661A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 1FCE2CE91EC5E1B50061661A /* Project object */;
+}
diff --git a/protocols/Telegram/tdlib/td/example/uwp/LICENSE_1_0.txt b/protocols/Telegram/tdlib/td/example/uwp/LICENSE_1_0.txt
new file mode 100644
index 0000000000..36b7cd93cd
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/protocols/Telegram/tdlib/td/example/uwp/README.md b/protocols/Telegram/tdlib/td/example/uwp/README.md
new file mode 100644
index 0000000000..e7bb9b821b
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/README.md
@@ -0,0 +1,28 @@
+# TDLib Universal Windows Platform example
+
+This is an example of building TDLib SDK for Universal Windows Platform and an example of its usage from C#.
+
+## Building SDK
+
+* Download and install Microsoft Visual Studio 2015+ with Windows 10 SDK. We recommend to use the latest available versions of Microsoft Visual Studio and Windows 10 SDK.
+* Download and install [CMake](https://cmake.org/download/).
+* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
+* Install `zlib` and `openssl` for all UWP architectures using `vcpkg`:
+```
+C:\src\vcpkg> .\vcpkg.exe install openssl:arm-uwp openssl:x64-uwp openssl:x86-uwp zlib:arm-uwp zlib:x64-uwp zlib:x86-uwp
+```
+* (Optional. For XML documentation generation.) Download [PHP](https://windows.php.net/download#php-7.2). Add the path to php.exe to the PATH environment variable.
+* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable.
+* Download and install [7-Zip](http://www.7-zip.org/download.html) archiver, which is used by the `build.ps1` script to create a Telegram.Td.UWP Visual Studio Extension. Add the path to 7z.exe to the PATH environment variable.
+ Alternatively `build.ps1` supports compressing using [WinRAR](https://en.wikipedia.org/wiki/WinRAR) with option `-compress winrar` and compressing using [zip](http://gnuwin32.sourceforge.net/packages/zip.htm) with `-compress zip`.
+* Build `TDLib` using provided `build.ps1` script (TDLib should be built 6 times for multiple platforms in Debug and Release configurations, so it make take few hours). Pass path to vcpkg.exe as `-vcpkg-root` argument:
+```
+powershell -ExecutionPolicy ByPass .\build.ps1 -vcpkg_root C:\src\vcpkg
+```
+If you need to restart the build from scratch, call `.\build.ps1 -mode clean` first.
+* Install Visual Studio Extension "TDLib for Universal Windows Platform" located at `build-uwp\vsix\tdlib.vsix`, which was created on the previous step by `build.ps1` script.
+
+Now `TDLib` can be freely used from any UWP project, built in Visual Studio.
+
+## Example of usage
+The `app/` directory contains a simple example of a C# application for Universal Windows Platform. Just open it with Visual Studio 2015 or 2017 and run.
diff --git a/protocols/Telegram/tdlib/td/example/uwp/SDKManifest.xml b/protocols/Telegram/tdlib/td/example/uwp/SDKManifest.xml
new file mode 100644
index 0000000000..d6896fcb65
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/SDKManifest.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<FileList
+ DisplayName="TDLib for Universal Windows Platform"
+ ProductFamilyName="Telegram.Td.UWP"
+ MoreInfo="https://core.telegram.org/tdlib"
+ MinVSVersion="14.0"
+ AppliesTo="WindowsAppContainer"
+ DependsOn="Microsoft.VCLibs, version=14.0"
+ SupportsMultipleVersions="Error"
+ SupportedArchitectures="x86;x64;ARM">
+ <File Reference="Telegram.Td.winmd" Implementation="Telegram.Td.dll" />
+</FileList>
diff --git a/protocols/Telegram/tdlib/td/example/uwp/[Content_Types].xml b/protocols/Telegram/tdlib/td/example/uwp/[Content_Types].xml
new file mode 100644
index 0000000000..b91d46fa3c
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/[Content_Types].xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
+ <Default Extension="winmd" ContentType="application/octet-stream" />
+ <Default Extension="pri" ContentType="application/octet-stream" />
+ <Default Extension="dll" ContentType="application/octet-stream" />
+ <Default Extension="h" ContentType="application/octet-stream" />
+ <Default Extension="lib" ContentType="application/octet-stream" />
+ <Default Extension="pdb" ContentType="application/octet-stream" />
+ <Default Extension="png" ContentType="application/octet-stream" />
+ <Default Extension="props" ContentType="application/octet-stream" />
+ <Default Extension="txt" ContentType="text/plain" />
+ <Default Extension="vsixmanifest" ContentType="text/xml" />
+ <Default Extension="xml" ContentType="text/xml" />
+</Types>
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/.gitignore b/protocols/Telegram/tdlib/td/example/uwp/app/.gitignore
new file mode 100644
index 0000000000..37ab08165b
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/.gitignore
@@ -0,0 +1,5 @@
+.vs/
+bin/
+obj/
+project.lock.json
+TdApp.csproj.user
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/App.xaml b/protocols/Telegram/tdlib/td/example/uwp/app/App.xaml
new file mode 100644
index 0000000000..b4256fd441
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/App.xaml
@@ -0,0 +1,7 @@
+<Application
+ x:Class="TdApp.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="using:TdApp"
+ RequestedTheme="Light">
+</Application>
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/App.xaml.cs b/protocols/Telegram/tdlib/td/example/uwp/app/App.xaml.cs
new file mode 100644
index 0000000000..0ed0f96812
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/App.xaml.cs
@@ -0,0 +1,104 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+using System;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Navigation;
+
+namespace TdApp
+{
+ /// <summary>
+ /// Provides application-specific behavior to supplement the default Application class.
+ /// </summary>
+ sealed partial class App : Application
+ {
+ /// <summary>
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ /// </summary>
+ public App()
+ {
+ Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
+ Microsoft.ApplicationInsights.WindowsCollectors.Metadata |
+ Microsoft.ApplicationInsights.WindowsCollectors.Session);
+ this.InitializeComponent();
+ this.Suspending += OnSuspending;
+ }
+
+ /// <summary>
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ /// </summary>
+ /// <param name="e">Details about the launch request and process.</param>
+ protected override void OnLaunched(LaunchActivatedEventArgs e)
+ {
+
+#if DEBUG
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ this.DebugSettings.EnableFrameRateCounter = true;
+ }
+#endif
+
+ Frame rootFrame = Window.Current.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == null)
+ {
+ // Create a Frame to act as the navigation context and navigate to the first page
+ rootFrame = new Frame();
+
+ rootFrame.NavigationFailed += OnNavigationFailed;
+
+ if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
+ {
+ //TODO: Load state from previously suspended application
+ }
+
+ // Place the frame in the current Window
+ Window.Current.Content = rootFrame;
+ }
+
+ if (rootFrame.Content == null)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame.Navigate(typeof(MainPage), e.Arguments);
+ }
+ // Ensure the current window is active
+ Window.Current.Activate();
+ }
+
+ /// <summary>
+ /// Invoked when Navigation to a certain page fails
+ /// </summary>
+ /// <param name="sender">The Frame which failed navigation</param>
+ /// <param name="e">Details about the navigation failure</param>
+ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
+ }
+
+ /// <summary>
+ /// Invoked when application execution is being suspended. Application state is saved
+ /// without knowing whether the application will be terminated or resumed with the contents
+ /// of memory still intact.
+ /// </summary>
+ /// <param name="sender">The source of the suspend request.</param>
+ /// <param name="e">Details about the suspend request.</param>
+ private void OnSuspending(object sender, SuspendingEventArgs e)
+ {
+ var deferral = e.SuspendingOperation.GetDeferral();
+ //TODO: Save application state and stop any background activity
+ deferral.Complete();
+ }
+ }
+}
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/ApplicationInsights.config b/protocols/Telegram/tdlib/td/example/uwp/app/ApplicationInsights.config
new file mode 100644
index 0000000000..cb2a232da3
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/ApplicationInsights.config
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ApplicationInsights xmlns = "http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
+</ApplicationInsights>
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/LockScreenLogo.scale-200.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 0000000000..735f57adb5
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/LockScreenLogo.scale-200.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/SplashScreen.scale-200.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/SplashScreen.scale-200.png
new file mode 100644
index 0000000000..023e7f1fed
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/SplashScreen.scale-200.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square150x150Logo.scale-200.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 0000000000..af49fec1a5
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square150x150Logo.scale-200.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.scale-200.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 0000000000..ce342a2ec8
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.scale-200.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 0000000000..f6c02ce97e
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/StoreLogo.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/StoreLogo.png
new file mode 100644
index 0000000000..7385b56c0e
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/StoreLogo.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Wide310x150Logo.scale-200.png b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 0000000000..288995b397
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Assets/Wide310x150Logo.scale-200.png
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml b/protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml
new file mode 100644
index 0000000000..cdff97d9f3
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml
@@ -0,0 +1,29 @@
+<Page
+ x:Class="TdApp.MainPage"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="using:TdApp"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d"
+ x:Name="Self">
+
+ <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto"/>
+ <RowDefinition Height="*"/>
+ </Grid.RowDefinitions>
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*"/>
+ <ColumnDefinition Width="Auto"/>
+ </Grid.ColumnDefinitions>
+ <TextBox x:Name="Input"/>
+ <Button Grid.Column="1" x:Name="Send" Content="send" Click="Button_Click"/>
+ </Grid>
+ <ListBox Grid.Row="1" x:Name="ItemsControl" ItemsSource="{Binding Items, ElementName=Self}">
+
+ </ListBox>
+ <!--<Button Content="Test" Click="Button_Click"/>-->
+ </Grid>
+</Page>
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml.cs b/protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml.cs
new file mode 100644
index 0000000000..9bdf5070ee
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/MainPage.xaml.cs
@@ -0,0 +1,171 @@
+//
+// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2018
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+using System;
+using System.IO;
+using Td = Telegram.Td;
+using TdApi = Telegram.Td.Api;
+using Windows.UI.Core;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace TdApp
+{
+ public sealed partial class MainPage : Page
+ {
+ public System.Collections.ObjectModel.ObservableCollection<string> Items { get; set; }
+
+ private static MyClientResultHandler _handler;
+
+ public MainPage()
+ {
+ InitializeComponent();
+
+ Items = new System.Collections.ObjectModel.ObservableCollection<string>();
+ _handler = new MyClientResultHandler(this);
+
+ System.Threading.Tasks.Task.Run(() =>
+ {
+ try
+ {
+ Td.Log.SetFilePath(Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "log"));
+ _client = Td.Client.Create(_handler);
+ var parameters = new TdApi.TdlibParameters();
+ parameters.DatabaseDirectory = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
+ parameters.UseSecretChats = true;
+ parameters.UseMessageDatabase = true;
+ parameters.ApiId = 94575;
+ parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
+ parameters.SystemLanguageCode = "en";
+ parameters.DeviceModel = "en";
+ parameters.SystemVersion = "en";
+ parameters.ApplicationVersion = "1.0.0";
+ _client.Send(new TdApi.SetTdlibParameters(parameters), null);
+ _client.Send(new TdApi.CheckDatabaseEncryptionKey(), null);
+ _client.Run();
+ }
+ catch (Exception ex)
+ {
+ Print(ex.ToString());
+ }
+ });
+ }
+
+ public void Print(String str)
+ {
+ var delayTask = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
+ {
+ Items.Insert(0, str.Substring(0, Math.Min(1024, str.Length)));
+ });
+ }
+
+ private static Td.Client _client;
+
+ private void AcceptCommand(String command)
+ {
+ Input.Text = string.Empty;
+ Items.Insert(0, string.Format(">>{0}", command));
+ }
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ var command = Input.Text;
+
+ if (command.StartsWith("DESTROY"))
+ {
+ AcceptCommand("Destroy");
+ _client.Send(new TdApi.Destroy(), _handler);
+ }
+ else if (command.StartsWith("lo"))
+ {
+ AcceptCommand("LogOut");
+ _client.Send(new TdApi.LogOut(), _handler);
+ }
+ else if (command.StartsWith("gas"))
+ {
+ AcceptCommand(command);
+ _client.Send(new TdApi.GetAuthorizationState(), _handler);
+ }
+ else if (command.StartsWith("sap"))
+ {
+ var args = command.Split(" ".ToCharArray(), 2);
+ AcceptCommand(command);
+ _client.Send(new TdApi.SetAuthenticationPhoneNumber(args[1], false, false), _handler);
+ }
+ else if (command.StartsWith("cac"))
+ {
+ var args = command.Split(" ".ToCharArray(), 2);
+ AcceptCommand(command);
+ _client.Send(new TdApi.CheckAuthenticationCode(args[1], String.Empty, String.Empty), _handler);
+ }
+ else if (command.StartsWith("cap"))
+ {
+ var args = command.Split(" ".ToCharArray(), 2);
+ AcceptCommand(command);
+ _client.Send(new TdApi.CheckAuthenticationPassword(args[1]), _handler);
+ }
+ else if (command.StartsWith("gco"))
+ {
+ var args = command.Split(" ".ToCharArray(), 2);
+ AcceptCommand(command);
+ _client.Send(new TdApi.SearchContacts(), _handler);
+ }
+ else if (command.StartsWith("df"))
+ {
+ var args = command.Split(" ".ToCharArray(), 2);
+ AcceptCommand(command);
+ _client.Send(new TdApi.DownloadFile(Int32.Parse(args[1]), 1), _handler);
+ }
+ else if (command.StartsWith("bench"))
+ {
+ var args = command.Split(" ".ToCharArray(), 2);
+ AcceptCommand(command);
+ var cnt = Int32.Parse(args[1]);
+ var handler = new BenchSimpleHandler(this, cnt);
+ for (int i = 0; i < cnt; i++)
+ {
+ _client.Send(new TdApi.TestSquareInt(123), handler);
+ }
+ }
+ }
+ }
+
+ class MyClientResultHandler : Td.ClientResultHandler
+ {
+ private MainPage _page;
+
+ public MyClientResultHandler(MainPage page)
+ {
+ _page = page;
+ }
+
+ public void OnResult(TdApi.BaseObject obj)
+ {
+ var str = obj.ToString();
+ _page.Print(str);
+ }
+ }
+
+ class BenchSimpleHandler : Td.ClientResultHandler
+ {
+ private MainPage _page;
+ private int _cnt;
+
+ public BenchSimpleHandler(MainPage page, int cnt)
+ {
+ _page = page;
+ _cnt = cnt;
+ }
+
+ public void OnResult(TdApi.BaseObject obj)
+ {
+ _cnt--;
+ if (_cnt == 0)
+ {
+ _page.Print("DONE");
+ }
+ }
+ }
+}
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Package.appxmanifest b/protocols/Telegram/tdlib/td/example/uwp/app/Package.appxmanifest
new file mode 100644
index 0000000000..ca1235ffa7
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Package.appxmanifest
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" IgnorableNamespaces="uap mp">
+ <Identity Name="1c9ba6de-23cf-4aef-803b-91fcc451b69a" Publisher="CN=arseny30" Version="1.0.0.0" />
+ <mp:PhoneIdentity PhoneProductId="1c9ba6de-23cf-4aef-803b-91fcc451b69a" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
+ <Properties>
+ <DisplayName>TdApp</DisplayName>
+ <PublisherDisplayName>arseny30</PublisherDisplayName>
+ <Logo>Assets\StoreLogo.png</Logo>
+ </Properties>
+ <Dependencies>
+ <TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
+ </Dependencies>
+ <Resources>
+ <Resource Language="x-generate" />
+ </Resources>
+ <Applications>
+ <Application Id="App" Executable="$targetnametoken$.exe" EntryPoint="TdApp.App">
+ <uap:VisualElements DisplayName="TdApp" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="TdApp" BackgroundColor="transparent">
+ <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
+ </uap:DefaultTile>
+ <uap:SplashScreen Image="Assets\SplashScreen.png" />
+ </uap:VisualElements>
+ </Application>
+ </Applications>
+ <Capabilities>
+ <Capability Name="internetClient" />
+ </Capabilities>
+</Package> \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Properties/AssemblyInfo.cs b/protocols/Telegram/tdlib/td/example/uwp/app/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..99e2b83bea
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("App2")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("App2")]
+[assembly: AssemblyCopyright("Copyright © 2015-2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)] \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/Properties/Default.rd.xml b/protocols/Telegram/tdlib/td/example/uwp/app/Properties/Default.rd.xml
new file mode 100644
index 0000000000..479eb7669d
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/Properties/Default.rd.xml
@@ -0,0 +1,31 @@
+<!--
+ This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
+ developers. However, you can modify these parameters to modify the behavior of the .NET Native
+ optimizer.
+
+ Runtime Directives are documented at http://go.microsoft.com/fwlink/?LinkID=391919
+
+ To fully enable reflection for App1.MyClass and all of its public/private members
+ <Type Name="App1.MyClass" Dynamic="Required All"/>
+
+ To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
+ <TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
+
+ Using the Namespace directive to apply reflection policy to all the types in a particular namespace
+ <Namespace Name="DataClasses.ViewModels" Seralize="All" />
+-->
+
+<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
+ <Application>
+ <!--
+ An Assembly element with Name="*Application*" applies to all assemblies in
+ the application package. The asterisks are not wildcards.
+ -->
+ <Assembly Name="*Application*" Dynamic="Required All" />
+
+
+ <!-- Add your application specific runtime directives here. -->
+
+
+ </Application>
+</Directives> \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/TdApp.csproj b/protocols/Telegram/tdlib/td/example/uwp/app/TdApp.csproj
new file mode 100644
index 0000000000..b3d1d944d1
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/TdApp.csproj
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProjectGuid>{0B971A4C-EC00-4FED-BCC2-FCD03B78D644}</ProjectGuid>
+ <OutputType>AppContainerExe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>TdApp</RootNamespace>
+ <AssemblyName>TdApp</AssemblyName>
+ <DefaultLanguage>en-US</DefaultLanguage>
+ <TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
+ <TargetPlatformVersion>10.0.10586.0</TargetPlatformVersion>
+ <TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
+ <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <PackageCertificateKeyFile>TdApp_TemporaryKey.pfx</PackageCertificateKeyFile>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+ <NoWarn>;2008</NoWarn>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <UseVSHostingProcess>false</UseVSHostingProcess>
+ <ErrorReport>prompt</ErrorReport>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+ <OutputPath>bin\x86\Release\</OutputPath>
+ <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoWarn>;2008</NoWarn>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <UseVSHostingProcess>false</UseVSHostingProcess>
+ <ErrorReport>prompt</ErrorReport>
+ <Prefer32Bit>true</Prefer32Bit>
+ <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\ARM\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+ <NoWarn>;2008</NoWarn>
+ <DebugType>full</DebugType>
+ <PlatformTarget>ARM</PlatformTarget>
+ <UseVSHostingProcess>false</UseVSHostingProcess>
+ <ErrorReport>prompt</ErrorReport>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
+ <OutputPath>bin\ARM\Release\</OutputPath>
+ <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoWarn>;2008</NoWarn>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>ARM</PlatformTarget>
+ <UseVSHostingProcess>false</UseVSHostingProcess>
+ <ErrorReport>prompt</ErrorReport>
+ <Prefer32Bit>true</Prefer32Bit>
+ <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x64\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+ <NoWarn>;2008</NoWarn>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x64</PlatformTarget>
+ <UseVSHostingProcess>false</UseVSHostingProcess>
+ <ErrorReport>prompt</ErrorReport>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ <OutputPath>bin\x64\Release\</OutputPath>
+ <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
+ <Optimize>true</Optimize>
+ <NoWarn>;2008</NoWarn>
+ <DebugType>pdbonly</DebugType>
+ <PlatformTarget>x64</PlatformTarget>
+ <UseVSHostingProcess>false</UseVSHostingProcess>
+ <ErrorReport>prompt</ErrorReport>
+ <Prefer32Bit>true</Prefer32Bit>
+ <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
+ </PropertyGroup>
+ <ItemGroup>
+ <!-- A reference to the entire .Net Framework and Windows SDK are automatically included -->
+ <Content Include="ApplicationInsights.config">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <None Include="project.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="MainPage.xaml.cs">
+ <DependentUpon>MainPage.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <AppxManifest Include="Package.appxmanifest">
+ <SubType>Designer</SubType>
+ </AppxManifest>
+ <None Include="TdApp_TemporaryKey.pfx" />
+ </ItemGroup>
+ <ItemGroup>
+ <Content Include="Properties\Default.rd.xml" />
+ <Content Include="Assets\LockScreenLogo.scale-200.png" />
+ <Content Include="Assets\SplashScreen.scale-200.png" />
+ <Content Include="Assets\Square150x150Logo.scale-200.png" />
+ <Content Include="Assets\Square44x44Logo.scale-200.png" />
+ <Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
+ <Content Include="Assets\StoreLogo.png" />
+ <Content Include="Assets\Wide310x150Logo.scale-200.png" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </ApplicationDefinition>
+ <Page Include="MainPage.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <SDKReference Include="Microsoft.VCLibs, Version=14.0">
+ <Name>Visual C++ 2015 Runtime for Universal Windows Platform Apps</Name>
+ </SDKReference>
+ <SDKReference Include="Telegram.Td.UWP, Version=1.0">
+ <Name>TDLib for Universal Windows Platform</Name>
+ </SDKReference>
+ </ItemGroup>
+ <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
+ <VisualStudioVersion>14.0</VisualStudioVersion>
+ </PropertyGroup>
+ <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project> \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/TdApp_TemporaryKey.pfx b/protocols/Telegram/tdlib/td/example/uwp/app/TdApp_TemporaryKey.pfx
new file mode 100644
index 0000000000..05ffbcabbc
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/TdApp_TemporaryKey.pfx
Binary files differ
diff --git a/protocols/Telegram/tdlib/td/example/uwp/app/project.json b/protocols/Telegram/tdlib/td/example/uwp/app/project.json
new file mode 100644
index 0000000000..e3b2dba25f
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/app/project.json
@@ -0,0 +1,19 @@
+{
+ "dependencies": {
+ "Microsoft.ApplicationInsights": "1.0.0",
+ "Microsoft.ApplicationInsights.PersistenceChannel": "1.0.0",
+ "Microsoft.ApplicationInsights.WindowsApps": "1.0.0",
+ "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
+ },
+ "frameworks": {
+ "uap10.0": {}
+ },
+ "runtimes": {
+ "win10-arm": {},
+ "win10-arm-aot": {},
+ "win10-x86": {},
+ "win10-x86-aot": {},
+ "win10-x64": {},
+ "win10-x64-aot": {}
+ }
+} \ No newline at end of file
diff --git a/protocols/Telegram/tdlib/td/example/uwp/build.ps1 b/protocols/Telegram/tdlib/td/example/uwp/build.ps1
new file mode 100644
index 0000000000..71156b0a2d
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/build.ps1
@@ -0,0 +1,142 @@
+param (
+ [string]$vcpkg_root = $(throw "-vcpkg_root=<path to vcpkg> is required"),
+ [string]$arch = "",
+ [string]$mode = "all",
+ [string]$compress = "7z"
+)
+$ErrorActionPreference = "Stop"
+
+$vcpkg_root = Resolve-Path $vcpkg_root
+
+$vcpkg_cmake="${vcpkg_root}\scripts\buildsystems\vcpkg.cmake"
+$arch_list = @( "x86", "x64", "arm" )
+if ($arch) {
+ $arch_list = @(, $arch)
+}
+
+$td_root = Resolve-Path "../.."
+
+function CheckLastExitCode {
+ if ($LastExitCode -ne 0) {
+ $msg = @"
+EXE RETURNED EXIT CODE $LastExitCode
+CALLSTACK:$(Get-PSCallStack | Out-String)
+"@
+ throw $msg
+ }
+}
+
+function clean {
+ Remove-Item build-* -Force -Recurse -ErrorAction SilentlyContinue
+}
+
+function prepare {
+ New-Item -ItemType Directory -Force -Path build-native
+
+ cd build-native
+
+ cmake $td_root -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=1
+ CheckLastExitCode
+ cmake --build . --target prepare_cross_compiling
+ CheckLastExitCode
+
+ cd ..
+}
+
+function config {
+ New-Item -ItemType Directory -Force -Path build-uwp
+ cd build-uwp
+
+ ForEach($arch in $arch_list) {
+ echo "Config Arch = [$arch]"
+ New-Item -ItemType Directory -Force -Path $arch
+ cd $arch
+ echo "${td_root}"
+ $fixed_arch = $arch
+ if ($arch -eq "x86") {
+ $fixed_arch = "win32"
+ }
+ cmake "$td_root" -A $fixed_arch -DCMAKE_SYSTEM_VERSION="10.0" -DCMAKE_SYSTEM_NAME="WindowsStore" -DCMAKE_TOOLCHAIN_FILE="$vcpkg_cmake" -DTD_ENABLE_DOTNET=1
+ CheckLastExitCode
+ cd ..
+ }
+ echo "done"
+ cd ..
+}
+
+function build {
+ cd build-uwp
+ ForEach($arch in $arch_list) {
+ echo "Build Arch = [$arch]"
+ cd $arch
+ cmake --build . --config Release --target tddotnet
+ cmake --build . --config Debug --target tddotnet
+ cd ..
+ }
+ cd ..
+}
+
+function export {
+ cd build-uwp
+ Remove-Item vsix -Force -Recurse -ErrorAction SilentlyContinue
+ New-Item -ItemType Directory -Force -Path vsix
+ cp ../SDKManifest.xml vsix
+ cp ../extension.vsixmanifest vsix
+ cp '../`[Content_Types`].xml' vsix
+ cp ../LICENSE_1_0.txt vsix
+
+ ForEach($arch in $arch_list) {
+ New-Item -ItemType Directory -Force -Path vsix/DesignTime/Debug/${arch}
+ New-Item -ItemType Directory -Force -Path vsix/DesignTime/Retail/${arch}
+ New-Item -ItemType Directory -Force -Path vsix/Redist/Debug/${arch}
+ New-Item -ItemType Directory -Force -Path vsix/Redist/Retail/${arch}
+ New-Item -ItemType Directory -Force -Path vsix/References/CommonConfiguration/${arch}
+
+ cp ${arch}/Debug/* -include "LIBEAY*","SSLEAY*","zlib*" vsix/Redist/Debug/${arch}/
+ cp ${arch}/Release/* -include "LIBEAY*","SSLEAY*","zlib*" vsix/Redist/Retail/${arch}/
+
+ cp ${arch}/Debug/* -filter "Telegram.Td.*" -include "*.lib" vsix/DesignTime/Debug/${arch}/
+ cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.lib" vsix/DesignTime/Retail/${arch}/
+
+ cp ${arch}/Debug/* -filter "Telegram.Td.*" -include "*.pdb","*.dll" vsix/Redist/Debug/${arch}/
+ cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pdb","*.dll" vsix/Redist/Retail/${arch}/
+
+ cp ${arch}/Release/* -filter "Telegram.Td.*" -include "*.pri","*.winmd","*.xml" vsix/References/CommonConfiguration/${arch}/
+ }
+
+ cd vsix
+
+ if ($compress -eq "zip") {
+ zip -r tdlib.vsix *
+ } elseif ($compress -eq "winrar") {
+ WinRAR.exe a -afzip -r -ep1 tdlib.vsix *
+ } else {
+ 7z.exe a -tzip -r tdlib.vsix *
+ }
+ cd ..
+}
+
+function run {
+ Push-Location
+ Try {
+ if ($mode -eq "clean") {
+ clean
+ }
+ if (($mode -eq "prepare") -or ($mode -eq "all")) {
+ prepare
+ }
+ if (($mode -eq "config") -or ( $mode -eq "all")) {
+ config
+ }
+ if (($mode -eq "build") -or ($mode -eq "all")) {
+ build
+ }
+ if (($mode -eq "export") -or ($mode -eq "all")) {
+ export
+ }
+ } Finally {
+ Pop-Location
+ }
+}
+
+run
diff --git a/protocols/Telegram/tdlib/td/example/uwp/extension.vsixmanifest b/protocols/Telegram/tdlib/td/example/uwp/extension.vsixmanifest
new file mode 100644
index 0000000000..cfcfdb57af
--- /dev/null
+++ b/protocols/Telegram/tdlib/td/example/uwp/extension.vsixmanifest
@@ -0,0 +1,17 @@
+<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
+ <Metadata>
+ <Identity Id="Telegram.Td.UWP" Version="1.2.0" Language="en-US" Publisher="Telegram LLC" />
+ <DisplayName>TDLib for Universal Windows Platform</DisplayName>
+ <Description>TDLib is a library for building Telegram clients</Description>
+ <MoreInfo>https://core.telegram.org/tdlib</MoreInfo>
+ <Tags>Telegram, TDLib, library, client, API</Tags>
+ <License>LICENSE_1_0.txt</License>
+ <ReleaseNotes>https://github.com/tdlib/td/blob/master/CHANGELOG.md</ReleaseNotes>
+ </Metadata>
+ <Installation Scope="Global">
+ <InstallationTarget Id="Microsoft.ExtensionSDK" TargetPlatformIdentifier="UAP" TargetPlatformVersion="v0.8.0.0" SdkName="Telegram.Td.UWP" SdkVersion="1.0" />
+ </Installation>
+ <Assets>
+ <Asset Type="Microsoft.ExtensionSDK" Path="SDKManifest.xml" />
+ </Assets>
+</PackageManifest>