diff --git a/CMakeLists.txt b/CMakeLists.txt index 007bd166d..9aab4d74c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,170 +1,170 @@ cmake_minimum_required(VERSION 3.0) set(PIM_VERSION "5.8.40") set(KDEPIM_RUNTIME_VERSION_NUMBER ${PIM_VERSION}) project(kdepim-runtime VERSION ${KDEPIM_RUNTIME_VERSION_NUMBER}) if (POLICY CMP0053) cmake_policy(SET CMP0053 NEW) endif() ############### KDEPIM-Runtime version ################ # KDEPIM_RUNTIME_VERSION # Version scheme: "x.y.z build". # # x is the version number. # y is the major release number. # z is the minor release number. # # "x.y.z" follow the kdelibs version kdepim is released with. # # If "z" is 0, it the version is "x.y" # # KDEPIM_DEV_VERSION # is empty for final versions. For development versions "build" is # something like "pre", "", "alpha2", "beta1", "beta2", "rc1", "rc2". # # Examples in chronological order: # # 3.0 # 3.0.1 # 3.1 # 3.1 beta1 # 3.1 beta2 # 3.1 rc1 # 3.1 # 3.1.1 # 3.2 pre # 3.2 set(KDEPIM_DEV_VERSION alpha) # add an extra space if(DEFINED KDEPIM_DEV_VERSION) set(KDEPIM_DEV_VERSION " ${KDEPIM_DEV_VERSION}") endif() set(KDEPIM_RUNTIME_VERSION "${KDEPIM_RUNTIME_VERSION_NUMBER}${KDEPIM_DEV_VERSION}") configure_file(kdepim-runtime-version.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdepim-runtime-version.h @ONLY) set(KF5_VERSION "5.46.0") find_package(ECM ${KF5_VERSION} CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${kdepim-runtime_SOURCE_DIR}/cmake/ ${ECM_MODULE_PATH}) include(CMakePackageConfigHelpers) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMQtDeclareLoggingCategory) include(GenerateExportHeader) include(ECMCoverageOption) set(QT_REQUIRED_VERSION "5.9.0") set(KDEPIMRUNTIME_LIB_VERSION "${KDEPIM_RUNTIME_VERSION_NUMBER}") set(KDEPIMRUNTIME_LIB_SOVERSION "5") set(AKONADI_VERSION "5.8.40") set(KCONTACTS_LIB_VERSION "5.8.40") set(KCALENDARCORE_LIB_VERSION "5.8.40") set(IDENTITYMANAGEMENT_LIB_VERSION "5.8.40") set(KMAILTRANSPORT_LIB_VERSION "5.8.40") set(CALENDARUTILS_LIB_VERSION "5.8.40") set(KDAV_LIB_VERSION "5.8.40") set(KIMAP_LIB_VERSION "5.8.41") set(KMBOX_LIB_VERSION "5.8.40") set(AKONADICALENDAR_LIB_VERSION "5.8.40") set(KONTACTINTERFACE_LIB_VERSION "5.8.40") set(AKONADIKALARM_LIB_VERSION "5.8.40") set(KMIME_LIB_VERSION "5.8.40") set(XMLRPCCLIENT_LIB_VERSION "5.8.40") set(KCONTACTS_LIB_VERSION "5.8.40") set(AKONADIMIME_LIB_VERSION "5.8.40") set(AKONADICONTACT_LIB_VERSION "5.8.40") set(AKONADINOTE_LIB_VERSION "5.8.40") set(PIMCOMMON_LIB_VERSION "5.8.40") -set(KGAPI_LIB_VERSION "5.8.41") +set(KGAPI_LIB_VERSION "5.8.42") set( SharedMimeInfo_MINIMUM_VERSION "1.3" ) find_package(SharedMimeInfo ${SharedMimeInfo_MINIMUM_VERSION} REQUIRED) find_package(Sasl2) set_package_properties(Sasl2 PROPERTIES TYPE REQUIRED) # QT5 package find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED Network Widgets Test XmlPatterns DBus WebEngineWidgets) find_package(Qt5 OPTIONAL_COMPONENTS TextToSpeech) if (NOT Qt5TextToSpeech_FOUND) message(STATUS "Qt5TextToSpeech not found, speech feature will be disabled") else() add_definitions(-DHAVE_TEXTTOSPEECH) endif() # KF5 package find_package(KF5Config ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5ConfigWidgets ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5NotifyConfig ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5ItemModels ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5Codecs ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5WindowSystem ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5TextWidgets ${KF5_VERSION} CONFIG REQUIRED) # for KPluralHandlingSpinBox find_package(KF5Notifications ${KF5_VERSION} CONFIG REQUIRED) # pop3 find_package(KF5DocTools ${KF5_VERSION} CONFIG REQUIRED) # pop3 find_package(KF5Holidays ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5DBusAddons ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5IconThemes ${KF5_VERSION} CONFIG REQUIRED) find_package(KF5KDELibs4Support ${KF5_VERSION} CONFIG REQUIRED) # KdepimLibs package find_package(KF5Akonadi ${AKONADI_VERSION} CONFIG REQUIRED) find_package(KPimKDAV ${KDAV_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Mime ${KMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiMime ${AKONADIMIME_LIB_VERSION} CONFIG REQUIRED) find_package(KF5MailTransportAkonadi ${KMAILTRANSPORT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5IdentityManagement ${IDENTITYMANAGEMENT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiContact ${AKONADICONTACT_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Contacts ${KCONTACTS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AlarmCalendar ${AKONADIKALARM_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KCALENDARCORE_LIB_VERSION} CONFIG REQUIRED) find_package(KF5CalendarUtils ${CALENDARUTILS_LIB_VERSION} CONFIG REQUIRED) find_package(KF5Mbox ${KMBOX_LIB_VERSION} CONFIG REQUIRED) find_package(KF5IMAP ${KIMAP_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiNotes ${AKONADINOTE_LIB_VERSION} CONFIG REQUIRED) find_package(KF5AkonadiCalendar ${AKONADICALENDAR_LIB_VERSION} CONFIG REQUIRED) find_package(KF5PimCommon ${PIMCOMMON_LIB_VERSION} CONFIG REQUIRED) find_package(KPimGAPI ${KGAPI_LIB_VERSION} CONFIG REQUIRED) option(KDEPIM_RUN_ISOLATED_TESTS "Run the isolated tests." FALSE) add_definitions(-DQT_NO_CAST_FROM_ASCII) add_definitions(-DQT_NO_CAST_TO_ASCII) add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) #add_definitions( -DQT_DISABLE_DEPRECATED_BEFORE=0x060000 ) add_subdirectory(resources) add_subdirectory(agents) add_subdirectory(defaultsetup) add_subdirectory(kioslave) add_subdirectory(migration) add_subdirectory(doc) ## install the MIME type spec file for KDEPIM specific MIME types install(FILES kdepim-mime.xml DESTINATION ${KDE_INSTALL_MIMEDIR}) update_xdg_mimetypes(${KDE_INSTALL_MIMEDIR}) install( FILES kdepim-runtime.renamecategories kdepim-runtime.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES ) diff --git a/resources/imap/gmailpasswordrequester.cpp b/resources/imap/gmailpasswordrequester.cpp index eccc2c971..3a01293f5 100644 --- a/resources/imap/gmailpasswordrequester.cpp +++ b/resources/imap/gmailpasswordrequester.cpp @@ -1,137 +1,88 @@ /* Copyright (c) 2016 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "gmailpasswordrequester.h" #include "imapresourcebase.h" #include "settings.h" #include "imapresource_debug.h" #include #include +#include #define GOOGLE_API_KEY QStringLiteral("554041944266.apps.googleusercontent.com") #define GOOGLE_API_SECRET QStringLiteral("mdT1DjzohxN3npUUzkENT0gO") GmailPasswordRequester::GmailPasswordRequester(ImapResourceBase *resource, QObject *parent) : PasswordRequesterInterface(parent) , mResource(resource) - , mRunningRequest(nullptr) { } GmailPasswordRequester::~GmailPasswordRequester() { } void GmailPasswordRequester::requestPassword(RequestType request, const QString &serverError) { Q_UNUSED(serverError); // we don't get anything useful from XOAUTH2 SASL if (request == WrongPasswordRequest) { - const QString tokens = mResource->settings()->password(); - if (tokens.isEmpty()) { - requestToken(); - } else { - const QString token = tokens.mid(tokens.indexOf(QLatin1Char('\001')) + 1); - if (token.isEmpty() || token == tokens) { - requestToken(token); // if token == tokens, assume it's account password - } else { - refreshToken(token); - } - } + auto promise = KGAPI2::AccountManager::instance()->findAccount(GOOGLE_API_KEY, mResource->settings()->userName()); + connect(promise, &KGAPI2::AccountPromise::finished, + this, [this](KGAPI2::AccountPromise *promise) { + if (promise->account()) { + promise = KGAPI2::AccountManager::instance()->refreshTokens( + GOOGLE_API_KEY, GOOGLE_API_SECRET, mResource->settings()->userName()); + } else { + promise = KGAPI2::AccountManager::instance()->getAccount( + GOOGLE_API_KEY, GOOGLE_API_SECRET, mResource->settings()->userName(), + { KGAPI2::Account::mailScopeUrl() }); + } + connect(promise, &KGAPI2::AccountPromise::finished, + this, &GmailPasswordRequester::onTokenRequestFinished); + mPendingPromise = promise; + }); + mPendingPromise = promise; } else { - connect(mResource->settings(), &Settings::passwordRequestCompleted, - this, &GmailPasswordRequester::onPasswordRequestCompleted); - mResource->settings()->requestPassword(); + auto promise = KGAPI2::AccountManager::instance()->getAccount( + GOOGLE_API_KEY, GOOGLE_API_SECRET, mResource->settings()->userName(), + { KGAPI2::Account::mailScopeUrl() }); + connect(promise, &KGAPI2::AccountPromise::finished, + this, &GmailPasswordRequester::onTokenRequestFinished); + mPendingPromise = promise; } } void GmailPasswordRequester::cancelPasswordRequests() { - if (mRunningRequest) { - mRunningRequest->disconnect(this); - mRunningRequest->deleteLater(); + if (mPendingPromise) { + mPendingPromise->disconnect(this); } } -void GmailPasswordRequester::onPasswordRequestCompleted(const QString &password, bool userRejected) +void GmailPasswordRequester::onTokenRequestFinished(KGAPI2::AccountPromise *promise) { - disconnect(mResource->settings(), &Settings::passwordRequestCompleted, - this, &GmailPasswordRequester::onPasswordRequestCompleted); - - QString token = password; - if (userRejected || token.isEmpty()) { - requestToken(); - return; + mPendingPromise = nullptr; + if (promise->hasError()) { + Q_EMIT done(UserRejected, promise->errorText()); } else { - token = password.left(password.indexOf(QLatin1Char('\001'))); - if (token.isEmpty() || token == password) { - requestToken(password); // if token == password, assume it's account password - return; - } + Q_EMIT done(PasswordRetrieved, promise->account()->accessToken()); } - - Q_EMIT done(PasswordRetrieved, token); -} - -void GmailPasswordRequester::requestToken(const QString &password) -{ - Q_ASSERT(!mRunningRequest); - auto acc = KGAPI2::AccountPtr::create(mResource->settings()->userName(), - QString(), QString(), - QList{ QUrl(QStringLiteral("https://mail.google.com/")) }); - - auto authJob = new KGAPI2::AuthJob(acc, GOOGLE_API_KEY, GOOGLE_API_SECRET, this); - authJob->setUsername(mResource->settings()->userName()); - authJob->setPassword(password); - connect(authJob, &KGAPI2::Job::finished, - this, &GmailPasswordRequester::onTokenRequestFinished); - mRunningRequest = authJob; -} - -void GmailPasswordRequester::onTokenRequestFinished(KGAPI2::Job *job) -{ - mRunningRequest.clear(); - - auto authJob = qobject_cast(job); - if (authJob->error()) { - qCWarning(IMAPRESOURCE_LOG) << "Error obtaining XOAUTH2 token:" << authJob->errorString(); - Q_EMIT done(UserRejected); - return; - } - - const auto account = authJob->account(); - const QString tokens = QStringLiteral("%1\001%2").arg(account->accessToken(), - account->refreshToken()); - mResource->settings()->setPassword(tokens); - Q_EMIT done(PasswordRetrieved, account->accessToken()); -} - -void GmailPasswordRequester::refreshToken(const QString &refreshToken) -{ - Q_ASSERT(!mRunningRequest); - auto acc = KGAPI2::AccountPtr::create(mResource->settings()->userName(), - QString(), refreshToken, - QList{ QUrl(QStringLiteral("https://mail.google.com/")) }); - auto authJob = new KGAPI2::AuthJob(acc, GOOGLE_API_KEY, GOOGLE_API_SECRET, this); - authJob->setUsername(mResource->settings()->userName()); - connect(authJob, &KGAPI2::Job::finished, - this, &GmailPasswordRequester::onTokenRequestFinished); - mRunningRequest = authJob; } diff --git a/resources/imap/gmailpasswordrequester.h b/resources/imap/gmailpasswordrequester.h index 10e601ee4..b5b8aa84c 100644 --- a/resources/imap/gmailpasswordrequester.h +++ b/resources/imap/gmailpasswordrequester.h @@ -1,54 +1,51 @@ /* Copyright (c) 2016 Daniel Vrátil This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef GMAILPASSWORDREQUESTER_H_ #define GMAILPASSWORDREQUESTER_H_ #include "passwordrequesterinterface.h" #include class ImapResourceBase; namespace KGAPI2 { -class Job; +class AccountPromise; } class GmailPasswordRequester : public PasswordRequesterInterface { Q_OBJECT public: explicit GmailPasswordRequester(ImapResourceBase *resource, QObject *parent = nullptr); ~GmailPasswordRequester(); void requestPassword(RequestType request, const QString &serverError) override; void cancelPasswordRequests() override; private Q_SLOTS: - void onPasswordRequestCompleted(const QString &password, bool userRejected); - void onTokenRequestFinished(KGAPI2::Job *job); -private: - void requestToken(const QString &password = QString()); - void refreshToken(const QString &refreshToken); + void onTokenRequestFinished(KGAPI2::AccountPromise *promise); +private: ImapResourceBase *mResource = nullptr; - QPointer mRunningRequest; + KGAPI2::AccountPromise *mPendingPromise = nullptr; }; #endif