diff options
Diffstat (limited to 'fbreader/src/network/authentication/litres/LitResAuthenticationManager.cpp')
-rw-r--r-- | fbreader/src/network/authentication/litres/LitResAuthenticationManager.cpp | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/fbreader/src/network/authentication/litres/LitResAuthenticationManager.cpp b/fbreader/src/network/authentication/litres/LitResAuthenticationManager.cpp new file mode 100644 index 0000000..e552b5c --- /dev/null +++ b/fbreader/src/network/authentication/litres/LitResAuthenticationManager.cpp @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2009-2012 Geometer Plus <contact@geometerplus.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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <ZLNetworkUtil.h> +#include <ZLNetworkManager.h> +#include <ZLUserData.h> +#include <ZLExecutionUtil.h> + +#include "../../tree/NetworkLibrary.h" + +#include "../../litres/LitResBooksFeedParser.h" +#include "../../litres/LitResUtil.h" +#include "LitResAuthenticationManager.h" +#include "LitResAuthenticationDataParser.h" + +#include "../../NetworkErrors.h" +#include "../../NetworkLink.h" +#include "../../NetworkLinkCollection.h" + +LitResAuthenticationManager::LitResAuthenticationManager(const NetworkLink &link) : + NetworkAuthenticationManager(link), + mySidChecked(false), + mySidUserNameOption(ZLCategoryKey::NETWORK, link.getSiteName(), "sidUserName", ""), + mySidOption(ZLCategoryKey::NETWORK, link.getSiteName(), "sid", "") +{ +} + +class LitResAuthorisationScope : public ZLUserData { +public: + std::string firstName; + std::string lastName; + std::string newSid; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +NetworkAuthenticationManager::AuthenticationStatus LitResAuthenticationManager::isAuthorised(shared_ptr<ZLNetworkRequest::Listener> listener) { + const bool useNetwork = !listener.isNull(); + bool authState = !mySidUserNameOption.value().empty() && !mySidOption.value().empty(); + if (mySidChecked || !useNetwork) { + if (!listener.isNull()) + listener->finished(authState ? std::string() : "Not authorised"); + return AuthenticationStatus(authState); + } + + if (!authState) { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + listener->finished("Not authorised"); + return AuthenticationStatus(false); + } + + LitResAuthorisationScope *scope = new LitResAuthorisationScope; + scope->listener = listener; + shared_ptr<ZLXMLReader> xmlReader = new LitResLoginDataParser(scope->firstName, scope->lastName, scope->newSid); + + std::string url = Link.url(NetworkLink::URL_SIGN_IN); + ZLNetworkUtil::appendParameter(url, "sid", mySidOption.value()); + + shared_ptr<ZLNetworkRequest> networkData = ZLNetworkManager::Instance().createXMLParserRequest(url, xmlReader); + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onAuthorised)); + ZLNetworkManager::Instance().performAsync(networkData); + return AuthenticationStatus(std::string()); +} + +std::string LitResAuthenticationManager::authorise(const std::string &pwd, shared_ptr<ZLNetworkRequest::Listener> listener) { + LitResAuthorisationScope *scope = new LitResAuthorisationScope; + scope->listener = listener; + shared_ptr<ZLXMLReader> xmlReader = new LitResLoginDataParser(scope->firstName, scope->lastName, scope->newSid); + + std::string url = Link.url(NetworkLink::URL_SIGN_IN); + ZLNetworkUtil::appendParameter(url, "login", UserNameOption.value()); + ZLNetworkUtil::appendParameter(url, "pwd", pwd); + ZLNetworkUtil::appendParameter(url, "skip_ip", "1"); + + shared_ptr<ZLNetworkRequest> networkData = + ZLNetworkManager::Instance().createXMLParserRequest( + url, + xmlReader + ); + + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onAuthorised)); + return ZLNetworkManager::Instance().performAsync(networkData); +} + +void LitResAuthenticationManager::onAuthorised(ZLUserDataHolder &data, const std::string &error) { + LitResAuthorisationScope &scope = static_cast<LitResAuthorisationScope&>(*data.getUserData("scope")); + + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_TIMEOUT_EXPIRED)) { + scope.listener->finished(error); + return; + } + + mySidChecked = true; + if (!error.empty()) { + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + } else { + mySidOption.setValue(scope.newSid); + mySidUserNameOption.setValue(UserNameOption.value()); + } + + scope.listener->finished(error); +} + + +void LitResAuthenticationManager::logOut() { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + + myInitializedDataSid.clear(); + myPurchasedBooksIds.clear(); + myPurchasedBooksList.clear(); + myAccount.clear(); +} + +const std::string &LitResAuthenticationManager::currentUserName() { + return mySidUserNameOption.value(); +} + +bool LitResAuthenticationManager::needPurchase(const NetworkBookItem &book) { + return myPurchasedBooksIds.count(book.Id) == 0; +} + +class LitResPurchaseBookScope : public ZLUserData { +public: + std::string account; + std::string bookId; + const NetworkBookItem *book; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +std::string LitResAuthenticationManager::purchaseBook(const NetworkBookItem &book, shared_ptr<ZLNetworkRequest::Listener> listener) { + const std::string &sid = mySidOption.value(); + std::string error; + if (sid.empty()) { + error = NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + listener->finished(error); + return error; + } + + shared_ptr<BookReference> reference = book.reference(BookReference::BUY); + if (reference.isNull()) { + // TODO: add correct error message + error = "Oh, that's impossible"; + listener->finished(error); + return error; + } + std::string query = reference->URL; + ZLNetworkUtil::appendParameter(query, "sid", sid); + + LitResPurchaseBookScope *scope = new LitResPurchaseBookScope; + scope->book = &book; + scope->listener = listener; + + shared_ptr<ZLXMLReader> xmlReader = new LitResPurchaseDataParser(scope->account, scope->bookId); + shared_ptr<ZLNetworkRequest> networkData = ZLNetworkManager::Instance().createXMLParserRequest(query, xmlReader); + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onBookPurchased)); + return ZLNetworkManager::Instance().performAsync(networkData); +} + +void LitResAuthenticationManager::onBookPurchased(ZLUserDataHolder &data, const std::string &error) { + LitResPurchaseBookScope &scope = static_cast<LitResPurchaseBookScope&>(*data.getUserData("scope")); + shared_ptr<ZLNetworkRequest::Listener> listener = scope.listener; + if (!scope.account.empty()) { + myAccount = BuyBookReference::price(scope.account, "RUB"); + } + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + } + const std::string alreadyPurchasedError = NetworkErrors::errorMessage(NetworkErrors::ERROR_PURCHASE_ALREADY_PURCHASED); + if (error != alreadyPurchasedError) { + if (!error.empty()) { + listener->finished(error); + return; + } + if (scope.bookId != scope.book->Id) { + listener->finished(NetworkErrors::errorMessage(NetworkErrors::ERROR_SOMETHING_WRONG, Link.getSiteName())); + return; + } + } + myPurchasedBooksIds.insert(scope.book->Id); + myPurchasedBooksList.push_back(new NetworkBookItem(*scope.book, 0)); + listener->finished(error); +} + +shared_ptr<BookReference> LitResAuthenticationManager::downloadReference(const NetworkBookItem &book) { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + return 0; + } + shared_ptr<BookReference> reference = + book.reference(BookReference::DOWNLOAD_FULL_CONDITIONAL); + if (reference.isNull()) { + return 0; + } + std::string url = reference->URL; + ZLNetworkUtil::appendParameter(url, "sid", sid); + return new DecoratedBookReference(*reference, url); +} + +void LitResAuthenticationManager::collectPurchasedBooks(NetworkItem::List &list) { + list.assign(myPurchasedBooksList.begin(), myPurchasedBooksList.end()); +} + +const std::set<std::string> &LitResAuthenticationManager::getPurchasedIds() const { + return myPurchasedBooksIds; +} + +const NetworkItem::List &LitResAuthenticationManager::purchasedBooks() const { + return myPurchasedBooksList; +} + +std::string LitResAuthenticationManager::topupAccountLink() { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + return std::string(); + } + std::string url = Link.url(NetworkLink::URL_TOPUP); + ZLNetworkUtil::appendParameter(url, "sid", sid); + return url; +} + +std::string LitResAuthenticationManager::currentAccount() { + return myAccount; +} + +bool LitResAuthenticationManager::needsInitialization() { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + return false; + } + return sid != myInitializedDataSid; +} + +class LitResInitializationScope : public ZLUserData { +public: + std::string dummy; + std::string error; + shared_ptr<ZLNetworkRequest::Listener> listener; +}; + +std::string LitResAuthenticationManager::initialize(shared_ptr<ZLNetworkRequest::Listener> listener) { + const std::string &sid = mySidOption.value(); + if (sid.empty()) { + listener->finished(NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)); + return NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + } + if (sid == myInitializedDataSid) { + listener->finished(std::string()); + return std::string(); + } + + LitResInitializationScope *scope = new LitResInitializationScope; + scope->listener = listener; + + shared_ptr<ZLNetworkRequest> request = loadPurchasedBooks(myPurchasedBooksIds, myPurchasedBooksList); + request->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onBooksLoaded)); + return ZLNetworkManager::Instance().performAsync(request); +} + +void LitResAuthenticationManager::onBooksLoaded(ZLUserDataHolder &data, const std::string &error) { + LitResInitializationScope &scope = static_cast<LitResInitializationScope&>(*data.getUserData("scope")); + + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_TIMEOUT_EXPIRED)) { + scope.listener->finished(error); + return; + } + + scope.error = error; + shared_ptr<ZLNetworkRequest> request = loadAccount(scope.dummy); + request->setListener(ZLExecutionUtil::createListener(new ZLUserDataHolder(data), this, &LitResAuthenticationManager::onAccountReceived)); + ZLNetworkManager::Instance().performAsync(request); +} + +void LitResAuthenticationManager::onAccountReceived(ZLUserDataHolder &data, const std::string &error) { + LitResInitializationScope &scope = static_cast<LitResInitializationScope&>(*data.getUserData("scope")); + + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_TIMEOUT_EXPIRED)) { + scope.listener->finished(error); + return; + } + + if (!error.empty() && !scope.error.empty()) { + scope.error.append("\n").append(error); + } else if (!error.empty()) { + scope.error = error; + } + if (!scope.error.empty()) { + myInitializedDataSid.clear(); + loadPurchasedBooksOnError(myPurchasedBooksIds, myPurchasedBooksList); + loadAccountOnError(); + scope.listener->finished(scope.error); + return; + } + myInitializedDataSid = mySidOption.value(); + loadPurchasedBooksOnSuccess(myPurchasedBooksIds, myPurchasedBooksList); + loadAccountOnSuccess(); + scope.listener->finished(); +} + +shared_ptr<ZLNetworkRequest> LitResAuthenticationManager::loadPurchasedBooks(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList) { + const std::string &sid = mySidOption.value(); + purchasedBooksIds.clear(); + purchasedBooksList.clear(); + + std::string query; + ZLNetworkUtil::appendParameter(query, "my", "1"); + ZLNetworkUtil::appendParameter(query, "sid", sid); + + return ZLNetworkManager::Instance().createXMLParserRequest( + LitResUtil::url(Link, "pages/catalit_browser/" + query), + new LitResBooksFeedParser(Link, purchasedBooksList) + ); +} + +void LitResAuthenticationManager::loadPurchasedBooksOnError(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList) { + purchasedBooksIds.clear(); + purchasedBooksList.clear(); +} + +void LitResAuthenticationManager::loadPurchasedBooksOnSuccess(std::set<std::string> &purchasedBooksIds, NetworkItem::List &purchasedBooksList) { + for (NetworkItem::List::iterator it = purchasedBooksList.begin(); it != purchasedBooksList.end(); ++it) { + NetworkBookItem &book = (NetworkBookItem&)**it; + book.Index = 0; + purchasedBooksIds.insert(book.Id); + } + + NetworkLibrary::Instance().invalidateVisibility(); + NetworkLibrary::Instance().synchronize(); + NetworkLibrary::Instance().refresh(); +} + +shared_ptr<ZLNetworkRequest> LitResAuthenticationManager::loadAccount(std::string &dummy1) { + const std::string &sid = mySidOption.value(); + + myAccount.clear(); + + std::string query; + ZLNetworkUtil::appendParameter(query, "sid", sid); + ZLNetworkUtil::appendParameter(query, "art", "0"); + + return ZLNetworkManager::Instance().createXMLParserRequest( + LitResUtil::url(Link, "pages/purchase_book/" + query), + new LitResPurchaseDataParser(myAccount, dummy1) + ); +} + +void LitResAuthenticationManager::loadAccountOnError() { + myAccount.clear(); +} + +void LitResAuthenticationManager::loadAccountOnSuccess() { + myAccount = BuyBookReference::price(myAccount, "RUB"); +} + +bool LitResAuthenticationManager::skipIPSupported() { + return true; +} + +bool LitResAuthenticationManager::registrationSupported() { + return true; +} + +std::string LitResAuthenticationManager::registerUser(const std::string &login, const std::string &password, const std::string &email) { + std::string newSid; + shared_ptr<ZLXMLReader> xmlReader = new LitResRegisterUserDataParser(newSid); + + std::string url = Link.url(NetworkLink::URL_SIGN_UP); + ZLNetworkUtil::appendParameter(url, "new_login", login); + ZLNetworkUtil::appendParameter(url, "new_pwd1", password); + ZLNetworkUtil::appendParameter(url, "mail", email); + + shared_ptr<ZLNetworkRequest> networkData = + ZLNetworkManager::Instance().createXMLParserRequest( + url, xmlReader + ); + std::string error = ZLNetworkManager::Instance().perform(networkData); + + mySidChecked = true; + if (!error.empty()) { + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + return error; + } + mySidOption.setValue(newSid); + mySidUserNameOption.setValue(login); + return ""; +} + +bool LitResAuthenticationManager::passwordRecoverySupported() { + return true; +} + +std::string LitResAuthenticationManager::recoverPassword(const std::string &email) { + std::string url = Link.url(NetworkLink::URL_RECOVER_PASSWORD); + ZLNetworkUtil::appendParameter(url, "mail", email); + + shared_ptr<ZLNetworkRequest> networkData = + ZLNetworkManager::Instance().createXMLParserRequest( + url, new LitResPasswordRecoveryDataParser() + ); + return ZLNetworkManager::Instance().perform(networkData); +} + +class LitResReloadPurchasedBooksScope : public ZLUserData { +public: + std::set<std::string> purchasedBooksIds; + NetworkItem::List purchasedBooksList; + shared_ptr<ZLNetworkRequest::Listener> Listener; +}; + +std::string LitResAuthenticationManager::reloadPurchasedBooks(shared_ptr<ZLNetworkRequest::Listener> listener) { + const std::string &sid = mySidOption.value(); + std::string error; + if (sid.empty()) { + error = NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + listener->finished(error); + return error; + } + if (sid != myInitializedDataSid) { + mySidChecked = true; + mySidUserNameOption.setValue(""); + mySidOption.setValue(""); + error = NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED); + listener->finished(error); + return error; + } + + LitResReloadPurchasedBooksScope *scope = new LitResReloadPurchasedBooksScope; + shared_ptr<ZLNetworkRequest> networkData = loadPurchasedBooks(scope->purchasedBooksIds, scope->purchasedBooksList); + scope->Listener = listener; + + networkData->setListener(ZLExecutionUtil::createListener(scope, this, &LitResAuthenticationManager::onBooksReloaded)); + return ZLNetworkManager::Instance().performAsync(networkData); +} + +void LitResAuthenticationManager::onBooksReloaded(ZLUserDataHolder &data, const std::string &error) { + LitResReloadPurchasedBooksScope &scope = static_cast<LitResReloadPurchasedBooksScope&>(*data.getUserData("scope")); + shared_ptr<ZLNetworkRequest::Listener> listener = scope.Listener; + if (!error.empty()) { + if (error == NetworkErrors::errorMessage(NetworkErrors::ERROR_AUTHENTICATION_FAILED)) { + logOut(); //should it logOut in this case? + } + listener->finished(error); + return; + } + loadPurchasedBooksOnSuccess(scope.purchasedBooksIds, scope.purchasedBooksList); + myPurchasedBooksIds = scope.purchasedBooksIds; + myPurchasedBooksList = scope.purchasedBooksList; + listener->finished(std::string()); +} + |