/* * Copyright (C) 2017-2018 infactum (infactum@gmail.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . */ #include #include #include #include #include #include #include "settings.h" // overloaded namespace detail { template struct overload; template struct overload : public F { explicit overload(F f) : F(f) { } }; template struct overload : public overload, overload { overload(F f, Fs... fs) : overload(f), overload(fs...) { } using overload::operator(); using overload::operator(); }; } // namespace detail template auto overloaded(F... f) { return detail::overload(f...); } namespace td_api = td::td_api; class TDClient { public: explicit TDClient(Settings &settings_) : settings(settings_) { td::Log::set_verbosity_level(1); client = std::make_unique(); } void auth() { while (!sequence_done) { process_response(client->receive(10)); } } private: using Object = td_api::object_ptr; Settings &settings; bool sequence_done{false}; std::unique_ptr client; td_api::object_ptr authorization_state; std::uint64_t current_query_id{0}; std::uint64_t authentication_query_id{0}; std::map> handlers; std::uint64_t next_query_id() { return ++current_query_id; } void send_query(td_api::object_ptr f, std::function 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; } 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)); handlers.erase(it->first); } } void process_update(td_api::object_ptr 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(); }, [](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 check_authentication_error(Object object) { if (object->get_id() == td_api::error::ID) { auto error = td::move_tl_object_as(object); std::cerr << "Error: " << to_string(error); on_authorization_state_update(); } } void on_authorization_state_update() { authentication_query_id++; td_api::downcast_call( *authorization_state, overloaded( [this](td_api::authorizationStateReady &) { sequence_done = true; std::cerr << "Authorization OK" << std::endl; }, [this](td_api::authorizationStateLoggingOut &) { sequence_done = true; std::cerr << "Logging out" << std::endl; }, [this](td_api::authorizationStateClosing &) { std::cerr << "Closing" << std::endl; }, [this](td_api::authorizationStateClosed &) { sequence_done = 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(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(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( phone_number, false /*allow_flash_calls*/, false /*is_current_phone_number*/), create_authentication_query_handler()); }, [this](td_api::authorizationStateWaitEncryptionKey &) { send_query(td_api::make_object(""), create_authentication_query_handler()); td_api::object_ptr proxy; if (settings.proxy_enabled()) { auto socks_proxy = td_api::make_object( settings.proxy_address(), settings.proxy_port(), settings.proxy_username(), settings.proxy_password() ); proxy = td_api::move_object_as(socks_proxy); } else { auto empty_proxy = td_api::make_object(); proxy = td_api::move_object_as(empty_proxy); } send_query(td_api::make_object( td_api::move_object_as(proxy)), [](Object) {}); }, [this](td_api::authorizationStateWaitTdlibParameters &) { auto lib_parameters = td_api::make_object(); lib_parameters = td_api::make_object(); lib_parameters->api_id_ = settings.api_id(); lib_parameters->api_hash_ = settings.api_hash(); lib_parameters->database_directory_ = settings.db_folder(); lib_parameters->system_language_code_ = settings.sys_lang_code(); lib_parameters->device_model_ = settings.device_model(); lib_parameters->system_version_ = settings.system_version(); lib_parameters->application_version_ = settings.app_version(); lib_parameters->use_file_database_ = false; lib_parameters->use_chat_info_database_ = true; lib_parameters->use_message_database_ = false; lib_parameters->use_secret_chats_ = false; lib_parameters->enable_storage_optimizer_ = true; send_query(td_api::make_object(std::move(lib_parameters)), create_authentication_query_handler()); })); } }; int main() { auto reader = INIReader("settings.ini"); Settings settings(reader); if (!settings.is_loaded()) { return 1; } TDClient client(settings); client.auth(); }