/*
* Copyright (C) 2010-2011 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.
*/
package org.geometerplus.fbreader.network.authentication.litres;
import java.util.*;
import org.geometerplus.zlibrary.core.options.ZLStringOption;
import org.geometerplus.zlibrary.core.util.ZLNetworkUtil;
import org.geometerplus.zlibrary.core.network.ZLNetworkManager;
import org.geometerplus.zlibrary.core.network.ZLNetworkException;
import org.geometerplus.zlibrary.core.network.ZLNetworkRequest;
import org.geometerplus.fbreader.network.*;
import org.geometerplus.fbreader.network.authentication.*;
public class LitResAuthenticationManager extends NetworkAuthenticationManager {
private boolean mySidChecked;
private final ZLStringOption mySidUserNameOption;
private final ZLStringOption mySidOption;
private final ZLStringOption myUserIdOption;
private String myInitializedDataSid;
private String myAccount;
private final HashMap<String, NetworkItem> myPurchasedBooks = new HashMap<String, NetworkItem>();
public LitResAuthenticationManager(INetworkLink link, String sslCertificate) {
super(link, sslCertificate);
mySidUserNameOption = new ZLStringOption(link.getSiteName(), "sidUserName", "");
mySidOption = new ZLStringOption(link.getSiteName(), "sid", "");
myUserIdOption = new ZLStringOption(link.getSiteName(), "userId", "");
}
@Override
public synchronized void initUser(String userName, String sid) throws ZLNetworkException {
mySidChecked = false;
mySidUserNameOption.setValue(userName);
mySidOption.setValue(sid);
if (!isAuthorised(true)) {
throw new ZLNetworkException(NetworkException.ERROR_AUTHENTICATION_FAILED);
}
}
private synchronized void initUser(String userName, String sid, String userId) {
mySidChecked = true;
mySidUserNameOption.setValue(userName);
mySidOption.setValue(sid);
myUserIdOption.setValue(userId);
}
@Override
public synchronized void logOut() {
initUser("", "", "");
}
@Override
public boolean isAuthorised(boolean useNetwork /* = true */) throws ZLNetworkException {
final String sid;
synchronized (this) {
boolean authState =
mySidUserNameOption.getValue().length() != 0 &&
mySidOption.getValue().length() != 0;
if (mySidChecked || !useNetwork) {
return authState;
}
if (!authState) {
logOut();
return false;
}
sid = mySidOption.getValue();
}
String url = Link.getUrlInfo(INetworkLink.URL_SIGN_IN).URL;
if (url == null) {
throw new ZLNetworkException(NetworkException.ERROR_UNSUPPORTED_OPERATION);
}
url = ZLNetworkUtil.appendParameter(url, "sid", sid);
final LitResLoginXMLReader xmlReader = new LitResLoginXMLReader(Link.getSiteName());
ZLNetworkException exception = null;
try {
ZLNetworkManager.Instance().perform(new LitResNetworkRequest(url, SSLCertificate, xmlReader));
} catch (ZLNetworkException e) {
exception = e;
}
synchronized (this) {
if (exception != null) {
if (NetworkException.ERROR_AUTHENTICATION_FAILED.equals(exception.getCode())) {
throw exception;
}
logOut();
return false;
}
initUser(UserNameOption.getValue(), xmlReader.Sid, xmlReader.UserId);
return true;
}
}
@Override
public void authorise(String password) throws ZLNetworkException {
String url = Link.getUrlInfo(INetworkLink.URL_SIGN_IN).URL;
if (url == null) {
throw new ZLNetworkException(NetworkException.ERROR_UNSUPPORTED_OPERATION);
}
final String login;
synchronized (this) {
login = UserNameOption.getValue();
}
url = ZLNetworkUtil.appendParameter(url, "login", login);
url = ZLNetworkUtil.appendParameter(url, "pwd", password);
final LitResLoginXMLReader xmlReader = new LitResLoginXMLReader(Link.getSiteName());
ZLNetworkException exception = null;
try {
ZLNetworkManager.Instance().perform(new LitResNetworkRequest(url, SSLCertificate, xmlReader));
} catch (ZLNetworkException e) {
exception = e;
}
synchronized (this) {
mySidChecked = true;
if (exception != null) {
logOut();
throw exception;
}
initUser(UserNameOption.getValue(), xmlReader.Sid, xmlReader.UserId);
}
}
@Override
public BookReference downloadReference(NetworkBookItem book) {
final String sid;
synchronized (this) {
sid = mySidOption.getValue();
}
if (sid.length() == 0) {
return null;
}
BookReference reference = book.reference(BookReference.Type.DOWNLOAD_FULL_CONDITIONAL);
if (reference == null) {
return null;
}
String url = reference.URL;
url = ZLNetworkUtil.appendParameter(url, "sid", sid);
return new DecoratedBookReference(reference, url);
}
@Override
public String currentUserName() {
final String value;
synchronized (this) {
value = mySidUserNameOption.getValue();
}
if (value.length() == 0) {
return null;
}
return value;
}
@Override
public synchronized boolean needPurchase(NetworkBookItem book) {
return !myPurchasedBooks.containsKey(book.Id);
}
@Override
public void purchaseBook(NetworkBookItem book) throws ZLNetworkException {
final String sid;
synchronized (this) {
sid = mySidOption.getValue();
}
if (sid.length() == 0) {
throw new ZLNetworkException(NetworkException.ERROR_AUTHENTICATION_FAILED);
}
BookReference reference = book.reference(BookReference.Type.BUY);
if (reference == null) {
throw new ZLNetworkException(NetworkException.ERROR_BOOK_NOT_PURCHASED); // TODO: more correct error message???
}
String query = reference.URL;
query = ZLNetworkUtil.appendParameter(query, "sid", sid);
final LitResPurchaseXMLReader xmlReader = new LitResPurchaseXMLReader(Link.getSiteName());
ZLNetworkException exception = null;
try {
ZLNetworkManager.Instance().perform(new LitResNetworkRequest(query, SSLCertificate, xmlReader));
} catch (ZLNetworkException e) {
exception = e;
}
synchronized (this) {
if (xmlReader.Account != null) {
myAccount = BuyBookReference.price(xmlReader.Account, "RUB");
}
if (exception != null) {
final String code = exception.getCode();
if (NetworkException.ERROR_AUTHENTICATION_FAILED.equals(code)) {
logOut();
} else if (NetworkException.ERROR_PURCHASE_ALREADY_PURCHASED.equals(code)) {
myPurchasedBooks.put(book.Id, book);
}
throw exception;
}
if (xmlReader.BookId == null || !xmlReader.BookId.equals(book.Id)) {
throw new ZLNetworkException(NetworkException.ERROR_SOMETHING_WRONG, Link.getSiteName());
}
myPurchasedBooks.put(book.Id, book);
}
}
@Override
public String refillAccountLink() {
final String sid;
synchronized (this) {
sid = mySidOption.getValue();
}
if (sid.length() == 0) {
return null;
}
final String url = Link.getUrlInfo(INetworkLink.URL_REFILL_ACCOUNT).URL;
if (url == null) {
return null;
}
return ZLNetworkUtil.appendParameter(url, "sid", sid);
}
@Override
public synchronized String currentAccount() {
return myAccount;
}
void reloadPurchasedBooks() throws ZLNetworkException {
final LitResNetworkRequest networkRequest;
synchronized (this) {
final String sid = mySidOption.getValue();
if (sid.length() == 0) {
throw new ZLNetworkException(NetworkException.ERROR_AUTHENTICATION_FAILED);
}
if (!sid.equals(myInitializedDataSid)) {
logOut();
throw new ZLNetworkException(NetworkException.ERROR_AUTHENTICATION_FAILED);
}
networkRequest = loadPurchasedBooks();
}
ZLNetworkException exception = null;
try {
ZLNetworkManager.Instance().perform(networkRequest);
} catch (ZLNetworkException e) {
exception = e;
}
synchronized (this) {
if (exception != null) {
//loadPurchasedBooksOnError();
if (NetworkException.ERROR_AUTHENTICATION_FAILED.equals(exception.getCode())) {
logOut();
}
throw exception;
}
loadPurchasedBooksOnSuccess(networkRequest);
}
}
@Override
public synchronized List<NetworkBookItem> purchasedBooks() {
return new ArrayList(myPurchasedBooks.values());
}
@Override
public synchronized boolean needsInitialization() {
final String sid = mySidOption.getValue();
if (sid.length() == 0) {
return false;
}
return !sid.equals(myInitializedDataSid);
}
@Override
public void initialize() throws ZLNetworkException {
final String sid;
final LitResNetworkRequest purchasedBooksRequest;
final LitResNetworkRequest accountRequest;
synchronized (this) {
sid = mySidOption.getValue();
if (sid.length() == 0) {
throw new ZLNetworkException(NetworkException.ERROR_AUTHENTICATION_FAILED);
}
if (sid.equals(myInitializedDataSid)) {
return;
}
purchasedBooksRequest = loadPurchasedBooks();
accountRequest = loadAccount();
}
final LinkedList<ZLNetworkRequest> requests = new LinkedList<ZLNetworkRequest>();
requests.add(purchasedBooksRequest);
requests.add(accountRequest);
ZLNetworkException exception = null;
try {
ZLNetworkManager.Instance().perform(requests);
} catch (ZLNetworkException e) {
exception = e;
}
synchronized (this) {
if (exception != null) {
myInitializedDataSid = null;
loadPurchasedBooksOnError();
loadAccountOnError();
throw exception;
}
myInitializedDataSid = sid;
loadPurchasedBooksOnSuccess(purchasedBooksRequest);
loadAccountOnSuccess(accountRequest);
}
}
private LitResNetworkRequest loadPurchasedBooks() {
final String sid = mySidOption.getValue();
String query = "pages/catalit_browser/";
query = ZLNetworkUtil.appendParameter(query, "my", "1");
query = ZLNetworkUtil.appendParameter(query, "sid", sid);
return new LitResNetworkRequest(
LitResUtil.url(Link, query),
SSLCertificate,
new LitResXMLReader(Link, new LinkedList<NetworkItem>())
);
}
private void loadPurchasedBooksOnError() {
myPurchasedBooks.clear();
}
private void loadPurchasedBooksOnSuccess(LitResNetworkRequest purchasedBooksRequest) {
LitResXMLReader reader = (LitResXMLReader)purchasedBooksRequest.Reader;
myPurchasedBooks.clear();
for (NetworkItem item: reader.Books) {
if (item instanceof NetworkBookItem) {
NetworkBookItem book = (NetworkBookItem)item;
myPurchasedBooks.put(book.Id, book);
}
}
}
private LitResNetworkRequest loadAccount() {
final String sid = mySidOption.getValue();
String query = "pages/purchase_book/";
query = ZLNetworkUtil.appendParameter(query, "sid", sid);
query = ZLNetworkUtil.appendParameter(query, "art", "0");
return new LitResNetworkRequest(
LitResUtil.url(Link, query),
SSLCertificate,
new LitResPurchaseXMLReader(Link.getSiteName())
);
}
private void loadAccountOnError() {
myAccount = null;
}
private void loadAccountOnSuccess(LitResNetworkRequest accountRequest) {
LitResPurchaseXMLReader reader = (LitResPurchaseXMLReader)accountRequest.Reader;
myAccount = BuyBookReference.price(reader.Account, "RUB");
}
@Override
public boolean passwordRecoverySupported() {
return true;
}
@Override
public void recoverPassword(String email) throws ZLNetworkException {
String url = Link.getUrlInfo(INetworkLink.URL_RECOVER_PASSWORD).URL;
if (url == null) {
throw new ZLNetworkException(NetworkException.ERROR_UNSUPPORTED_OPERATION);
}
url = ZLNetworkUtil.appendParameter(url, "mail", email);
final LitResPasswordRecoveryXMLReader xmlReader = new LitResPasswordRecoveryXMLReader(Link.getSiteName());
ZLNetworkManager.Instance().perform(new LitResNetworkRequest(url, SSLCertificate, xmlReader));
}
@Override
public Map<String,String> getSmsRefillingData() {
final HashMap<String,String> map = new HashMap<String,String>();
map.put("litres:userId", myUserIdOption.getValue());
map.put("litres:sid", mySidOption.getValue());
return map;
}
}