/* Copyright (C) 2020 Sebastian J. Wolf This file is part of Fernschreiber. Fernschreiber is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fernschreiber 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 Fernschreiber. If not, see . */ #include "tdlibwrapper.h" #include "tdlibsecrets.h" #include #include #include #include TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent) { qDebug() << "[TDLibWrapper] Initializing TD Lib..."; this->tdLibClient = td_json_client_create(); this->tdLibReceiver = new TDLibReceiver(this->tdLibClient, this); QString tdLibDatabaseDirectoryPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdlib"; QDir tdLibDatabaseDirectory(tdLibDatabaseDirectoryPath); if (!tdLibDatabaseDirectory.exists()) { tdLibDatabaseDirectory.mkpath(tdLibDatabaseDirectoryPath); } connect(this->tdLibReceiver, SIGNAL(versionDetected(QString)), this, SLOT(handleVersionDetected(QString))); connect(this->tdLibReceiver, SIGNAL(authorizationStateChanged(QString)), this, SLOT(handleAuthorizationStateChanged(QString))); connect(this->tdLibReceiver, SIGNAL(optionUpdated(QString, QVariant)), this, SLOT(handleOptionUpdated(QString, QVariant))); connect(this->tdLibReceiver, SIGNAL(connectionStateChanged(QString)), this, SLOT(handleConnectionStateChanged(QString))); connect(this->tdLibReceiver, SIGNAL(userUpdated(QVariantMap)), this, SLOT(handleUserUpdated(QVariantMap))); this->tdLibReceiver->start(); } TDLibWrapper::~TDLibWrapper() { qDebug() << "[TDLibWrapper] Destroying TD Lib..."; this->tdLibReceiver->setActive(false); while (this->tdLibReceiver->isRunning()) { QCoreApplication::processEvents(QEventLoop::AllEvents, 1000); } td_json_client_destroy(this->tdLibClient); } void TDLibWrapper::sendRequest(const QVariantMap &requestObject) { qDebug() << "[TDLibWrapper] Sending request to TD Lib, object type name: " << requestObject.value("@type").toString(); QJsonDocument requestDocument = QJsonDocument::fromVariant(requestObject); td_json_client_send(this->tdLibClient, requestDocument.toJson().constData()); } QString TDLibWrapper::getVersion() { return this->version; } TDLibWrapper::AuthorizationState TDLibWrapper::getAuthorizationState() { return this->authorizationState; } TDLibWrapper::ConnectionState TDLibWrapper::getConnectionState() { return this->connectionState; } void TDLibWrapper::setAuthenticationPhoneNumber(const QString &phoneNumber) { qDebug() << "[TDLibWrapper] Set authentication phone number " << phoneNumber; QVariantMap requestObject; requestObject.insert("@type", "setAuthenticationPhoneNumber"); requestObject.insert("phone_number", phoneNumber); QVariantMap phoneNumberSettings; phoneNumberSettings.insert("allow_flash_call", false); phoneNumberSettings.insert("is_current_phone_number", true); requestObject.insert("settings", phoneNumberSettings); this->sendRequest(requestObject); } void TDLibWrapper::setAuthenticationCode(const QString &authenticationCode) { qDebug() << "[TDLibWrapper] Set authentication code " << authenticationCode; QVariantMap requestObject; requestObject.insert("@type", "checkAuthenticationCode"); requestObject.insert("code", authenticationCode); this->sendRequest(requestObject); } void TDLibWrapper::handleVersionDetected(const QString &version) { this->version = version; emit versionDetected(version); } void TDLibWrapper::handleAuthorizationStateChanged(const QString &authorizationState) { if (authorizationState == "authorizationStateClosed") { this->authorizationState = AuthorizationState::Closed; } if (authorizationState == "authorizationStateClosing") { this->authorizationState = AuthorizationState::Closing; } if (authorizationState == "authorizationStateLoggingOut") { this->authorizationState = AuthorizationState::LoggingOut; } if (authorizationState == "authorizationStateReady") { this->authorizationState = AuthorizationState::AuthorizationReady; } if (authorizationState == "authorizationStateWaitCode") { this->authorizationState = AuthorizationState::WaitCode; } if (authorizationState == "authorizationStateWaitEncryptionKey") { this->setEncryptionKey(); this->authorizationState = AuthorizationState::WaitEncryptionKey; } if (authorizationState == "authorizationStateWaitOtherDeviceConfirmation") { this->authorizationState = AuthorizationState::WaitOtherDeviceConfirmation; } if (authorizationState == "authorizationStateWaitPassword") { this->authorizationState = AuthorizationState::WaitPassword; } if (authorizationState == "authorizationStateWaitPhoneNumber") { this->authorizationState = AuthorizationState::WaitPhoneNumber; } if (authorizationState == "authorizationStateWaitRegistration") { this->authorizationState = AuthorizationState::WaitRegistration; } if (authorizationState == "authorizationStateWaitTdlibParameters") { this->setInitialParameters(); this->authorizationState = AuthorizationState::WaitTdlibParameters; } emit authorizationStateChanged(this->authorizationState); } void TDLibWrapper::handleOptionUpdated(const QString &optionName, const QVariant &optionValue) { this->options.insert(optionName, optionValue); emit optionUpdated(optionName, optionValue); } void TDLibWrapper::handleConnectionStateChanged(const QString &connectionState) { if (connectionState == "connectionStateConnecting") { this->connectionState = ConnectionState::Connecting; } if (connectionState == "connectionStateConnectingToProxy") { this->connectionState = ConnectionState::ConnectingToProxy; } if (connectionState == "connectionStateReady") { this->connectionState = ConnectionState::ConnectionReady; } if (connectionState == "connectionStateUpdating") { this->connectionState = ConnectionState::Updating; } if (connectionState == "connectionStateWaitingForNetwork") { this->connectionState = ConnectionState::WaitingForNetwork; } emit connectionStateChanged(this->connectionState); } void TDLibWrapper::handleUserUpdated(const QVariantMap &userInformation) { if (userInformation.value("id") == this->options.value("my_id")) { qDebug() << "[TDLibWrapper] Own user information updated :)"; this->userInformation = userInformation; } else { qDebug() << "[TDLibWrapper] Other user information updated"; } } void TDLibWrapper::setInitialParameters() { qDebug() << "[TDLibWrapper] Sending initial parameters to TD Lib"; QVariantMap requestObject; requestObject.insert("@type", "setTdlibParameters"); QVariantMap initialParameters; initialParameters.insert("api_id", TDLIB_API_ID); initialParameters.insert("api_hash", TDLIB_API_HASH); initialParameters.insert("database_directory", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/tdlib"); initialParameters.insert("use_file_database", true); initialParameters.insert("use_chat_info_database", true); initialParameters.insert("use_message_database", true); initialParameters.insert("use_secret_chats", false); initialParameters.insert("system_language_code", QLocale::system().name()); QSettings hardwareSettings("/etc/hw-release", QSettings::NativeFormat); initialParameters.insert("device_model", hardwareSettings.value("NAME", "Unknown Mobile Device").toString()); initialParameters.insert("system_version", QSysInfo::prettyProductName()); initialParameters.insert("application_version", "0.1"); requestObject.insert("parameters", initialParameters); this->sendRequest(requestObject); } void TDLibWrapper::setEncryptionKey() { qDebug() << "[TDLibWrapper] Setting database encryption key"; QVariantMap requestObject; requestObject.insert("@type", "checkDatabaseEncryptionKey"); // see https://github.com/tdlib/td/issues/188#issuecomment-379536139 requestObject.insert("encryption_key", ""); this->sendRequest(requestObject); }